tablemocking.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /* globals console, window, document */
  6. import { createTableAsciiArt, modelTable, prepareModelTableInput, prettyFormatModelTableInput } from '../_utils/utils';
  7. import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
  8. import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  9. import { diffString } from 'json-diff';
  10. import { debounce } from 'lodash-es';
  11. import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';
  12. import TableWalker from '../../src/tablewalker';
  13. ClassicEditor
  14. .create( document.querySelector( '#editor' ), {
  15. plugins: [ ArticlePluginSet ],
  16. toolbar: [
  17. 'insertTable', 'undo', 'redo'
  18. ],
  19. table: {
  20. contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells' ]
  21. }
  22. } )
  23. .then( editor => {
  24. window.editor = editor;
  25. const asciiOut = document.getElementById( 'ascii-art' );
  26. const modelData = document.getElementById( 'model-data' );
  27. document.getElementById( 'clear-content' ).addEventListener( 'click', () => {
  28. editor.setData( '' );
  29. } );
  30. document.getElementById( 'set-model-data' ).addEventListener( 'click', () => {
  31. updateInputStatus();
  32. const inputModelData = parseModelData( modelData.value );
  33. setModelData( editor.model, inputModelData ? modelTable( inputModelData ) : '' );
  34. } );
  35. document.getElementById( 'get-model-data' ).addEventListener( 'click', () => {
  36. updateInputStatus();
  37. const table = findTable( editor );
  38. modelData.value = table ? prettyFormatModelTableInput( prepareModelTableInput( editor.model, table ) ) : '';
  39. updateAsciiAndDiff();
  40. } );
  41. document.getElementById( 'renumber-cells' ).addEventListener( 'click', () => {
  42. const table = findTable( editor );
  43. if ( !table ) {
  44. return;
  45. }
  46. const useLetters = document.getElementById( 'use-letters' ).checked;
  47. editor.model.change( writer => {
  48. for ( const { row, column, cell } of new TableWalker( table ) ) {
  49. const selection = editor.model.createSelection( cell, 'in' );
  50. editor.model.insertContent( writer.createText( createCellText( row, column, useLetters ) ), selection );
  51. }
  52. } );
  53. updateAsciiAndDiff();
  54. } );
  55. editor.model.document.on( 'change:data', debounce( () => updateAsciiAndDiff(), 100 ) );
  56. updateAsciiAndDiff();
  57. function updateAsciiAndDiff() {
  58. const table = findTable( editor );
  59. if ( !table ) {
  60. asciiOut.innerText = '-- table not found --';
  61. return;
  62. }
  63. const inputModelData = parseModelData( modelData.value );
  64. const currentModelData = prepareModelTableInput( editor.model, table );
  65. const diffOutput = inputModelData ? diffString( inputModelData, currentModelData, {
  66. theme: {
  67. ' ': string => string,
  68. '+': string => `<span class="diff-add">${ string }</span>`,
  69. '-': string => `<span class="diff-del">${ string }</span>`
  70. }
  71. } ) : '-- no input --';
  72. asciiOut.innerHTML = createTableAsciiArt( editor.model, table ) + '\n\n' +
  73. 'Diff: input vs post-fixed model:\n' + ( diffOutput ? diffOutput : '-- no differences --' );
  74. }
  75. function findTable( editor ) {
  76. const range = editor.model.createRangeIn( editor.model.document.getRoot() );
  77. for ( const element of range.getItems() ) {
  78. if ( element.is( 'table' ) ) {
  79. return element;
  80. }
  81. }
  82. return null;
  83. }
  84. function parseModelData( string ) {
  85. if ( !string.trim() ) {
  86. return null;
  87. }
  88. const jsonString = string
  89. .replace( /'/g, '"' )
  90. .replace( /([a-z0-9$_]+)\s*:/gi, '"$1":' );
  91. try {
  92. return JSON.parse( jsonString );
  93. } catch ( error ) {
  94. updateInputStatus( error.message );
  95. }
  96. return null;
  97. }
  98. function updateInputStatus( message = '' ) {
  99. document.getElementById( 'input-status' ).innerText = message;
  100. }
  101. function createCellText( row, column, useLetters ) {
  102. const rowLabel = useLetters ? String.fromCharCode( row + 'a'.charCodeAt( 0 ) ) : row;
  103. const columnLabel = useLetters ? String.fromCharCode( column + 'a'.charCodeAt( 0 ) ) : column;
  104. return `${ rowLabel }${ columnLabel }`;
  105. }
  106. } )
  107. .catch( err => {
  108. console.error( err.stack );
  109. } );