/** * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ /* globals console, window, document */ import { createTableAsciiArt, modelTable, prepareModelTableInput, prettyFormatModelTableInput } from '../_utils/utils'; import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor'; import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import { diffString } from 'json-diff'; import { debounce } from 'lodash-es'; import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset'; import TableWalker from '../../src/tablewalker'; import { getSelectionAffectedTableCells } from '../../src/utils/selection'; ClassicEditor .create( document.querySelector( '#editor' ), { plugins: [ ArticlePluginSet ], toolbar: [ 'insertTable', 'undo', 'redo' ], table: { contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells' ] } } ) .then( editor => { window.editor = editor; const asciiOut = document.getElementById( 'ascii-art' ); const modelData = document.getElementById( 'model-data' ); document.getElementById( 'clear-content' ).addEventListener( 'click', () => { editor.setData( '' ); } ); document.getElementById( 'set-model-data' ).addEventListener( 'click', () => { updateInputStatus(); const table = findTable( editor ); const inputModelData = parseModelData( modelData.value ); if ( inputModelData ) { const element = setModelData._parse( modelTable( inputModelData ), editor.model.schema ); editor.model.change( writer => { editor.model.insertContent( element, table ? editor.model.createRangeOn( table ) : null ); writer.setSelection( element, 'on' ); } ); editor.editing.view.focus(); } } ); document.getElementById( 'get-model-data' ).addEventListener( 'click', () => { updateInputStatus(); const table = findTable( editor, true ); modelData.value = table ? prettyFormatModelTableInput( prepareModelTableInput( editor.model, table ) ) : ''; updateAsciiAndDiff(); } ); document.getElementById( 'renumber-cells' ).addEventListener( 'click', () => { const table = findTable( editor, true ); if ( !table ) { return; } const useLetters = document.getElementById( 'use-letters' ).checked; editor.model.change( writer => { for ( const { row, column, cell } of new TableWalker( table ) ) { const selection = editor.model.createSelection( cell, 'in' ); editor.model.insertContent( writer.createText( createCellText( row, column, useLetters ) ), selection ); } } ); updateAsciiAndDiff(); } ); editor.model.document.on( 'change:data', debounce( () => updateAsciiAndDiff(), 100 ) ); updateAsciiAndDiff(); function updateAsciiAndDiff() { const tables = getAllTables( editor ); if ( !tables.length ) { asciiOut.innerText = '-- table not found --'; return; } const inputModelData = parseModelData( modelData.value ); const currentModelData = prepareModelTableInput( editor.model, tables[ 0 ] ); const diffOutput = inputModelData ? diffString( inputModelData, currentModelData, { theme: { ' ': string => string, '+': string => `${ string }`, '-': string => `${ string }` } } ) : '-- no input --'; const asciiArt = tables .map( table => createTableAsciiArt( editor.model, table ) ) .join( '\n\n' ); asciiOut.innerHTML = asciiArt + '\n\n' + 'Diff: input vs post-fixed model (only first table):\n' + ( diffOutput ? diffOutput : '-- no differences --' ); } function findTable( editor, useAnyTable = false ) { const selection = editor.model.document.selection; const tableCells = getSelectionAffectedTableCells( selection ); if ( tableCells.length ) { return tableCells[ 0 ].findAncestor( 'table' ); } const element = selection.getSelectedElement(); if ( element && element.is( 'table' ) ) { return element; } if ( useAnyTable ) { const range = editor.model.createRangeIn( editor.model.document.getRoot() ); for ( const element of range.getItems() ) { if ( element.is( 'table' ) ) { return element; } } } return null; } function getAllTables( editor ) { const range = editor.model.createRangeIn( editor.model.document.getRoot() ); const tables = []; for ( const element of range.getItems() ) { if ( element.is( 'table' ) ) { tables.push( element ); } } return tables; } function parseModelData( string ) { if ( !string.trim() ) { return null; } const jsonString = string .replace( /'/g, '"' ) .replace( /([a-z0-9$_]+)\s*:/gi, '"$1":' ); try { return JSON.parse( jsonString ); } catch ( error ) { updateInputStatus( error.message ); } return null; } function updateInputStatus( message = '' ) { document.getElementById( 'input-status' ).innerText = message; } function createCellText( row, column, useLetters ) { const rowLabel = useLetters ? String.fromCharCode( row + 'a'.charCodeAt( 0 ) ) : row; const columnLabel = useLetters ? String.fromCharCode( column + 'a'.charCodeAt( 0 ) ) : column; return `${ rowLabel }${ columnLabel }`; } } ) .catch( err => { console.error( err.stack ); } );