blockautoformatediting.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /**
  2. * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /**
  6. * @module autoformat/blockautoformatediting
  7. */
  8. /**
  9. * The block autoformatting engine. It allows to format various block patterns. For example,
  10. * it can be configured to turn a paragraph starting with `*` and followed by a space into a list item.
  11. *
  12. * The autoformatting operation is integrated with the undo manager,
  13. * so the autoformatting step can be undone if the user's intention was not to format the text.
  14. *
  15. * See the constructors documentation to learn how to create custom inline autoformatters. You can also use
  16. * the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters
  17. * (lists, headings, bold and italic).
  18. */
  19. export default class BlockAutoformatEditing {
  20. /**
  21. * Creates a listener triggered on `change` event in the document.
  22. * Calls the callback when inserted text matches the regular expression or the command name
  23. * if provided instead of the callback.
  24. *
  25. * Examples of usage:
  26. *
  27. * To convert a paragraph to heading 1 when `- ` is typed, using just the command name:
  28. *
  29. * new BlockAutoformatEditing( editor, /^\- $/, 'heading1' );
  30. *
  31. * To convert a paragraph to heading 1 when `- ` is typed, using just the callback:
  32. *
  33. * new BlockAutoformatEditing( editor, /^\- $/, ( context ) => {
  34. * const { match } = context;
  35. * const headingLevel = match[ 1 ].length;
  36. *
  37. * editor.execute( 'heading', {
  38. * formatId: `heading${ headingLevel }`
  39. * } );
  40. * } );
  41. *
  42. * @param {module:core/editor/editor~Editor} editor The editor instance.
  43. * @param {RegExp} pattern The regular expression to execute on just inserted text.
  44. * @param {Function|String} callbackOrCommand The callback to execute or the command to run when the text is matched.
  45. * In case of providing the callback, it receives the following parameter:
  46. * * {Object} match RegExp.exec() result of matching the pattern to inserted text.
  47. */
  48. constructor( editor, pattern, callbackOrCommand ) {
  49. let callback;
  50. let command = null;
  51. if ( typeof callbackOrCommand == 'function' ) {
  52. callback = callbackOrCommand;
  53. } else {
  54. // We assume that the actual command name was provided.
  55. command = editor.commands.get( callbackOrCommand );
  56. callback = () => {
  57. editor.execute( callbackOrCommand );
  58. };
  59. }
  60. editor.model.document.on( 'change', ( evt, batch ) => {
  61. if ( command && !command.isEnabled ) {
  62. return;
  63. }
  64. if ( batch.type == 'transparent' ) {
  65. return;
  66. }
  67. const changes = Array.from( editor.model.document.differ.getChanges() );
  68. const entry = changes[ 0 ];
  69. // Typing is represented by only a single change.
  70. if ( changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1 ) {
  71. return;
  72. }
  73. const item = entry.position.textNode || entry.position.nodeAfter;
  74. if ( !item.parent.is( 'paragraph' ) ) {
  75. return;
  76. }
  77. const match = pattern.exec( item.data );
  78. if ( !match ) {
  79. return;
  80. }
  81. // Use enqueueChange to create new batch to separate typing batch from the auto-format changes.
  82. editor.model.enqueueChange( writer => {
  83. // Matched range.
  84. const start = writer.createPositionAt( item.parent, 0 );
  85. const end = writer.createPositionAt( item.parent, match[ 0 ].length );
  86. const range = writer.createRange( start, end );
  87. // Remove matched text.
  88. writer.remove( range );
  89. callback( { match } );
  90. } );
  91. } );
  92. }
  93. }