{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/utils/changebuffer.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/inputcommand.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/utils/utils.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/utils/injecttypingmutationshandling.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/input.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/deletecommand.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/deleteobserver.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/delete.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/typing.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/utils/getlasttextline.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/textwatcher.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/twostepcaretmovement.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/texttransformation.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/utils/findattributerange.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/utils/inlinehighlight.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/index.js","webpack:///./node_modules/@ckeditor/ckeditor5-typing/src/utils/injectunsafekeystrokeshandling.js"],"names":["ChangeBuffer","model","limit","this","size","isLocked","_changeCallback","evt","batch","type","_batch","_reset","_selectionChangeCallback","document","on","selection","changeCount","off","ignoreLock","createBatch","InputCommand","editor","undoStepSize","_buffer","_batches","WeakSet","destroy","options","doc","text","textInsertions","length","range","createSelection","resultRange","enqueueChange","writer","lock","add","deleteContent","insertContent","createText","getAttributes","setSelection","is","unlock","input","Command","containerChildrenMutated","mutations","mutation","getSingleTextNodeChange","newChildren","oldChildren","diffResult","diff","compareChildNodes","changes","diffToChanges","change","values","oldChild","newChild","data","injectTypingMutationsHandling","editing","view","viewSelection","MutationHandler","handle","_handleContainerChildrenMutations","_handleTextMutation","_handleTextNodeInsertion","mutationsCommonAncestor","getMutationsContainer","domConverter","domMutationCommonAncestor","mapViewToDom","freshDomConverter","DomConverter","modelFromCurrentDom","toModel","domToView","getChild","currentModel","mapper","toModelElement","modelFromDomChildren","Array","from","getChildren","currentModelChildren","lastDomChild","lastCurrentChild","isLastDomChildSoftBreak","isLastCurrentChildSoftBreak","pop","schema","isSafeForTextMutation","newText","map","item","join","replace","oldText","calculateChanges","firstChangeAt","insertions","deletions","modelSelectionRange","toModelRange","getFirstRange","insertText","substr","removeRange","createRange","createPositionAt","execute","viewPos","node","modelPos","toModelPosition","getShiftedBy","index","insertedText","lca","reduce","commonAncestor","getCommonAncestor","includeSelf","getAncestors","parentFirst","find","element","children","every","child","isInline","lastChangeAt","i","Input","inputCommand","config","get","commands","injectUnsafeKeystrokesHandling","has","Plugin","DeleteCommand","direction","sequence","doNotResetEntireContent","isCollapsed","modifySelection","unit","_shouldEntireContentBeReplacedWithParagraph","_replaceEntireContentWithParagraph","_shouldReplaceFirstBlockWithParagraph","getMinimalFlatRanges","forEach","count","getWalker","singleCharacters","ignoreElementEnd","shallow","limitElement","getLimitElement","limitElementIsEmpty","containsEntireContent","checkChild","limitElementFirstChild","name","paragraph","createElement","remove","createRangeIn","insert","position","getFirstPosition","parent","DeleteObserver","fireViewDeleteEvent","originalEvent","domEvent","deleteData","event","once","priority","Number","POSITIVE_INFINITY","fire","DomEventData","stop","called","keyCode","keyCodes","delete","backspace","hasWordModifier","env","isMac","altKey","ctrlKey","isAndroid","inputType","domSelection","domTarget","ownerDocument","defaultView","getSelection","anchorNode","focusNode","anchorOffset","focusOffset","selectionToRemove","domSelectionToView","Observer","Delete","viewDocument","addObserver","deleteForwardCommand","listenTo","deleteCommandParams","modelSelection","ranges","getRanges","viewRange","push","setTo","preventDefault","scrollToTheSelection","domSelectionAfterDeletion","collapse","extend","Typing","getLastTextLine","start","getItems","rangeText","createPositionAfter","end","TextWatcher","testCallback","hasMatch","set","isEnabled","_startListening","stopListening","directChange","_evaluateTextBeforeSelection","suffix","rangeBeforeSelection","focus","testResult","eventData","Object","assign","mix","ObservableMixin","TwoStepCaretMovement","attributes","Set","_overrideUid","locale","shiftKey","arrowRightPressed","arrowright","arrowLeftPressed","arrowleft","contentDirection","contentLanguageDirection","isMovementHandled","_handleForwardMovement","_handleBackwardMovement","priorities","_isNextGravityRestorationSkipped","_isGravityOverridden","isBetweenDifferentAttributes","_restoreGravity","attribute","isAtStart","hasAnyAttribute","preventCaretMovement","_overrideGravity","setSelectionAttributesFromTheNodeBefore","isStepAfterAnyAttributeBoundary","isAtEnd","overrideSelectionGravity","restoreSelectionGravity","observedAttribute","hasAttribute","nodeBefore","setSelectionAttribute","removeSelectionAttribute","positionBefore","nodeAfter","attrBefore","getAttribute","undefined","attrAfter","TRANSFORMATIONS","copyright","to","registeredTrademark","trademark","oneHalf","oneThird","twoThirds","oneForth","threeQuarters","lessThanOrEqual","greaterThanOrEqual","notEqual","arrowLeft","arrowRight","horizontalEllipsis","enDash","emDash","quotesPrimary","buildQuotesRegExp","quotesSecondary","quotesPrimaryEnGb","quotesSecondaryEnGb","quotesPrimaryPl","quotesSecondaryPl","TRANSFORMATION_GROUPS","symbols","mathematical","typography","quotes","DEFAULT_TRANSFORMATIONS","normalizeFrom","RegExp","escapeRegExp","normalizeTo","getTextAttributesAfterPosition","textNode","quoteCharacter","normalizeTransformations","extra","isNotRemoved","transformation","includes","configured","include","concat","filter","expandGroupsAndRemoveDuplicates","definitions","definedTransformations","transformationOrGroup","findAttributeRange","attributeName","value","_findBound","lookBack","lastNode","previousSibling","nextSibling","inlineHighlight","tagName","className","highlightedElements","registerPostFixer","changed","modelRange","toViewRange","hasClass","addClass","conversion","for","dispatcher","removeHighlight","removeClass","latestCompositionSelection","handleUnsafeKeystroke","evtData","isComposing","isSelectionUnchanged","isEqual","isNonTypingKeystroke","deleteSelectionContent","handleCompositionStart","isFlatSelection","rangeCount","isFlat","buffer","safeKeycodes","getCode","code","keyData","metaKey"],"mappings":"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","file":"js/chunk-vendors~e563b9fc.8703d020.js","sourcesContent":["/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/changebuffer\n */\n\n/**\n * Change buffer allows to group atomic changes (like characters that have been typed) into\n * {@link module:engine/model/batch~Batch batches}.\n *\n * Batches represent single undo steps, hence changes added to one single batch are undone together.\n *\n * The buffer has a configurable limit of atomic changes that it can accommodate. After the limit was\n * exceeded (see {@link ~ChangeBuffer#input}), a new batch is created in {@link ~ChangeBuffer#batch}.\n *\n * To use the change buffer you need to let it know about the number of changes that were added to the batch:\n *\n *\t\tconst buffer = new ChangeBuffer( model, LIMIT );\n *\n *\t\t// Later on in your feature:\n *\t\tbuffer.batch.insert( pos, insertedCharacters );\n *\t\tbuffer.input( insertedCharacters.length );\n *\n */\nexport default class ChangeBuffer {\n\t/**\n\t * Creates a new instance of the change buffer.\n\t *\n\t * @param {module:engine/model/model~Model} model\n\t * @param {Number} [limit=20] The maximum number of atomic changes which can be contained in one batch.\n\t */\n\tconstructor( model, limit = 20 ) {\n\t\t/**\n\t\t * The model instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model} #model\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * The number of atomic changes in the buffer. Once it exceeds the {@link #limit},\n\t\t * the {@link #batch batch} is set to a new one.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #size\n\t\t */\n\t\tthis.size = 0;\n\n\t\t/**\n\t\t * The maximum number of atomic changes which can be contained in one batch.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #limit\n\t\t */\n\t\tthis.limit = limit;\n\n\t\t/**\n\t\t * Whether the buffer is locked. A locked buffer cannot be reset unless it gets unlocked.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isLocked\n\t\t */\n\t\tthis.isLocked = false;\n\n\t\t// The function to be called in order to notify the buffer about batches which appeared in the document.\n\t\t// The callback will check whether it is a new batch and in that case the buffer will be flushed.\n\t\t//\n\t\t// The reason why the buffer needs to be flushed whenever a new batch appears is that the changes added afterwards\n\t\t// should be added to a new batch. For instance, when the user types, then inserts an image, and then types again,\n\t\t// the characters typed after inserting the image should be added to a different batch than the characters typed before.\n\t\tthis._changeCallback = ( evt, batch ) => {\n\t\t\tif ( batch.type != 'transparent' && batch !== this._batch ) {\n\t\t\t\tthis._reset( true );\n\t\t\t}\n\t\t};\n\n\t\tthis._selectionChangeCallback = () => {\n\t\t\tthis._reset();\n\t\t};\n\n\t\tthis.model.document.on( 'change', this._changeCallback );\n\n\t\tthis.model.document.selection.on( 'change:range', this._selectionChangeCallback );\n\t\tthis.model.document.selection.on( 'change:attribute', this._selectionChangeCallback );\n\n\t\t/**\n\t\t * The current batch instance.\n\t\t *\n\t\t * @private\n\t\t * @member #_batch\n\t\t */\n\n\t\t/**\n\t\t * The callback to document the change event which later needs to be removed.\n\t\t *\n\t\t * @private\n\t\t * @member #_changeCallback\n\t\t */\n\n\t\t/**\n\t\t * The callback to document selection `change:attribute` and `change:range` events which resets the buffer.\n\t\t *\n\t\t * @private\n\t\t * @member #_selectionChangeCallback\n\t\t */\n\t}\n\n\t/**\n\t * The current batch to which a feature should add its operations. Once the {@link #size}\n\t * is reached or exceeds the {@link #limit}, the batch is set to a new instance and the size is reset.\n\t *\n\t * @type {module:engine/model/batch~Batch}\n\t */\n\tget batch() {\n\t\tif ( !this._batch ) {\n\t\t\tthis._batch = this.model.createBatch();\n\t\t}\n\n\t\treturn this._batch;\n\t}\n\n\t/**\n\t * The input number of changes into the buffer. Once the {@link #size} is\n\t * reached or exceeds the {@link #limit}, the batch is set to a new instance and the size is reset.\n\t *\n\t * @param {Number} changeCount The number of atomic changes to input.\n\t */\n\tinput( changeCount ) {\n\t\tthis.size += changeCount;\n\n\t\tif ( this.size >= this.limit ) {\n\t\t\tthis._reset( true );\n\t\t}\n\t}\n\n\t/**\n\t * Locks the buffer.\n\t */\n\tlock() {\n\t\tthis.isLocked = true;\n\t}\n\n\t/**\n\t * Unlocks the buffer.\n\t */\n\tunlock() {\n\t\tthis.isLocked = false;\n\t}\n\n\t/**\n\t * Destroys the buffer.\n\t */\n\tdestroy() {\n\t\tthis.model.document.off( 'change', this._changeCallback );\n\t\tthis.model.document.selection.off( 'change:range', this._selectionChangeCallback );\n\t\tthis.model.document.selection.off( 'change:attribute', this._selectionChangeCallback );\n\t}\n\n\t/**\n\t * Resets the change buffer.\n\t *\n\t * @private\n\t * @param {Boolean} [ignoreLock] Whether internal lock {@link #isLocked} should be ignored.\n\t */\n\t_reset( ignoreLock ) {\n\t\tif ( !this.isLocked || ignoreLock ) {\n\t\t\tthis._batch = null;\n\t\t\tthis.size = 0;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/inputcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport ChangeBuffer from './utils/changebuffer';\n\n/**\n * The input command. Used by the {@link module:typing/input~Input input feature} to handle typing.\n *\n * @extends module:core/command~Command\n */\nexport default class InputCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {Number} undoStepSize The maximum number of atomic changes\n\t * which can be contained in one batch in the command buffer.\n\t */\n\tconstructor( editor, undoStepSize ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * Typing's change buffer used to group subsequent changes into batches.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {module:typing/utils/changebuffer~ChangeBuffer} #_buffer\n\t\t */\n\t\tthis._buffer = new ChangeBuffer( editor.model, undoStepSize );\n\n\t\t/**\n\t\t * Stores batches created by the input command. The batches are used to differentiate input batches from other batches using\n\t\t * {@link module:typing/input~Input#isInput} method.\n\t\t *\n\t\t * @type {WeakSet}\n\t\t * @protected\n\t\t */\n\t\tthis._batches = new WeakSet();\n\t}\n\n\t/**\n\t * The current change buffer.\n\t *\n\t * @type {module:typing/utils/changebuffer~ChangeBuffer}\n\t */\n\tget buffer() {\n\t\treturn this._buffer;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis._buffer.destroy();\n\t}\n\n\t/**\n\t * Executes the input command. It replaces the content within the given range with the given text.\n\t * Replacing is a two step process, first the content within the range is removed and then the new text is inserted\n\t * at the beginning of the range (which after the removal is a collapsed range).\n\t *\n\t * @fires execute\n\t * @param {Object} [options] The command options.\n\t * @param {String} [options.text=''] The text to be inserted.\n\t * @param {module:engine/model/range~Range} [options.range] The range in which the text is inserted. Defaults\n\t * to the first range in the current selection.\n\t * @param {module:engine/model/range~Range} [options.resultRange] The range where the selection\n\t * should be placed after the insertion. If not specified, the selection will be placed right after\n\t * the inserted text.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst text = options.text || '';\n\t\tconst textInsertions = text.length;\n\t\tconst selection = options.range ? model.createSelection( options.range ) : doc.selection;\n\t\tconst resultRange = options.resultRange;\n\n\t\tmodel.enqueueChange( this._buffer.batch, writer => {\n\t\t\tthis._buffer.lock();\n\n\t\t\t// Store the batch as an 'input' batch for the Input.isInput( batch ) check.\n\t\t\tthis._batches.add( this._buffer.batch );\n\n\t\t\tmodel.deleteContent( selection );\n\n\t\t\tif ( text ) {\n\t\t\t\tmodel.insertContent( writer.createText( text, doc.selection.getAttributes() ), selection );\n\t\t\t}\n\n\t\t\tif ( resultRange ) {\n\t\t\t\twriter.setSelection( resultRange );\n\t\t\t} else if ( !selection.is( 'documentSelection' ) ) {\n\t\t\t\twriter.setSelection( selection );\n\t\t\t}\n\n\t\t\tthis._buffer.unlock();\n\n\t\t\tthis._buffer.input( textInsertions );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/utils\n */\n\nimport diff from '@ckeditor/ckeditor5-utils/src/diff';\nimport diffToChanges from '@ckeditor/ckeditor5-utils/src/difftochanges';\n\n/**\n * Returns true if container children have mutated or more than a single text node was changed.\n *\n * @private\n * @param {Array.} mutations\n * @returns {Boolean}\n */\nexport function containerChildrenMutated( mutations ) {\n\tif ( mutations.length == 0 ) {\n\t\treturn false;\n\t}\n\n\t// Check if there is any mutation of `children` type or any mutation that changes more than one text node.\n\tfor ( const mutation of mutations ) {\n\t\tif ( mutation.type === 'children' && !getSingleTextNodeChange( mutation ) ) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Returns change made to a single text node.\n *\n * @private\n * @param {module:engine/view/observer/mutationobserver~MutatedText|\n * module:engine/view/observer/mutationobserver~MutatedChildren} mutation\n * @returns {Object|undefined} Change object (see {@link module:utils/difftochanges~diffToChanges} output)\n * or undefined if more than a single text node was changed.\n */\nexport function getSingleTextNodeChange( mutation ) {\n\t// One new node.\n\tif ( mutation.newChildren.length - mutation.oldChildren.length != 1 ) {\n\t\treturn;\n\t}\n\n\t// Which is text.\n\tconst diffResult = diff( mutation.oldChildren, mutation.newChildren, compareChildNodes );\n\tconst changes = diffToChanges( diffResult, mutation.newChildren );\n\n\t// In case of [ delete, insert, insert ] the previous check will not exit.\n\tif ( changes.length > 1 ) {\n\t\treturn;\n\t}\n\n\tconst change = changes[ 0 ];\n\n\t// Which is text.\n\tif ( !( !!change.values[ 0 ] && change.values[ 0 ].is( '$text' ) ) ) {\n\t\treturn;\n\t}\n\n\treturn change;\n}\n\n/**\n * Checks whether two view nodes are identical, which means they are the same object\n * or contain exactly same data (in case of text nodes).\n *\n * @private\n * @param {module:engine/view/node~Node} oldChild\n * @param {module:engine/view/node~Node} newChild\n * @returns {Boolean}\n */\nexport function compareChildNodes( oldChild, newChild ) {\n\tif ( !!oldChild && oldChild.is( '$text' ) && !!newChild && newChild.is( '$text' ) ) {\n\t\treturn oldChild.data === newChild.data;\n\t} else {\n\t\treturn oldChild === newChild;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/injecttypingmutationshandling\n */\n\nimport diff from '@ckeditor/ckeditor5-utils/src/diff';\nimport DomConverter from '@ckeditor/ckeditor5-engine/src/view/domconverter';\n\nimport { getSingleTextNodeChange, containerChildrenMutated } from './utils';\n\n/**\n * Handles mutations caused by normal typing.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n */\nexport default function injectTypingMutationsHandling( editor ) {\n\teditor.editing.view.document.on( 'mutations', ( evt, mutations, viewSelection ) => {\n\t\tnew MutationHandler( editor ).handle( mutations, viewSelection );\n\t} );\n}\n\n/**\n * Helper class for translating DOM mutations into model changes.\n *\n * @private\n */\nclass MutationHandler {\n\t/**\n\t * Creates an instance of the mutation handler.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * Editor instance for which mutations are handled.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor} #editor\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * The editing controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/controller/editingcontroller~EditingController} #editing\n\t\t */\n\t\tthis.editing = this.editor.editing;\n\t}\n\n\t/**\n\t * Handles given mutations.\n\t *\n\t * @param {Array.} mutations\n\t * @param {module:engine/view/selection~Selection|null} viewSelection\n\t */\n\thandle( mutations, viewSelection ) {\n\t\tif ( containerChildrenMutated( mutations ) ) {\n\t\t\tthis._handleContainerChildrenMutations( mutations, viewSelection );\n\t\t} else {\n\t\t\tfor ( const mutation of mutations ) {\n\t\t\t\t// Fortunately it will never be both.\n\t\t\t\tthis._handleTextMutation( mutation, viewSelection );\n\t\t\t\tthis._handleTextNodeInsertion( mutation );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Handles situations when container's children mutated during input. This can happen when\n\t * the browser is trying to \"fix\" DOM in certain situations. For example, when the user starts to type\n\t * in `

Link{}

`, the browser might change the order of elements\n\t * to `

Linkx{}

`. A similar situation happens when the spell checker\n\t * replaces a word wrapped with `` with a word wrapped with a `` element.\n\t *\n\t * To handle such situations, the common DOM ancestor of all mutations is converted to the model representation\n\t * and then compared with the current model to calculate the proper text change.\n\t *\n\t * Note: Single text node insertion is handled in {@link #_handleTextNodeInsertion} and text node mutation is handled\n\t * in {@link #_handleTextMutation}).\n\t *\n\t * @private\n\t * @param {Array.} mutations\n\t * @param {module:engine/view/selection~Selection|null} viewSelection\n\t */\n\t_handleContainerChildrenMutations( mutations, viewSelection ) {\n\t\t// Get common ancestor of all mutations.\n\t\tconst mutationsCommonAncestor = getMutationsContainer( mutations );\n\n\t\t// Quit if there is no common ancestor.\n\t\tif ( !mutationsCommonAncestor ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst domConverter = this.editor.editing.view.domConverter;\n\n\t\t// Get common ancestor in DOM.\n\t\tconst domMutationCommonAncestor = domConverter.mapViewToDom( mutationsCommonAncestor );\n\n\t\t// Create fresh DomConverter so it will not use existing mapping and convert current DOM to model.\n\t\t// This wouldn't be needed if DomConverter would allow to create fresh view without checking any mappings.\n\t\tconst freshDomConverter = new DomConverter( this.editor.editing.view.document );\n\t\tconst modelFromCurrentDom = this.editor.data.toModel(\n\t\t\tfreshDomConverter.domToView( domMutationCommonAncestor )\n\t\t).getChild( 0 );\n\n\t\t// Current model.\n\t\tconst currentModel = this.editor.editing.mapper.toModelElement( mutationsCommonAncestor );\n\n\t\t// If common ancestor is not mapped, do not do anything. It probably is a parent of another view element.\n\t\t// That means that we would need to diff model elements (see `if` below). Better return early instead of\n\t\t// trying to get a reasonable model ancestor. It will fell into the `if` below anyway.\n\t\t// This situation happens for example for lists. If `
    ` is a common ancestor, `currentModel` is `undefined`\n\t\t// because `
      ` is not mapped (`
    • `s are).\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/718.\n\t\tif ( !currentModel ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Get children from both ancestors.\n\t\tconst modelFromDomChildren = Array.from( modelFromCurrentDom.getChildren() );\n\t\tconst currentModelChildren = Array.from( currentModel.getChildren() );\n\n\t\t// Remove the last `` from the end of `modelFromDomChildren` if there is no `` in current model.\n\t\t// If the described scenario happened, it means that this is a bogus `
      ` added by a browser.\n\t\tconst lastDomChild = modelFromDomChildren[ modelFromDomChildren.length - 1 ];\n\t\tconst lastCurrentChild = currentModelChildren[ currentModelChildren.length - 1 ];\n\n\t\tconst isLastDomChildSoftBreak = lastDomChild && lastDomChild.is( 'element', 'softBreak' );\n\t\tconst isLastCurrentChildSoftBreak = lastCurrentChild && !lastCurrentChild.is( 'element', 'softBreak' );\n\n\t\tif ( isLastDomChildSoftBreak && isLastCurrentChildSoftBreak ) {\n\t\t\tmodelFromDomChildren.pop();\n\t\t}\n\n\t\tconst schema = this.editor.model.schema;\n\n\t\t// Skip situations when common ancestor has any container elements.\n\t\tif ( !isSafeForTextMutation( modelFromDomChildren, schema ) || !isSafeForTextMutation( currentModelChildren, schema ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Replace   inserted by the browser with normal space. See comment in `_handleTextMutation`.\n\t\t// Replace non-texts with any character. This is potentially dangerous but passes in manual tests. The thing is\n\t\t// that we need to take care of proper indexes so we cannot simply remove non-text elements from the content.\n\t\t// By inserting a character we keep all the real texts on their indexes.\n\t\tconst newText = modelFromDomChildren.map( item => item.is( '$text' ) ? item.data : '@' ).join( '' ).replace( /\\u00A0/g, ' ' );\n\t\tconst oldText = currentModelChildren.map( item => item.is( '$text' ) ? item.data : '@' ).join( '' ).replace( /\\u00A0/g, ' ' );\n\n\t\t// Do nothing if mutations created same text.\n\t\tif ( oldText === newText ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst diffResult = diff( oldText, newText );\n\n\t\tconst { firstChangeAt, insertions, deletions } = calculateChanges( diffResult );\n\n\t\t// Try setting new model selection according to passed view selection.\n\t\tlet modelSelectionRange = null;\n\n\t\tif ( viewSelection ) {\n\t\t\tmodelSelectionRange = this.editing.mapper.toModelRange( viewSelection.getFirstRange() );\n\t\t}\n\n\t\tconst insertText = newText.substr( firstChangeAt, insertions );\n\t\tconst removeRange = this.editor.model.createRange(\n\t\t\tthis.editor.model.createPositionAt( currentModel, firstChangeAt ),\n\t\t\tthis.editor.model.createPositionAt( currentModel, firstChangeAt + deletions )\n\t\t);\n\n\t\tthis.editor.execute( 'input', {\n\t\t\ttext: insertText,\n\t\t\trange: removeRange,\n\t\t\tresultRange: modelSelectionRange\n\t\t} );\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_handleTextMutation( mutation, viewSelection ) {\n\t\tif ( mutation.type != 'text' ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Replace   inserted by the browser with normal space.\n\t\t// We want only normal spaces in the model and in the view. Renderer and DOM Converter will be then responsible\n\t\t// for rendering consecutive spaces using  , but the model and the view has to be clear.\n\t\t// Other feature may introduce inserting non-breakable space on specific key stroke (for example shift + space).\n\t\t// However then it will be handled outside of mutations, like enter key is.\n\t\t// The replacing is here because it has to be done before `diff` and `diffToChanges` functions, as they\n\t\t// take `newText` and compare it to (cleaned up) view.\n\t\t// It could also be done in mutation observer too, however if any outside plugin would like to\n\t\t// introduce additional events for mutations, they would get already cleaned up version (this may be good or not).\n\t\tconst newText = mutation.newText.replace( /\\u00A0/g, ' ' );\n\t\t// To have correct `diffResult`, we also compare view node text data with   replaced by space.\n\t\tconst oldText = mutation.oldText.replace( /\\u00A0/g, ' ' );\n\n\t\t// Do nothing if mutations created same text.\n\t\tif ( oldText === newText ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst diffResult = diff( oldText, newText );\n\n\t\tconst { firstChangeAt, insertions, deletions } = calculateChanges( diffResult );\n\n\t\t// Try setting new model selection according to passed view selection.\n\t\tlet modelSelectionRange = null;\n\n\t\tif ( viewSelection ) {\n\t\t\tmodelSelectionRange = this.editing.mapper.toModelRange( viewSelection.getFirstRange() );\n\t\t}\n\n\t\t// Get the position in view and model where the changes will happen.\n\t\tconst viewPos = this.editing.view.createPositionAt( mutation.node, firstChangeAt );\n\t\tconst modelPos = this.editing.mapper.toModelPosition( viewPos );\n\t\tconst removeRange = this.editor.model.createRange( modelPos, modelPos.getShiftedBy( deletions ) );\n\t\tconst insertText = newText.substr( firstChangeAt, insertions );\n\n\t\tthis.editor.execute( 'input', {\n\t\t\ttext: insertText,\n\t\t\trange: removeRange,\n\t\t\tresultRange: modelSelectionRange\n\t\t} );\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_handleTextNodeInsertion( mutation ) {\n\t\tif ( mutation.type != 'children' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst change = getSingleTextNodeChange( mutation );\n\t\tconst viewPos = this.editing.view.createPositionAt( mutation.node, change.index );\n\t\tconst modelPos = this.editing.mapper.toModelPosition( viewPos );\n\t\tconst insertedText = change.values[ 0 ].data;\n\n\t\tthis.editor.execute( 'input', {\n\t\t\t// Replace   inserted by the browser with normal space.\n\t\t\t// See comment in `_handleTextMutation`.\n\t\t\t// In this case we don't need to do this before `diff` because we diff whole nodes.\n\t\t\t// Just change   in case there are some.\n\t\t\ttext: insertedText.replace( /\\u00A0/g, ' ' ),\n\t\t\trange: this.editor.model.createRange( modelPos )\n\t\t} );\n\t}\n}\n\n// Returns first common ancestor of all mutations that is either {@link module:engine/view/containerelement~ContainerElement}\n// or {@link module:engine/view/rootelement~RootElement}.\n//\n// @private\n// @param {Array.} mutations\n// @returns {module:engine/view/containerelement~ContainerElement|engine/view/rootelement~RootElement|undefined}\nfunction getMutationsContainer( mutations ) {\n\tconst lca = mutations\n\t\t.map( mutation => mutation.node )\n\t\t.reduce( ( commonAncestor, node ) => {\n\t\t\treturn commonAncestor.getCommonAncestor( node, { includeSelf: true } );\n\t\t} );\n\n\tif ( !lca ) {\n\t\treturn;\n\t}\n\n\t// We need to look for container and root elements only, so check all LCA's\n\t// ancestors (starting from itself).\n\treturn lca.getAncestors( { includeSelf: true, parentFirst: true } )\n\t\t.find( element => element.is( 'containerElement' ) || element.is( 'rootElement' ) );\n}\n\n// Returns true if provided array contains content that won't be problematic during diffing and text mutation handling.\n//\n// @param {Array.} children\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction isSafeForTextMutation( children, schema ) {\n\treturn children.every( child => schema.isInline( child ) );\n}\n\n// Calculates first change index and number of characters that should be inserted and deleted starting from that index.\n//\n// @private\n// @param diffResult\n// @returns {{insertions: number, deletions: number, firstChangeAt: *}}\nfunction calculateChanges( diffResult ) {\n\t// Index where the first change happens. Used to set the position from which nodes will be removed and where will be inserted.\n\tlet firstChangeAt = null;\n\t// Index where the last change happens. Used to properly count how many characters have to be removed and inserted.\n\tlet lastChangeAt = null;\n\n\t// Get `firstChangeAt` and `lastChangeAt`.\n\tfor ( let i = 0; i < diffResult.length; i++ ) {\n\t\tconst change = diffResult[ i ];\n\n\t\tif ( change != 'equal' ) {\n\t\t\tfirstChangeAt = firstChangeAt === null ? i : firstChangeAt;\n\t\t\tlastChangeAt = i;\n\t\t}\n\t}\n\n\t// How many characters, starting from `firstChangeAt`, should be removed.\n\tlet deletions = 0;\n\t// How many characters, starting from `firstChangeAt`, should be inserted.\n\tlet insertions = 0;\n\n\tfor ( let i = firstChangeAt; i <= lastChangeAt; i++ ) {\n\t\t// If there is no change (equal) or delete, the character is existing in `oldText`. We count it for removing.\n\t\tif ( diffResult[ i ] != 'insert' ) {\n\t\t\tdeletions++;\n\t\t}\n\n\t\t// If there is no change (equal) or insert, the character is existing in `newText`. We count it for inserting.\n\t\tif ( diffResult[ i ] != 'delete' ) {\n\t\t\tinsertions++;\n\t\t}\n\t}\n\n\treturn { insertions, deletions, firstChangeAt };\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/input\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport InputCommand from './inputcommand';\n\nimport injectUnsafeKeystrokesHandling from './utils/injectunsafekeystrokeshandling';\nimport injectTypingMutationsHandling from './utils/injecttypingmutationshandling';\n\n/**\n * Handles text input coming from the keyboard or other input methods.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Input extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Input';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// TODO The above default configuration value should be defined using editor.config.define() once it's fixed.\n\t\tconst inputCommand = new InputCommand( editor, editor.config.get( 'typing.undoStep' ) || 20 );\n\n\t\teditor.commands.add( 'input', inputCommand );\n\n\t\tinjectUnsafeKeystrokesHandling( editor );\n\t\tinjectTypingMutationsHandling( editor );\n\t}\n\n\t/**\n\t * Checks batch if it is a result of user input - e.g. typing.\n\t *\n\t *\t\tconst input = editor.plugins.get( 'Input' );\n\t *\n\t *\t\teditor.model.document.on( 'change:data', ( evt, batch ) => {\n\t *\t\t\tif ( input.isInput( batch ) ) {\n\t *\t\t\t\tconsole.log( 'The user typed something...' );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * **Note:** This method checks if the batch was created using {@link module:typing/inputcommand~InputCommand 'input'}\n\t * command as typing changes coming from user input are inserted to the document using that command.\n\t *\n\t * @param {module:engine/model/batch~Batch} batch A batch to check.\n\t * @returns {Boolean}\n\t */\n\tisInput( batch ) {\n\t\tconst inputCommand = this.editor.commands.get( 'input' );\n\n\t\treturn inputCommand._batches.has( batch );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/deletecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport count from '@ckeditor/ckeditor5-utils/src/count';\n\nimport ChangeBuffer from './utils/changebuffer';\n\n/**\n * The delete command. Used by the {@link module:typing/delete~Delete delete feature} to handle the Delete and\n * Backspace keys.\n *\n * @extends module:core/command~Command\n */\nexport default class DeleteCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {'forward'|'backward'} direction The directionality of the delete describing in what direction it\n\t * should consume the content when the selection is collapsed.\n\t */\n\tconstructor( editor, direction ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The directionality of the delete describing in what direction it should\n\t\t * consume the content when the selection is collapsed.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'forward'|'backward'} #direction\n\t\t */\n\t\tthis.direction = direction;\n\n\t\t/**\n\t\t * Delete's change buffer used to group subsequent changes into batches.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @type {module:typing/utils/changebuffer~ChangeBuffer}\n\t\t */\n\t\tthis._buffer = new ChangeBuffer( editor.model, editor.config.get( 'typing.undoStep' ) );\n\t}\n\n\t/**\n\t * The current change buffer.\n\t *\n\t * @type {module:typing/utils/changebuffer~ChangeBuffer}\n\t */\n\tget buffer() {\n\t\treturn this._buffer;\n\t}\n\n\t/**\n\t * Executes the delete command. Depending on whether the selection is collapsed or not, deletes its content\n\t * or a piece of content in the {@link #direction defined direction}.\n\t *\n\t * @fires execute\n\t * @param {Object} [options] The command options.\n\t * @param {'character'} [options.unit='character'] See {@link module:engine/model/utils/modifyselection~modifySelection}'s options.\n\t * @param {Number} [options.sequence=1] A number describing which subsequent delete event it is without the key being released.\n\t * See the {@link module:engine/view/document~Document#event:delete} event data.\n\t * @param {module:engine/model/selection~Selection} [options.selection] Selection to remove. If not set, current model selection\n\t * will be used.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tmodel.enqueueChange( this._buffer.batch, writer => {\n\t\t\tthis._buffer.lock();\n\n\t\t\tconst selection = writer.createSelection( options.selection || doc.selection );\n\t\t\tconst sequence = options.sequence || 1;\n\n\t\t\t// Do not replace the whole selected content if selection was collapsed.\n\t\t\t// This prevents such situation:\n\t\t\t//\n\t\t\t//

      []

      \t-->

      [

      ]

      \t\t-->

      \n\t\t\t// starting content\t\t--> after `modifySelection`\t--> after `deleteContent`.\n\t\t\tconst doNotResetEntireContent = selection.isCollapsed;\n\n\t\t\t// Try to extend the selection in the specified direction.\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\tmodel.modifySelection( selection, { direction: this.direction, unit: options.unit } );\n\t\t\t}\n\n\t\t\t// Check if deleting in an empty editor. See #61.\n\t\t\tif ( this._shouldEntireContentBeReplacedWithParagraph( sequence ) ) {\n\t\t\t\tthis._replaceEntireContentWithParagraph( writer );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Check if deleting in the first empty block.\n\t\t\t// See https://github.com/ckeditor/ckeditor5/issues/8137.\n\t\t\tif ( this._shouldReplaceFirstBlockWithParagraph( selection, sequence ) ) {\n\t\t\t\tthis.editor.execute( 'paragraph', { selection } );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If selection is still collapsed, then there's nothing to delete.\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet changeCount = 0;\n\n\t\t\tselection.getFirstRange().getMinimalFlatRanges().forEach( range => {\n\t\t\t\tchangeCount += count(\n\t\t\t\t\trange.getWalker( { singleCharacters: true, ignoreElementEnd: true, shallow: true } )\n\t\t\t\t);\n\t\t\t} );\n\n\t\t\tmodel.deleteContent( selection, {\n\t\t\t\tdoNotResetEntireContent,\n\t\t\t\tdirection: this.direction\n\t\t\t} );\n\n\t\t\tthis._buffer.input( changeCount );\n\n\t\t\twriter.setSelection( selection );\n\n\t\t\tthis._buffer.unlock();\n\t\t} );\n\t}\n\n\t/**\n\t * If the user keeps Backspace or Delete key pressed, the content of the current\n\t * editable will be cleared. However, this will not yet lead to resetting the remaining block to a paragraph\n\t * (which happens e.g. when the user does Ctrl + A, Backspace).\n\t *\n\t * But, if the user pressed the key in an empty editable for the first time,\n\t * we want to replace the entire content with a paragraph if:\n\t *\n\t * * the current limit element is empty,\n\t * * the paragraph is allowed in the limit element,\n\t * * the limit doesn't already have a paragraph inside.\n\t *\n\t * See https://github.com/ckeditor/ckeditor5-typing/issues/61.\n\t *\n\t * @private\n\t * @param {Number} sequence A number describing which subsequent delete event it is without the key being released.\n\t * @returns {Boolean}\n\t */\n\t_shouldEntireContentBeReplacedWithParagraph( sequence ) {\n\t\t// Does nothing if user pressed and held the \"Backspace\" or \"Delete\" key.\n\t\tif ( sequence > 1 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\t\tconst limitElement = model.schema.getLimitElement( selection );\n\n\t\t// If a collapsed selection contains the whole content it means that the content is empty\n\t\t// (from the user perspective).\n\t\tconst limitElementIsEmpty = selection.isCollapsed && selection.containsEntireContent( limitElement );\n\n\t\tif ( !limitElementIsEmpty ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( !model.schema.checkChild( limitElement, 'paragraph' ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst limitElementFirstChild = limitElement.getChild( 0 );\n\n\t\t// Does nothing if the limit element already contains only a paragraph.\n\t\t// We ignore the case when paragraph might have some inline elements (

      []

      )\n\t\t// because we don't support such cases yet and it's unclear whether inlineWidget shouldn't be a limit itself.\n\t\tif ( limitElementFirstChild && limitElementFirstChild.name === 'paragraph' ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * The entire content is replaced with the paragraph. Selection is moved inside the paragraph.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer The model writer.\n\t */\n\t_replaceEntireContentWithParagraph( writer ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\t\tconst limitElement = model.schema.getLimitElement( selection );\n\t\tconst paragraph = writer.createElement( 'paragraph' );\n\n\t\twriter.remove( writer.createRangeIn( limitElement ) );\n\t\twriter.insert( paragraph, limitElement );\n\n\t\twriter.setSelection( paragraph, 0 );\n\t}\n\n\t/**\n\t * Checks if the selection is inside an empty element that is the first child of the limit element\n\t * and should be replaced with a paragraph.\n\t *\n\t * @private\n\t * @param {module:engine/model/selection~Selection} selection The selection.\n\t * @param {Number} sequence A number describing which subsequent delete event it is without the key being released.\n\t * @returns {Boolean}\n\t */\n\t_shouldReplaceFirstBlockWithParagraph( selection, sequence ) {\n\t\tconst model = this.editor.model;\n\n\t\t// Does nothing if user pressed and held the \"Backspace\" key or it was a \"Delete\" button.\n\t\tif ( sequence > 1 || this.direction != 'backward' ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst position = selection.getFirstPosition();\n\t\tconst limitElement = model.schema.getLimitElement( position );\n\t\tconst limitElementFirstChild = limitElement.getChild( 0 );\n\n\t\t// Only elements that are direct children of the limit element can be replaced.\n\t\t// Unwrapping from a block quote should be handled in a dedicated feature.\n\t\tif ( position.parent != limitElementFirstChild ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// A block should be replaced only if it was empty.\n\t\tif ( !selection.containsEntireContent( limitElementFirstChild ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Replace with a paragraph only if it's allowed there.\n\t\tif ( !model.schema.checkChild( limitElement, 'paragraph' ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Does nothing if the limit element already contains only a paragraph.\n\t\tif ( limitElementFirstChild.name == 'paragraph' ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/deleteobserver\n */\n\nimport Observer from '@ckeditor/ckeditor5-engine/src/view/observer/observer';\nimport DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata';\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * Delete observer introduces the {@link module:engine/view/document~Document#event:delete} event.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class DeleteObserver extends Observer {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tconst document = view.document;\n\t\tlet sequence = 0;\n\n\t\tdocument.on( 'keyup', ( evt, data ) => {\n\t\t\tif ( data.keyCode == keyCodes.delete || data.keyCode == keyCodes.backspace ) {\n\t\t\t\tsequence = 0;\n\t\t\t}\n\t\t} );\n\n\t\tdocument.on( 'keydown', ( evt, data ) => {\n\t\t\tconst deleteData = {};\n\n\t\t\tif ( data.keyCode == keyCodes.delete ) {\n\t\t\t\tdeleteData.direction = 'forward';\n\t\t\t\tdeleteData.unit = 'character';\n\t\t\t} else if ( data.keyCode == keyCodes.backspace ) {\n\t\t\t\tdeleteData.direction = 'backward';\n\t\t\t\tdeleteData.unit = 'codePoint';\n\t\t\t} else {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst hasWordModifier = env.isMac ? data.altKey : data.ctrlKey;\n\t\t\tdeleteData.unit = hasWordModifier ? 'word' : deleteData.unit;\n\t\t\tdeleteData.sequence = ++sequence;\n\n\t\t\tfireViewDeleteEvent( evt, data.domEvent, deleteData );\n\t\t} );\n\n\t\t// `beforeinput` is handled only for Android devices. Desktop Chrome and iOS are skipped because they are working fine now.\n\t\tif ( env.isAndroid ) {\n\t\t\tdocument.on( 'beforeinput', ( evt, data ) => {\n\t\t\t\t// If event type is other than `deleteContentBackward` then this is not deleting.\n\t\t\t\tif ( data.domEvent.inputType != 'deleteContentBackward' ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst deleteData = {\n\t\t\t\t\tunit: 'codepoint',\n\t\t\t\t\tdirection: 'backward',\n\t\t\t\t\tsequence: 1\n\t\t\t\t};\n\n\t\t\t\t// Android IMEs may change the DOM selection on `beforeinput` event so that the selection contains all the text\n\t\t\t\t// that the IME wants to remove. We will pass this information to `delete` event so proper part of the content is removed.\n\t\t\t\t//\n\t\t\t\t// Sometimes it is only expanding by a one character (in case of collapsed selection). In this case we don't need to\n\t\t\t\t// set a different selection to remove, it will work just fine.\n\t\t\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\n\t\t\t\tif ( domSelection.anchorNode == domSelection.focusNode && domSelection.anchorOffset + 1 != domSelection.focusOffset ) {\n\t\t\t\t\tdeleteData.selectionToRemove = view.domConverter.domSelectionToView( domSelection );\n\t\t\t\t}\n\n\t\t\t\tfireViewDeleteEvent( evt, data.domEvent, deleteData );\n\t\t\t} );\n\t\t}\n\n\t\tfunction fireViewDeleteEvent( originalEvent, domEvent, deleteData ) {\n\t\t\t// Save the event object to check later if it was stopped or not.\n\t\t\tlet event;\n\t\t\tdocument.once( 'delete', evt => ( event = evt ), { priority: Number.POSITIVE_INFINITY } );\n\n\t\t\tdocument.fire( 'delete', new DomEventData( document, domEvent, deleteData ) );\n\n\t\t\t// Stop the original event if `delete` event was stopped.\n\t\t\t// https://github.com/ckeditor/ckeditor5/issues/753\n\t\t\tif ( event && event.stop.called ) {\n\t\t\t\toriginalEvent.stop();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve() {}\n}\n\n/**\n * Event fired when the user tries to delete content (e.g. presses Delete or Backspace).\n *\n * Note: This event is fired by the {@link module:typing/deleteobserver~DeleteObserver observer}\n * (usually registered by the {@link module:typing/delete~Delete delete feature}).\n *\n * @event module:engine/view/document~Document#event:delete\n * @param {module:engine/view/observer/domeventdata~DomEventData} data\n * @param {'forward'|'delete'} data.direction The direction in which the deletion should happen.\n * @param {'character'|'word'} data.unit The \"amount\" of content that should be deleted.\n * @param {Number} data.sequence A number describing which subsequent delete event it is without the key being released.\n * If it's 2 or more it means that the key was pressed and hold.\n * @param {module:engine/view/selection~Selection} [data.selectionToRemove] View selection which content should be removed. If not set,\n * current selection should be used.\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/delete\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport DeleteCommand from './deletecommand';\nimport DeleteObserver from './deleteobserver';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * The delete and backspace feature. Handles the Delete and Backspace keys in the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Delete extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Delete';\n\t}\n\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\tview.addObserver( DeleteObserver );\n\n\t\tconst deleteForwardCommand = new DeleteCommand( editor, 'forward' );\n\n\t\t// Register `deleteForward` command and add `forwardDelete` command as an alias for backward compatibility.\n\t\teditor.commands.add( 'deleteForward', deleteForwardCommand );\n\t\teditor.commands.add( 'forwardDelete', deleteForwardCommand );\n\n\t\teditor.commands.add( 'delete', new DeleteCommand( editor, 'backward' ) );\n\n\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\tconst deleteCommandParams = { unit: data.unit, sequence: data.sequence };\n\n\t\t\t// If a specific (view) selection to remove was set, convert it to a model selection and set as a parameter for `DeleteCommand`.\n\t\t\tif ( data.selectionToRemove ) {\n\t\t\t\tconst modelSelection = editor.model.createSelection();\n\t\t\t\tconst ranges = [];\n\n\t\t\t\tfor ( const viewRange of data.selectionToRemove.getRanges() ) {\n\t\t\t\t\tranges.push( editor.editing.mapper.toModelRange( viewRange ) );\n\t\t\t\t}\n\n\t\t\t\tmodelSelection.setTo( ranges );\n\n\t\t\t\tdeleteCommandParams.selection = modelSelection;\n\t\t\t}\n\n\t\t\teditor.execute( data.direction == 'forward' ? 'deleteForward' : 'delete', deleteCommandParams );\n\n\t\t\tdata.preventDefault();\n\n\t\t\tview.scrollToTheSelection();\n\t\t} );\n\n\t\t// Android IMEs have a quirk - they change DOM selection after the input changes were performed by the browser.\n\t\t// This happens on `keyup` event. Android doesn't know anything about our deletion and selection handling. Even if the selection\n\t\t// was changed during input events, IME remembers the position where the selection \"should\" be placed and moves it there.\n\t\t//\n\t\t// To prevent incorrect selection, we save the selection after deleting here and then re-set it on `keyup`. This has to be done\n\t\t// on DOM selection level, because on `keyup` the model selection is still the same as it was just after deletion, so it\n\t\t// wouldn't be changed and the fix would do nothing.\n\t\t//\n\t\tif ( env.isAndroid ) {\n\t\t\tlet domSelectionAfterDeletion = null;\n\n\t\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\n\t\t\t\tdomSelectionAfterDeletion = {\n\t\t\t\t\tanchorNode: domSelection.anchorNode,\n\t\t\t\t\tanchorOffset: domSelection.anchorOffset,\n\t\t\t\t\tfocusNode: domSelection.focusNode,\n\t\t\t\t\tfocusOffset: domSelection.focusOffset\n\t\t\t\t};\n\t\t\t}, { priority: 'lowest' } );\n\n\t\t\tthis.listenTo( viewDocument, 'keyup', ( evt, data ) => {\n\t\t\t\tif ( domSelectionAfterDeletion ) {\n\t\t\t\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\n\t\t\t\t\tdomSelection.collapse( domSelectionAfterDeletion.anchorNode, domSelectionAfterDeletion.anchorOffset );\n\t\t\t\t\tdomSelection.extend( domSelectionAfterDeletion.focusNode, domSelectionAfterDeletion.focusOffset );\n\n\t\t\t\t\tdomSelectionAfterDeletion = null;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/typing\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Input from './input';\nimport Delete from './delete';\n\n/**\n * The typing feature. It handles typing.\n *\n * This is a \"glue\" plugin which loads the {@link module:typing/input~Input} and {@link module:typing/delete~Delete}\n * plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Typing extends Plugin {\n\tstatic get requires() {\n\t\treturn [ Input, Delete ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Typing';\n\t}\n}\n\n/**\n * The configuration of the typing features. Used by the features from the `@ckeditor/ckeditor5-typing` package.\n *\n * Read more in {@link module:typing/typing~TypingConfig}.\n *\n * @member {module:typing/typing~TypingConfig} module:core/editor/editorconfig~EditorConfig#typing\n */\n\n/**\n * The configuration of the typing features. Used by the typing features in `@ckeditor/ckeditor5-typing` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\ttyping: ... // Typing feature options.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface TypingConfig\n */\n\n/**\n * The granularity of undo/redo for typing and deleting. The value `20` means (more or less) that a new undo step\n * is created every 20 characters are inserted or deleted.\n *\n * @member {Number} [module:typing/typing~TypingConfig#undoStep=20]\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/getlasttextline\n */\n\n/**\n * Returns the last text line from the given range.\n *\n * \"The last text line\" is understood as text (from one or more text nodes) which is limited either by a parent block\n * or by inline elements (e.g. ``).\n *\n *\t\tconst rangeToCheck = model.createRange(\n *\t\t\tmodel.createPositionAt( paragraph, 0 ),\n *\t\t\tmodel.createPositionAt( paragraph, 'end' )\n *\t\t);\n *\n *\t\tconst { text, range } = getLastTextLine( rangeToCheck, model );\n *\n * For model below, the returned `text` will be \"Foo bar baz\" and `range` will be set on whole `` content:\n *\n *\t\tFoo bar baz\n *\n * However, in below case, `text` will be set to \"baz\" and `range` will be set only on \"baz\".\n *\n *\t\tFoobarbaz\n *\n * @protected\n * @param {module:engine/model/range~Range} range\n * @param {module:engine/model/model~Model} model\n * @returns {module:typing/utils/getlasttextline~LastTextLineData}\n */\nexport default function getLastTextLine( range, model ) {\n\tlet start = range.start;\n\n\tconst text = Array.from( range.getItems() ).reduce( ( rangeText, node ) => {\n\t\t// Trim text to a last occurrence of an inline element and update range start.\n\t\tif ( !( node.is( '$text' ) || node.is( '$textProxy' ) ) ) {\n\t\t\tstart = model.createPositionAfter( node );\n\n\t\t\treturn '';\n\t\t}\n\n\t\treturn rangeText + node.data;\n\t}, '' );\n\n\treturn { text, range: model.createRange( start, range.end ) };\n}\n\n/**\n * The value returned by {@link module:typing/utils/getlasttextline~getLastTextLine}.\n *\n * @typedef {Object} module:typing/utils/getlasttextline~LastTextLineData\n *\n * @property {String} text The text from the text nodes in the last text line.\n * @property {module:engine/model/range~Range} range The range set on the text nodes in the last text line.\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/textwatcher\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport getLastTextLine from './utils/getlasttextline';\n\n/**\n * The text watcher feature.\n *\n * Fires the {@link module:typing/textwatcher~TextWatcher#event:matched:data `matched:data`},\n * {@link module:typing/textwatcher~TextWatcher#event:matched:selection `matched:selection`} and\n * {@link module:typing/textwatcher~TextWatcher#event:unmatched `unmatched`} events on typing or selection changes.\n *\n * @private\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class TextWatcher {\n\t/**\n\t * Creates a text watcher instance.\n\t *\n\t * @param {module:engine/model/model~Model} model\n\t * @param {Function} testCallback See {@link module:typing/textwatcher~TextWatcher#testCallback}.\n\t */\n\tconstructor( model, testCallback ) {\n\t\t/**\n\t\t * The editor's model.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * The function used to match the text.\n\t\t *\n\t\t * The test callback can return 3 values:\n\t\t *\n\t\t * * `false` if there is no match,\n\t\t * * `true` if there is a match,\n\t\t * * an object if there is a match and we want to pass some additional information to the {@link #event:matched:data} event.\n\t\t *\n\t\t * @member {Function} #testCallback\n\t\t * @returns {Object} testResult\n\t\t */\n\t\tthis.testCallback = testCallback;\n\n\t\t/**\n\t\t * Whether there is a match currently.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.hasMatch = false;\n\n\t\t/**\n\t\t * Flag indicating whether the `TextWatcher` instance is enabled or disabled.\n\t\t * A disabled TextWatcher will not evaluate text.\n\t\t *\n\t\t * To disable TextWatcher:\n\t\t *\n\t\t *\t\tconst watcher = new TextWatcher( editor.model, testCallback );\n\t\t *\n\t\t *\t\t// After this a testCallback will not be called.\n\t\t *\t\twatcher.isEnabled = false;\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', true );\n\n\t\t// Toggle text watching on isEnabled state change.\n\t\tthis.on( 'change:isEnabled', () => {\n\t\t\tif ( this.isEnabled ) {\n\t\t\t\tthis._startListening();\n\t\t\t} else {\n\t\t\t\tthis.stopListening( model.document.selection );\n\t\t\t\tthis.stopListening( model.document );\n\t\t\t}\n\t\t} );\n\n\t\tthis._startListening();\n\t}\n\n\t/**\n\t * Starts listening to the editor for typing and selection events.\n\t *\n\t * @private\n\t */\n\t_startListening() {\n\t\tconst model = this.model;\n\t\tconst document = model.document;\n\n\t\tthis.listenTo( document.selection, 'change:range', ( evt, { directChange } ) => {\n\t\t\t// Indirect changes (i.e. when the user types or external changes are applied) are handled in the document's change event.\n\t\t\tif ( !directChange ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Act only on collapsed selection.\n\t\t\tif ( !document.selection.isCollapsed ) {\n\t\t\t\tif ( this.hasMatch ) {\n\t\t\t\t\tthis.fire( 'unmatched' );\n\t\t\t\t\tthis.hasMatch = false;\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._evaluateTextBeforeSelection( 'selection' );\n\t\t} );\n\n\t\tthis.listenTo( document, 'change:data', ( evt, batch ) => {\n\t\t\tif ( batch.type == 'transparent' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._evaluateTextBeforeSelection( 'data', { batch } );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the editor content for matched text.\n\t *\n\t * @fires matched:data\n\t * @fires matched:selection\n\t * @fires unmatched\n\t *\n\t * @private\n\t * @param {'data'|'selection'} suffix A suffix used for generating the event name.\n\t * @param {Object} data Data object for event.\n\t */\n\t_evaluateTextBeforeSelection( suffix, data = {} ) {\n\t\tconst model = this.model;\n\t\tconst document = model.document;\n\t\tconst selection = document.selection;\n\n\t\tconst rangeBeforeSelection = model.createRange( model.createPositionAt( selection.focus.parent, 0 ), selection.focus );\n\n\t\tconst { text, range } = getLastTextLine( rangeBeforeSelection, model );\n\n\t\tconst testResult = this.testCallback( text );\n\n\t\tif ( !testResult && this.hasMatch ) {\n\t\t\tthis.fire( 'unmatched' );\n\t\t}\n\n\t\tthis.hasMatch = !!testResult;\n\n\t\tif ( testResult ) {\n\t\t\tconst eventData = Object.assign( data, { text, range } );\n\n\t\t\t// If the test callback returns an object with additional data, assign the data as well.\n\t\t\tif ( typeof testResult == 'object' ) {\n\t\t\t\tObject.assign( eventData, testResult );\n\t\t\t}\n\n\t\t\tthis.fire( `matched:${ suffix }`, eventData );\n\t\t}\n\t}\n}\n\nmix( TextWatcher, ObservableMixin );\n\n/**\n * Fired whenever the text watcher found a match for data changes.\n *\n * @event matched:data\n * @param {Object} data Event data.\n * @param {String} data.text The full text before selection to which the regexp was applied.\n * @param {module:engine/model/range~Range} data.range The range representing the position of the `data.text`.\n * @param {Object} [data.testResult] The additional data returned from the {@link module:typing/textwatcher~TextWatcher#testCallback}.\n */\n\n/**\n * Fired whenever the text watcher found a match for selection changes.\n *\n * @event matched:selection\n * @param {Object} data Event data.\n * @param {String} data.text The full text before selection.\n * @param {module:engine/model/range~Range} data.range The range representing the position of the `data.text`.\n * @param {Object} [data.testResult] The additional data returned from the {@link module:typing/textwatcher~TextWatcher#testCallback}.\n */\n\n/**\n * Fired whenever the text does not match anymore. Fired only when the text watcher found a match.\n *\n * @event unmatched\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/twostepcaretmovement\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport priorities from '@ckeditor/ckeditor5-utils/src/priorities';\n\n/**\n * This plugin enables the two-step caret (phantom) movement behavior for\n * {@link module:typing/twostepcaretmovement~TwoStepCaretMovement#registerAttribute registered attributes}\n * on arrow right () and left () key press.\n *\n * Thanks to this (phantom) caret movement the user is able to type before/after as well as at the\n * beginning/end of an attribute.\n *\n * **Note:** This plugin support right–to–left (Arabic, Hebrew, etc.) content by mirroring its behavior\n * but for the sake of simplicity examples showcase only left–to–right use–cases.\n *\n * # Forward movement\n *\n * ## \"Entering\" an attribute:\n *\n * When this plugin is enabled and registered for the `a` attribute and the selection is right before it\n * (at the attribute boundary), pressing the right arrow key will not move the selection but update its\n * attributes accordingly:\n *\n * * When enabled:\n *\n * \t\tfoo{}<$text a=\"true\">bar\n *\n * \n *\n * \t\tfoo<$text a=\"true\">{}bar\n *\n * * When disabled:\n *\n * \t\tfoo{}<$text a=\"true\">bar\n *\n * \n *\n * \t\tfoo<$text a=\"true\">b{}ar\n *\n *\n * ## \"Leaving\" an attribute:\n *\n * * When enabled:\n *\n * \t\t<$text a=\"true\">bar{}baz\n *\n * \n *\n * \t\t<$text a=\"true\">bar{}baz\n *\n * * When disabled:\n *\n * \t\t<$text a=\"true\">bar{}baz\n *\n * \n *\n * \t\t<$text a=\"true\">barb{}az\n *\n * # Backward movement\n *\n * * When enabled:\n *\n * \t\t<$text a=\"true\">bar{}baz\n *\n * \n *\n * \t\t<$text a=\"true\">bar{}baz\n *\n * * When disabled:\n *\n * \t\t<$text a=\"true\">bar{}baz\n *\n * \n *\n * \t\t<$text a=\"true\">ba{}rb{}az\n *\n * # Multiple attributes\n *\n * * When enabled and many attributes starts or ends at the same position:\n *\n * \t\t<$text a=\"true\" b=\"true\">bar{}baz\n *\n * \n *\n * \t\t<$text a=\"true\" b=\"true\">bar{}baz\n *\n * * When enabled and one procedes another:\n *\n * \t\t<$text a=\"true\">bar<$text b=\"true\">{}bar\n *\n * \n *\n * \t\t<$text a=\"true\">bar{}<$text b=\"true\">bar\n *\n */\nexport default class TwoStepCaretMovement extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TwoStepCaretMovement';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A set of attributes to handle.\n\t\t *\n\t\t * @protected\n\t\t * @property {module:typing/twostepcaretmovement~TwoStepCaretMovement}\n\t\t */\n\t\tthis.attributes = new Set();\n\n\t\t/**\n\t\t * The current UID of the overridden gravity, as returned by\n\t\t * {@link module:engine/model/writer~Writer#overrideSelectionGravity}.\n\t\t *\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._overrideUid = null;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst view = editor.editing.view;\n\t\tconst locale = editor.locale;\n\n\t\tconst modelSelection = model.document.selection;\n\n\t\t// Listen to keyboard events and handle the caret movement according to the 2-step caret logic.\n\t\t//\n\t\t// Note: This listener has the \"high+1\" priority:\n\t\t// * \"high\" because of the filler logic implemented in the renderer which also engages on #keydown.\n\t\t// When the gravity is overridden the attributes of the (model) selection attributes are reset.\n\t\t// It may end up with the filler kicking in and breaking the selection.\n\t\t// * \"+1\" because we would like to avoid collisions with other features (like Widgets), which\n\t\t// take over the keydown events with the \"high\" priority. Two-step caret movement takes precedence\n\t\t// over Widgets in that matter.\n\t\t//\n\t\t// Find out more in https://github.com/ckeditor/ckeditor5-engine/issues/1301.\n\t\tthis.listenTo( view.document, 'keydown', ( evt, data ) => {\n\t\t\t// This implementation works only for collapsed selection.\n\t\t\tif ( !modelSelection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// When user tries to expand the selection or jump over the whole word or to the beginning/end then\n\t\t\t// two-steps movement is not necessary.\n\t\t\tif ( data.shiftKey || data.altKey || data.ctrlKey ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst arrowRightPressed = data.keyCode == keyCodes.arrowright;\n\t\t\tconst arrowLeftPressed = data.keyCode == keyCodes.arrowleft;\n\n\t\t\t// When neither left or right arrow has been pressed then do noting.\n\t\t\tif ( !arrowRightPressed && !arrowLeftPressed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst contentDirection = locale.contentLanguageDirection;\n\t\t\tlet isMovementHandled = false;\n\n\t\t\tif ( ( contentDirection === 'ltr' && arrowRightPressed ) || ( contentDirection === 'rtl' && arrowLeftPressed ) ) {\n\t\t\t\tisMovementHandled = this._handleForwardMovement( data );\n\t\t\t} else {\n\t\t\t\tisMovementHandled = this._handleBackwardMovement( data );\n\t\t\t}\n\n\t\t\t// Stop the keydown event if the two-step caret movement handled it. Avoid collisions\n\t\t\t// with other features which may also take over the caret movement (e.g. Widget).\n\t\t\tif ( isMovementHandled === true ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: priorities.get( 'high' ) + 1 } );\n\n\t\t/**\n\t\t * A flag indicating that the automatic gravity restoration should not happen upon the next\n\t\t * gravity restoration.\n\t\t * {@link module:engine/model/selection~Selection#event:change:range} event.\n\t\t *\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._isNextGravityRestorationSkipped = false;\n\n\t\t// The automatic gravity restoration logic.\n\t\tthis.listenTo( modelSelection, 'change:range', ( evt, data ) => {\n\t\t\t// Skipping the automatic restoration is needed if the selection should change\n\t\t\t// but the gravity must remain overridden afterwards. See the #handleBackwardMovement\n\t\t\t// to learn more.\n\t\t\tif ( this._isNextGravityRestorationSkipped ) {\n\t\t\t\tthis._isNextGravityRestorationSkipped = false;\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip automatic restore when the gravity is not overridden — simply, there's nothing to restore\n\t\t\t// at this moment.\n\t\t\tif ( !this._isGravityOverridden ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip automatic restore when the change is indirect AND the selection is at the attribute boundary.\n\t\t\t// It means that e.g. if the change was external (collaboration) and the user had their\n\t\t\t// selection around the link, its gravity should remain intact in this change:range event.\n\t\t\tif ( !data.directChange && isBetweenDifferentAttributes( modelSelection.getFirstPosition(), this.attributes ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._restoreGravity();\n\t\t} );\n\t}\n\n\t/**\n\t * Registers a given attribute for the two-step caret movement.\n\t *\n\t * @param {String} attribute Name of the attribute to handle.\n\t */\n\tregisterAttribute( attribute ) {\n\t\tthis.attributes.add( attribute );\n\t}\n\n\t/**\n\t * Updates the document selection and the view according to the two–step caret movement state\n\t * when moving **forwards**. Executed upon `keypress` in the {@link module:engine/view/view~View}.\n\t *\n\t * @private\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} data Data of the key press.\n\t * @returns {Boolean} `true` when the handler prevented caret movement\n\t */\n\t_handleForwardMovement( data ) {\n\t\tconst attributes = this.attributes;\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst position = selection.getFirstPosition();\n\t\t// DON'T ENGAGE 2-SCM if gravity is already overridden. It means that we just entered\n\t\t//\n\t\t// \t\tfoo<$text attribute>{}barbaz\n\t\t//\n\t\t// or left the attribute\n\t\t//\n\t\t// \t\tfoo<$text attribute>bar{}baz\n\t\t//\n\t\t// and the gravity will be restored automatically.\n\t\tif ( this._isGravityOverridden ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// DON'T ENGAGE 2-SCM when the selection is at the beginning of the block AND already has the\n\t\t// attribute:\n\t\t// * when the selection was initially set there using the mouse,\n\t\t// * when the editor has just started\n\t\t//\n\t\t//\t\t<$text attribute>{}barbaz\n\t\t//\n\t\tif ( position.isAtStart && hasAnyAttribute( selection, attributes ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// ENGAGE 2-SCM When at least one of the observed attributes changes its value (incl. starts, ends).\n\t\t//\n\t\t//\t\tfoo<$text attribute>bar{}baz\n\t\t//\t\tfoo<$text attribute>bar{}<$text otherAttribute>baz\n\t\t//\t\tfoo<$text attribute=1>bar{}<$text attribute=2>baz\n\t\t//\t\tfoo{}<$text attribute>barbaz\n\t\t//\n\t\tif ( isBetweenDifferentAttributes( position, attributes ) ) {\n\t\t\tpreventCaretMovement( data );\n\t\t\tthis._overrideGravity();\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Updates the document selection and the view according to the two–step caret movement state\n\t * when moving **backwards**. Executed upon `keypress` in the {@link module:engine/view/view~View}.\n\t *\n\t * @private\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} data Data of the key press.\n\t * @returns {Boolean} `true` when the handler prevented caret movement\n\t */\n\t_handleBackwardMovement( data ) {\n\t\tconst attributes = this.attributes;\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst position = selection.getFirstPosition();\n\n\t\t// When the gravity is already overridden (by this plugin), it means we are on the two-step position.\n\t\t// Prevent the movement, restore the gravity and update selection attributes.\n\t\t//\n\t\t//\t\tfoo<$text attribute=1>bar<$text attribute=2>{}baz\n\t\t//\t\tfoo<$text attribute>bar<$text otherAttribute>{}baz\n\t\t//\t\tfoo<$text attribute>{}barbaz\n\t\t//\t\tfoo<$text attribute>bar{}baz\n\t\t//\n\t\tif ( this._isGravityOverridden ) {\n\t\t\tpreventCaretMovement( data );\n\t\t\tthis._restoreGravity();\n\t\t\tsetSelectionAttributesFromTheNodeBefore( model, attributes, position );\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\t// REMOVE SELECTION ATTRIBUTE when restoring gravity towards a non-existent content at the\n\t\t\t// beginning of the block.\n\t\t\t//\n\t\t\t// \t\t{}<$text attribute>bar\n\t\t\t//\n\t\t\tif ( position.isAtStart ) {\n\t\t\t\tif ( hasAnyAttribute( selection, attributes ) ) {\n\t\t\t\t\tpreventCaretMovement( data );\n\t\t\t\t\tsetSelectionAttributesFromTheNodeBefore( model, attributes, position );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// When we are moving from natural gravity, to the position of the 2SCM, we need to override the gravity,\n\t\t\t// and make sure it won't be restored. Unless it's at the end of the block and an observed attribute.\n\t\t\t// We need to check if the caret is a one position before the attribute boundary:\n\t\t\t//\n\t\t\t//\t\tfoo<$text attribute=1>bar<$text attribute=2>b{}az\n\t\t\t//\t\tfoo<$text attribute>bar<$text otherAttribute>b{}az\n\t\t\t//\t\tfoo<$text attribute>b{}arbaz\n\t\t\t//\t\tfoo<$text attribute>barb{}az\n\t\t\t//\n\t\t\tif ( isStepAfterAnyAttributeBoundary( position, attributes ) ) {\n\t\t\t\t// ENGAGE 2-SCM if the selection has no attribute. This may happen when the user\n\t\t\t\t// left the attribute using a FORWARD 2-SCM.\n\t\t\t\t//\n\t\t\t\t// \t\t<$text attribute>bar{}\n\t\t\t\t//\n\t\t\t\tif (\n\t\t\t\t\tposition.isAtEnd &&\n\t\t\t\t\t!hasAnyAttribute( selection, attributes ) &&\n\t\t\t\t\tisBetweenDifferentAttributes( position, attributes )\n\t\t\t\t) {\n\t\t\t\t\tpreventCaretMovement( data );\n\t\t\t\t\tsetSelectionAttributesFromTheNodeBefore( model, attributes, position );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\t// Skip the automatic gravity restore upon the next selection#change:range event.\n\t\t\t\t// If not skipped, it would automatically restore the gravity, which should remain\n\t\t\t\t// overridden.\n\t\t\t\tthis._isNextGravityRestorationSkipped = true;\n\t\t\t\tthis._overrideGravity();\n\n\t\t\t\t// Don't return \"true\" here because we didn't call _preventCaretMovement.\n\t\t\t\t// Returning here will destabilize the filler logic, which also listens to\n\t\t\t\t// keydown (and the event would be stopped).\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * `true` when the gravity is overridden for the plugin.\n\t *\n\t * @readonly\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isGravityOverridden() {\n\t\treturn !!this._overrideUid;\n\t}\n\n\t/**\n\t * Overrides the gravity using the {@link module:engine/model/writer~Writer model writer}\n\t * and stores the information about this fact in the {@link #_overrideUid}.\n\t *\n\t * A shorthand for {@link module:engine/model/writer~Writer#overrideSelectionGravity}.\n\t *\n\t * @private\n\t */\n\t_overrideGravity() {\n\t\tthis._overrideUid = this.editor.model.change( writer => {\n\t\t\treturn writer.overrideSelectionGravity();\n\t\t} );\n\t}\n\n\t/**\n\t * Restores the gravity using the {@link module:engine/model/writer~Writer model writer}.\n\t *\n\t * A shorthand for {@link module:engine/model/writer~Writer#restoreSelectionGravity}.\n\t *\n\t * @private\n\t */\n\t_restoreGravity() {\n\t\tthis.editor.model.change( writer => {\n\t\t\twriter.restoreSelectionGravity( this._overrideUid );\n\t\t\tthis._overrideUid = null;\n\t\t} );\n\t}\n}\n\n// Checks whether the selection has any of given attributes.\n//\n// @param {module:engine/model/documentselection~DocumentSelection} selection\n// @param {Iterable.} attributes\nfunction hasAnyAttribute( selection, attributes ) {\n\tfor ( const observedAttribute of attributes ) {\n\t\tif ( selection.hasAttribute( observedAttribute ) ) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n// Applies the given attributes to the current selection using using the\n// values from the node before the current position. Uses\n// the {@link module:engine/model/writer~Writer model writer}.\n//\n// @param {module:engine/model/model~Model}\n// @param {Iterable.} attributess\n// @param {module:engine/model/position~Position} position\nfunction setSelectionAttributesFromTheNodeBefore( model, attributes, position ) {\n\tconst nodeBefore = position.nodeBefore;\n\tmodel.change( writer => {\n\t\tif ( nodeBefore ) {\n\t\t\twriter.setSelectionAttribute( nodeBefore.getAttributes() );\n\t\t} else {\n\t\t\twriter.removeSelectionAttribute( attributes );\n\t\t}\n\t} );\n}\n\n// Prevents the caret movement in the view by calling `preventDefault` on the event data.\n//\n// @alias data.preventDefault\nfunction preventCaretMovement( data ) {\n\tdata.preventDefault();\n}\n\n// Checks whether the step before `isBetweenDifferentAttributes()`.\n//\n// @param {module:engine/model/position~Position} position\n// @param {String} attribute\nfunction isStepAfterAnyAttributeBoundary( position, attributes ) {\n\tconst positionBefore = position.getShiftedBy( -1 );\n\treturn isBetweenDifferentAttributes( positionBefore, attributes );\n}\n\n// Checks whether the given position is between different values of given attributes.\n//\n// @param {module:engine/model/position~Position} position\n// @param {Iterable.} attributes\nfunction isBetweenDifferentAttributes( position, attributes ) {\n\tconst { nodeBefore, nodeAfter } = position;\n\tfor ( const observedAttribute of attributes ) {\n\t\tconst attrBefore = nodeBefore ? nodeBefore.getAttribute( observedAttribute ) : undefined;\n\t\tconst attrAfter = nodeAfter ? nodeAfter.getAttribute( observedAttribute ) : undefined;\n\n\t\tif ( attrAfter !== attrBefore ) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/texttransformation\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport TextWatcher from './textwatcher';\nimport { escapeRegExp } from 'lodash-es';\n\n// All named transformations.\nconst TRANSFORMATIONS = {\n\t// Common symbols:\n\tcopyright: { from: '(c)', to: '©' },\n\tregisteredTrademark: { from: '(r)', to: '®' },\n\ttrademark: { from: '(tm)', to: '™' },\n\n\t// Mathematical:\n\toneHalf: { from: '1/2', to: '½' },\n\toneThird: { from: '1/3', to: '⅓' },\n\ttwoThirds: { from: '2/3', to: '⅔' },\n\toneForth: { from: '1/4', to: '¼' },\n\tthreeQuarters: { from: '3/4', to: '¾' },\n\tlessThanOrEqual: { from: '<=', to: '≤' },\n\tgreaterThanOrEqual: { from: '>=', to: '≥' },\n\tnotEqual: { from: '!=', to: '≠' },\n\tarrowLeft: { from: '<-', to: '←' },\n\tarrowRight: { from: '->', to: '→' },\n\n\t// Typography:\n\thorizontalEllipsis: { from: '...', to: '…' },\n\tenDash: { from: /(^| )(--)( )$/, to: [ null, '–', null ] },\n\temDash: { from: /(^| )(---)( )$/, to: [ null, '—', null ] },\n\t// Quotations:\n\t// English, US\n\tquotesPrimary: { from: buildQuotesRegExp( '\"' ), to: [ null, '“', null, '”' ] },\n\tquotesSecondary: { from: buildQuotesRegExp( '\\'' ), to: [ null, '‘', null, '’' ] },\n\n\t// English, UK\n\tquotesPrimaryEnGb: { from: buildQuotesRegExp( '\\'' ), to: [ null, '‘', null, '’' ] },\n\tquotesSecondaryEnGb: { from: buildQuotesRegExp( '\"' ), to: [ null, '“', null, '”' ] },\n\n\t// Polish\n\tquotesPrimaryPl: { from: buildQuotesRegExp( '\"' ), to: [ null, '„', null, '”' ] },\n\tquotesSecondaryPl: { from: buildQuotesRegExp( '\\'' ), to: [ null, '‚', null, '’' ] }\n};\n\n// Transformation groups.\nconst TRANSFORMATION_GROUPS = {\n\tsymbols: [ 'copyright', 'registeredTrademark', 'trademark' ],\n\tmathematical: [\n\t\t'oneHalf', 'oneThird', 'twoThirds', 'oneForth', 'threeQuarters',\n\t\t'lessThanOrEqual', 'greaterThanOrEqual', 'notEqual',\n\t\t'arrowLeft', 'arrowRight'\n\t],\n\ttypography: [ 'horizontalEllipsis', 'enDash', 'emDash' ],\n\tquotes: [ 'quotesPrimary', 'quotesSecondary' ]\n};\n\n// A set of default transformations provided by the feature.\nconst DEFAULT_TRANSFORMATIONS = [\n\t'symbols',\n\t'mathematical',\n\t'typography',\n\t'quotes'\n];\n\n/**\n * The text transformation plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TextTransformation extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TextTransformation';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'typing', {\n\t\t\ttransformations: {\n\t\t\t\tinclude: DEFAULT_TRANSFORMATIONS\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst model = this.editor.model;\n\t\tconst modelSelection = model.document.selection;\n\n\t\tmodelSelection.on( 'change:range', () => {\n\t\t\t// Disable plugin when selection is inside a code block.\n\t\t\tthis.isEnabled = !modelSelection.anchor.parent.is( 'element', 'codeBlock' );\n\t\t} );\n\n\t\tthis._enableTransformationWatchers();\n\t}\n\n\t/**\n\t * Create new TextWatcher listening to the editor for typing and selection events.\n\t *\n\t * @private\n\t */\n\t_enableTransformationWatchers() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst input = editor.plugins.get( 'Input' );\n\t\tconst normalizedTransformations = normalizeTransformations( editor.config.get( 'typing.transformations' ) );\n\n\t\tconst testCallback = text => {\n\t\t\tfor ( const normalizedTransformation of normalizedTransformations ) {\n\t\t\t\tconst from = normalizedTransformation.from;\n\t\t\t\tconst match = from.test( text );\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\treturn { normalizedTransformation };\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tconst watcherCallback = ( evt, data ) => {\n\t\t\tif ( !input.isInput( data.batch ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { from, to } = data.normalizedTransformation;\n\n\t\t\tconst matches = from.exec( data.text );\n\t\t\tconst replaces = to( matches.slice( 1 ) );\n\n\t\t\tconst matchedRange = data.range;\n\n\t\t\tlet changeIndex = matches.index;\n\n\t\t\tmodel.enqueueChange( writer => {\n\t\t\t\tfor ( let i = 1; i < matches.length; i++ ) {\n\t\t\t\t\tconst match = matches[ i ];\n\t\t\t\t\tconst replaceWith = replaces[ i - 1 ];\n\n\t\t\t\t\tif ( replaceWith == null ) {\n\t\t\t\t\t\tchangeIndex += match.length;\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst replacePosition = matchedRange.start.getShiftedBy( changeIndex );\n\t\t\t\t\tconst replaceRange = model.createRange( replacePosition, replacePosition.getShiftedBy( match.length ) );\n\t\t\t\t\tconst attributes = getTextAttributesAfterPosition( replacePosition );\n\n\t\t\t\t\tmodel.insertContent( writer.createText( replaceWith, attributes ), replaceRange );\n\n\t\t\t\t\tchangeIndex += replaceWith.length;\n\t\t\t\t}\n\t\t\t} );\n\t\t};\n\n\t\tconst watcher = new TextWatcher( editor.model, testCallback );\n\n\t\twatcher.on( 'matched:data', watcherCallback );\n\t\twatcher.bind( 'isEnabled' ).to( this );\n\t}\n}\n\n// Normalizes the configuration `from` parameter value.\n// The normalized value for the `from` parameter is a RegExp instance. If the passed `from` is already a RegExp instance,\n// it is returned unchanged.\n//\n// @param {String|RegExp} from\n// @returns {RegExp}\nfunction normalizeFrom( from ) {\n\tif ( typeof from == 'string' ) {\n\t\treturn new RegExp( `(${ escapeRegExp( from ) })$` );\n\t}\n\n\t// `from` is already a regular expression.\n\treturn from;\n}\n\n// Normalizes the configuration `to` parameter value.\n// The normalized value for the `to` parameter is a function that takes an array and returns an array. See more in the\n// configuration description. If the passed `to` is already a function, it is returned unchanged.\n//\n// @param {String|Array.|Function} to\n// @returns {Function}\nfunction normalizeTo( to ) {\n\tif ( typeof to == 'string' ) {\n\t\treturn () => [ to ];\n\t} else if ( to instanceof Array ) {\n\t\treturn () => to;\n\t}\n\n\t// `to` is already a function.\n\treturn to;\n}\n\n// For given `position` returns attributes for the text that is after that position.\n// The text can be in the same text node as the position (`foo[]bar`) or in the next text node (`foo[]<$text bold=\"true\">bar`).\n//\n// @param {module:engine/model/position~Position} position\n// @returns {Iterable.<*>}\nfunction getTextAttributesAfterPosition( position ) {\n\tconst textNode = position.textNode ? position.textNode : position.nodeAfter;\n\n\treturn textNode.getAttributes();\n}\n\n// Returns a RegExp pattern string that detects a sentence inside a quote.\n//\n// @param {String} quoteCharacter The character to create a pattern for.\n// @returns {String}\nfunction buildQuotesRegExp( quoteCharacter ) {\n\treturn new RegExp( `(^|\\\\s)(${ quoteCharacter })([^${ quoteCharacter }]*)(${ quoteCharacter })$` );\n}\n\n// Reads text transformation config and returns normalized array of transformations objects.\n//\n// @param {module:typing/texttransformation~TextTransformationDescription} config\n// @returns {Array.<{from:String,to:Function}>}\nfunction normalizeTransformations( config ) {\n\tconst extra = config.extra || [];\n\tconst remove = config.remove || [];\n\tconst isNotRemoved = transformation => !remove.includes( transformation );\n\n\tconst configured = config.include.concat( extra ).filter( isNotRemoved );\n\n\treturn expandGroupsAndRemoveDuplicates( configured )\n\t\t.filter( isNotRemoved ) // Filter out 'remove' transformations as they might be set in group\n\t\t.map( transformation => TRANSFORMATIONS[ transformation ] || transformation )\n\t\t.map( transformation => ( {\n\t\t\tfrom: normalizeFrom( transformation.from ),\n\t\t\tto: normalizeTo( transformation.to )\n\t\t} ) );\n}\n\n// Reads definitions and expands named groups if needed to transformation names.\n// This method also removes duplicated named transformations if any.\n//\n// @param {Array.} definitions\n// @returns {Array.}\nfunction expandGroupsAndRemoveDuplicates( definitions ) {\n\t// Set is using to make sure that transformation names are not duplicated.\n\tconst definedTransformations = new Set();\n\n\tfor ( const transformationOrGroup of definitions ) {\n\t\tif ( TRANSFORMATION_GROUPS[ transformationOrGroup ] ) {\n\t\t\tfor ( const transformation of TRANSFORMATION_GROUPS[ transformationOrGroup ] ) {\n\t\t\t\tdefinedTransformations.add( transformation );\n\t\t\t}\n\t\t} else {\n\t\t\tdefinedTransformations.add( transformationOrGroup );\n\t\t}\n\t}\n\n\treturn Array.from( definedTransformations );\n}\n\n/**\n * The text transformation definition object. It describes what should be replaced with what.\n *\n * The input value (`from`) can be passed either as a string or as a regular expression.\n *\n * * If a string is passed, it will be simply checked if the end of the input matches it.\n * * If a regular expression is passed, its entire length must be covered with capturing groups (e.g. `/(foo)(bar)$/`).\n * Also, since it is compared against the end of the input, it has to end with `$` to be correctly matched.\n * See examples below.\n *\n * The output value (`to`) can be passed as a string, as an array or as a function.\n *\n * * If a string is passed, it will be used as a replacement value as-is. Note that a string output value can be used only if\n * the input value is a string, too.\n * * If an array is passed, it has to have the same number of elements as there are capturing groups in the input value regular expression.\n * Each capture group will be replaced with a corresponding string from the passed array. If a given capturing group should not be replaced,\n * use `null` instead of passing a string.\n * * If a function is used, it should return an array as described above. The function is passed one parameter — an array with matches\n * by the regular expression. See the examples below.\n *\n * A simple string-to-string replacement:\n *\n *\t\t{ from: '(c)', to: '©' }\n *\n * Change quote styles using a regular expression. Note how all the parts are in separate capturing groups and the space at the beginning\n * and the text inside quotes are not replaced (`null` passed as the first and the third value in the `to` parameter):\n *\n *\t\t{\n *\t\t\tfrom: /(^|\\s)(\")([^\"]*)(\")$/,\n *\t\t\tto: [ null, '“', null, '”' ]\n *\t\t}\n *\n * Automatic uppercase after a dot using a callback:\n *\n *\t\t{\n *\t\t\tfrom: /(\\. )([a-z])$/,\n *\t\t\tto: matches => [ null, matches[ 1 ].toUpperCase() ]\n *\t\t}\n *\n * @typedef {Object} module:typing/texttransformation~TextTransformationDescription\n * @property {String|RegExp} from The string or regular expression to transform.\n * @property {String} to The text to transform compatible with `String.replace()`.\n */\n\n/**\n * The configuration of the {@link module:typing/texttransformation~TextTransformation} feature.\n *\n * Read more in {@link module:typing/texttransformation~TextTransformationConfig}.\n *\n * @member {module:typing/texttransformation~TextTransformationConfig} module:typing/typing~TypingConfig#transformations\n */\n\n/**\n * The configuration of the text transformation feature.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\ttyping: {\n *\t\t\t\t\ttransformations: ... // Text transformation feature options.\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * By default, the feature comes pre-configured\n * (via {@link module:typing/texttransformation~TextTransformationConfig#include `config.typing.transformations.include`}) with the\n * following groups of transformations:\n *\n * * Typography (group name: `typography`)\n * - `ellipsis`: transforms `...` to `…`\n * - `enDash`: transforms ` -- ` to ` – `\n * - `emDash`: transforms ` --- ` to ` — `\n * * Quotations (group name: `quotes`)\n * - `quotesPrimary`: transforms `\"Foo bar\"` to `“Foo bar”`\n * - `quotesSecondary`: transforms `'Foo bar'` to `‘Foo bar’`\n * * Symbols (group name: `symbols`)\n * - `trademark`: transforms `(tm)` to `™`\n * - `registeredTrademark`: transforms `(r)` to `®`\n * - `copyright`: transforms `(c)` to `©`\n * * Mathematical (group name: `mathematical`)\n * - `oneHalf`: transforms `1/2` to: `½`\n * - `oneThird`: transforms `1/3` to: `⅓`\n * - `twoThirds`: transforms `2/3` to: `⅔`\n * - `oneForth`: transforms `1/4` to: `¼`\n * - `threeQuarters`: transforms `3/4` to: `¾`\n * - `lessThanOrEqual`: transforms `<=` to: `≤`\n * - `greaterThanOrEqual`: transforms `>=` to: `≥`\n * - `notEqual`: transforms `!=` to: `≠`\n * - `arrowLeft`: transforms `<-` to: `←`\n * - `arrowRight`: transforms `->` to: `→`\n * * Misc:\n * - `quotesPrimaryEnGb`: transforms `'Foo bar'` to `‘Foo bar’`\n * - `quotesSecondaryEnGb`: transforms `\"Foo bar\"` to `“Foo bar”`\n * - `quotesPrimaryPl`: transforms `\"Foo bar\"` to `„Foo bar”`\n * - `quotesSecondaryPl`: transforms `'Foo bar'` to `‚Foo bar’`\n *\n * In order to load additional transformations, use the\n * {@link module:typing/texttransformation~TextTransformationConfig#extra `transformations.extra` option}.\n *\n * In order to narrow down the list of transformations, use the\n * {@link module:typing/texttransformation~TextTransformationConfig#remove `transformations.remove` option}.\n *\n * In order to completely override the supported transformations, use the\n * {@link module:typing/texttransformation~TextTransformationConfig#include `transformations.include` option}.\n *\n * Examples:\n *\n *\t\tconst transformationsConfig = {\n *\t\t\tinclude: [\n *\t\t\t\t// Use only the 'quotes' and 'typography' groups.\n *\t\t\t\t'quotes',\n *\t\t\t\t'typography',\n *\n *\t\t\t\t// Plus, some custom transformation.\n *\t\t\t\t{ from: 'CKE', to: 'CKEditor' }\n *\t\t\t]\n *\t\t};\n *\n *\t\tconst transformationsConfig = {\n *\t\t\t// Remove the 'ellipsis' transformation loaded by the 'typography' group.\n *\t\t\tremove: [ 'ellipsis' ]\n *\t\t}\n *\n * @interface TextTransformationConfig\n */\n\n/* eslint-disable max-len */\n/**\n * The standard list of text transformations supported by the editor. By default it comes pre-configured with a couple dozen of them\n * (see {@link module:typing/texttransformation~TextTransformationConfig} for the full list). You can override this list completely\n * by setting this option or use the other two options\n * ({@link module:typing/texttransformation~TextTransformationConfig#extra `transformations.extra`},\n * {@link module:typing/texttransformation~TextTransformationConfig#remove `transformations.remove`}) to fine-tune the default list.\n *\n * @member {Array.} module:typing/texttransformation~TextTransformationConfig#include\n */\n\n/**\n * Additional text transformations that are added to the transformations defined in\n * {@link module:typing/texttransformation~TextTransformationConfig#include `transformations.include`}.\n *\n *\t\tconst transformationsConfig = {\n *\t\t\textra: [\n *\t\t\t\t{ from: 'CKE', to: 'CKEditor' }\n *\t\t\t]\n *\t\t};\n *\n * @member {Array.} module:typing/texttransformation~TextTransformationConfig#extra\n */\n\n/**\n * The text transformation names that are removed from transformations defined in\n * {@link module:typing/texttransformation~TextTransformationConfig#include `transformations.include`} or\n * {@link module:typing/texttransformation~TextTransformationConfig#extra `transformations.extra`}.\n *\n *\t\tconst transformationsConfig = {\n *\t\t\tremove: [\n *\t\t\t\t'ellipsis', // Remove only 'ellipsis' from the 'typography' group.\n *\t\t\t\t'mathematical' // Remove all transformations from the 'mathematical' group.\n *\t\t\t]\n *\t\t}\n *\n * @member {Array.} module:typing/texttransformation~TextTransformationConfig#remove\n */\n/* eslint-enable max-len */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/findattributerange\n */\n\n/**\n * Returns a model range that covers all consecutive nodes with the same `attributeName` and its `value`\n * that intersect the given `position`.\n *\n * It can be used e.g. to get the entire range on which the `linkHref` attribute needs to be changed when having a\n * selection inside a link.\n *\n * @param {module:engine/model/position~Position} position The start position.\n * @param {String} attributeName The attribute name.\n * @param {String} value The attribute value.\n * @param {module:engine/model/model~Model} model The model instance.\n * @returns {module:engine/model/range~Range} The link range.\n */\nexport default function findAttributeRange( position, attributeName, value, model ) {\n\treturn model.createRange(\n\t\t_findBound( position, attributeName, value, true, model ),\n\t\t_findBound( position, attributeName, value, false, model )\n\t);\n}\n\n// Walks forward or backward (depends on the `lookBack` flag), node by node, as long as they have the same attribute value\n// and returns a position just before or after (depends on the `lookBack` flag) the last matched node.\n//\n// @param {module:engine/model/position~Position} position The start position.\n// @param {String} attributeName The attribute name.\n// @param {String} value The attribute value.\n// @param {Boolean} lookBack Whether the walk direction is forward (`false`) or backward (`true`).\n// @returns {module:engine/model/position~Position} The position just before the last matched node.\nfunction _findBound( position, attributeName, value, lookBack, model ) {\n\t// Get node before or after position (depends on `lookBack` flag).\n\t// When position is inside text node then start searching from text node.\n\tlet node = position.textNode || ( lookBack ? position.nodeBefore : position.nodeAfter );\n\n\tlet lastNode = null;\n\n\twhile ( node && node.getAttribute( attributeName ) == value ) {\n\t\tlastNode = node;\n\t\tnode = lookBack ? node.previousSibling : node.nextSibling;\n\t}\n\n\treturn lastNode ? model.createPositionAt( lastNode, lookBack ? 'before' : 'after' ) : position;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport findAttributeRange from './findattributerange';\n\n/**\n * @module typing/utils/inlinehighlight\n */\n\n/**\n * Adds a visual highlight style to an attribute element in which the selection is anchored.\n * Together with two-step caret movement, they indicate that the user is typing inside the element.\n *\n * Highlight is turned on by adding the given class to the attribute element in the view:\n *\n * * The class is removed before the conversion has started, as callbacks added with the `'highest'` priority\n * to {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} events.\n * * The class is added in the view post fixer, after other changes in the model tree were converted to the view.\n *\n * This way, adding and removing the highlight does not interfere with conversion.\n *\n * Usage:\n *\n *\t\timport inlineHighlight from '@ckeditor/ckeditor5-typing/src/utils/inlinehighlight';\n *\n *\t\t// Make `ck-link_selected` class be applied on an `a` element\n *\t\t// whenever the corresponding `linkHref` attribute element is selected.\n *\t\tinlineHighlight( editor, 'linkHref', 'a', 'ck-link_selected' );\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @param {String} attributeName The attribute name to check.\n * @param {String} tagName The tagName of a view item.\n * @param {String} className The class name to apply in the view.\n */\nexport default function inlineHighlight( editor, attributeName, tagName, className ) {\n\tconst view = editor.editing.view;\n\tconst highlightedElements = new Set();\n\n\t// Adding the class.\n\tview.document.registerPostFixer( writer => {\n\t\tconst selection = editor.model.document.selection;\n\t\tlet changed = false;\n\n\t\tif ( selection.hasAttribute( attributeName ) ) {\n\t\t\tconst modelRange = findAttributeRange(\n\t\t\t\tselection.getFirstPosition(),\n\t\t\t\tattributeName,\n\t\t\t\tselection.getAttribute( attributeName ),\n\t\t\t\teditor.model\n\t\t\t);\n\t\t\tconst viewRange = editor.editing.mapper.toViewRange( modelRange );\n\n\t\t\t// There might be multiple view elements in the `viewRange`, for example, when the `a` element is\n\t\t\t// broken by a UIElement.\n\t\t\tfor ( const item of viewRange.getItems() ) {\n\t\t\t\tif ( item.is( 'element', tagName ) && !item.hasClass( className ) ) {\n\t\t\t\t\twriter.addClass( className, item );\n\t\t\t\t\thighlightedElements.add( item );\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn changed;\n\t} );\n\n\t// Removing the class.\n\teditor.conversion.for( 'editingDowncast' ).add( dispatcher => {\n\t\t// Make sure the highlight is removed on every possible event, before conversion is started.\n\t\tdispatcher.on( 'insert', removeHighlight, { priority: 'highest' } );\n\t\tdispatcher.on( 'remove', removeHighlight, { priority: 'highest' } );\n\t\tdispatcher.on( 'attribute', removeHighlight, { priority: 'highest' } );\n\t\tdispatcher.on( 'selection', removeHighlight, { priority: 'highest' } );\n\n\t\tfunction removeHighlight() {\n\t\t\tview.change( writer => {\n\t\t\t\tfor ( const item of highlightedElements.values() ) {\n\t\t\t\t\twriter.removeClass( className, item );\n\t\t\t\t\thighlightedElements.delete( item );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing\n */\n\nexport { default as Typing } from './typing';\nexport { default as Input } from './input';\nexport { default as Delete } from './delete';\n\nexport { default as TextWatcher } from './textwatcher';\nexport { default as TwoStepCaretMovement } from './twostepcaretmovement';\nexport { default as TextTransformation } from './texttransformation';\n\nexport { default as inlineHighlight } from './utils/inlinehighlight';\nexport { default as findAttributeRange } from './utils/findattributerange';\nexport { default as getLastTextLine } from './utils/getlasttextline';\n\nexport * from './utils/injectunsafekeystrokeshandling';\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/injectunsafekeystrokeshandling\n */\n\nimport { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * Handles keystrokes which are unsafe for typing. This handler's logic is explained\n * in https://github.com/ckeditor/ckeditor5-typing/issues/83#issuecomment-398690251.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n */\nexport default function injectUnsafeKeystrokesHandling( editor ) {\n\tlet latestCompositionSelection = null;\n\n\tconst model = editor.model;\n\tconst view = editor.editing.view;\n\tconst inputCommand = editor.commands.get( 'input' );\n\n\t// For Android, we want to handle keystrokes on `beforeinput` to be sure that code in `DeleteObserver` already had a chance to be fired.\n\tif ( env.isAndroid ) {\n\t\tview.document.on( 'beforeinput', ( evt, evtData ) => handleUnsafeKeystroke( evtData ), { priority: 'lowest' } );\n\t} else {\n\t\tview.document.on( 'keydown', ( evt, evtData ) => handleUnsafeKeystroke( evtData ), { priority: 'lowest' } );\n\t}\n\n\tview.document.on( 'compositionstart', handleCompositionStart, { priority: 'lowest' } );\n\n\tview.document.on( 'compositionend', () => {\n\t\tlatestCompositionSelection = model.createSelection( model.document.selection );\n\t}, { priority: 'lowest' } );\n\n\t// Handles the keydown event. We need to guess whether such keystroke is going to result\n\t// in typing. If so, then before character insertion happens, any selected content needs\n\t// to be deleted. Otherwise the default browser deletion mechanism would be\n\t// triggered, resulting in:\n\t//\n\t// * Hundreds of mutations which could not be handled.\n\t// * But most importantly, loss of control over how the content is being deleted.\n\t//\n\t// The method is used in a low-priority listener, hence allowing other listeners (e.g. delete or enter features)\n\t// to handle the event.\n\t//\n\t// @param {module:engine/view/observer/keyobserver~KeyEventData} evtData\n\tfunction handleUnsafeKeystroke( evtData ) {\n\t\tconst doc = model.document;\n\t\tconst isComposing = view.document.isComposing;\n\t\tconst isSelectionUnchanged = latestCompositionSelection && latestCompositionSelection.isEqual( doc.selection );\n\n\t\t// Reset stored composition selection.\n\t\tlatestCompositionSelection = null;\n\n\t\t// By relying on the state of the input command we allow disabling the entire input easily\n\t\t// by just disabling the input command. We could’ve used here the delete command but that\n\t\t// would mean requiring the delete feature which would block loading one without the other.\n\t\t// We could also check the editor.isReadOnly property, but that wouldn't allow to block\n\t\t// the input without blocking other features.\n\t\tif ( !inputCommand.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( isNonTypingKeystroke( evtData ) || doc.selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If during composition, deletion should be prevented as it may remove composed sequence (#83).\n\t\tif ( isComposing && evtData.keyCode === 229 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there is a `keydown` event fired with '229' keycode it might be related\n\t\t// to recent composition. Check if selection is the same as upon ending recent composition,\n\t\t// if so do not remove selected content as it will remove composed sequence (#83).\n\t\tif ( !isComposing && evtData.keyCode === 229 && isSelectionUnchanged ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdeleteSelectionContent();\n\t}\n\n\t// Handles the `compositionstart` event. It is used only in special cases to remove the contents\n\t// of a non-collapsed selection so composition itself does not result in complex mutations.\n\t//\n\t// The special case mentioned above is a situation in which the `keydown` event is fired after\n\t// `compositionstart` event. In such cases {@link #handleKeydown} cannot clear current selection\n\t// contents (because it is too late and will break the composition) so the composition handler takes care of it.\n\tfunction handleCompositionStart() {\n\t\tconst doc = model.document;\n\t\tconst isFlatSelection = doc.selection.rangeCount === 1 ? doc.selection.getFirstRange().isFlat : true;\n\n\t\t// If on `compositionstart` there is a non-collapsed selection which start and end have different parents\n\t\t// it means the `handleKeydown()` method did not remove its contents. It happens usually because\n\t\t// of different order of events (`compositionstart` before `keydown` - in Safari). In such cases\n\t\t// we need to remove selection contents on composition start (#83).\n\t\tif ( doc.selection.isCollapsed || isFlatSelection ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdeleteSelectionContent();\n\t}\n\n\tfunction deleteSelectionContent() {\n\t\tconst buffer = inputCommand.buffer;\n\n\t\tbuffer.lock();\n\n\t\tconst batch = buffer.batch;\n\t\tinputCommand._batches.add( batch );\n\n\t\tmodel.enqueueChange( batch, () => {\n\t\t\tmodel.deleteContent( model.document.selection );\n\t\t} );\n\n\t\tbuffer.unlock();\n\t}\n}\n\nconst safeKeycodes = [\n\tgetCode( 'arrowUp' ),\n\tgetCode( 'arrowRight' ),\n\tgetCode( 'arrowDown' ),\n\tgetCode( 'arrowLeft' ),\n\t9, // Tab\n\t16, // Shift\n\t17, // Ctrl\n\t18, // Alt\n\t19, // Pause\n\t20, // CapsLock\n\t27, // Escape\n\t33, // PageUp\n\t34, // PageDown\n\t35, // Home\n\t36, // End,\n\t45, // Insert,\n\t91, // Windows,\n\t93, // Menu key,\n\t144, // NumLock\n\t145, // ScrollLock,\n\t173, // Mute/Unmute\n\t174, // Volume up\n\t175, // Volume down,\n\t176, // Next song,\n\t177, // Previous song,\n\t178, // Stop,\n\t179, // Play/Pause,\n\t255 // Display brightness (increase and decrease)\n];\n\n// Function keys.\nfor ( let code = 112; code <= 135; code++ ) {\n\tsafeKeycodes.push( code );\n}\n\n/**\n * Returns `true` if a keystroke will **not** result in \"typing\".\n *\n * For instance, keystrokes that result in typing are letters \"a-zA-Z\", numbers \"0-9\", delete, backspace, etc.\n *\n * Keystrokes that do not cause typing are, for instance, Fn keys (F5, F8, etc.), arrow keys (←, →, ↑, ↓),\n * Tab (↹), \"Windows logo key\" (⊞ Win), etc.\n *\n * Note: This implementation is very simple and will need to be refined with time.\n *\n * @param {module:engine/view/observer/keyobserver~KeyEventData} keyData\n * @returns {Boolean}\n */\nexport function isNonTypingKeystroke( keyData ) {\n\t// Keystrokes which contain Ctrl or Cmd don't represent typing.\n\tif ( keyData.ctrlKey || keyData.metaKey ) {\n\t\treturn true;\n\t}\n\n\treturn safeKeycodes.includes( keyData.keyCode );\n}\n"],"sourceRoot":""}