diff options
Diffstat (limited to 'assets/editor')
-rw-r--r-- | assets/editor/editor.js | 6 | ||||
-rw-r--r-- | assets/editor/editor.js.map | 1 |
2 files changed, 7 insertions, 0 deletions
diff --git a/assets/editor/editor.js b/assets/editor/editor.js new file mode 100644 index 0000000..60137b5 --- /dev/null +++ b/assets/editor/editor.js @@ -0,0 +1,6 @@ +/*! + * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ +!function(t){t.en=Object.assign(t.en||{},{a:"Cannot upload file:",b:"Image toolbar",c:"Table toolbar",d:"Italic",e:"Strikethrough",f:"Underline",g:"Bold",h:"Subscript",i:"Code",j:"Superscript",k:"Block quote",l:"Choose heading",m:"Heading",n:"Full size image",o:"Side image",p:"Left aligned image",q:"Centered image",r:"Right aligned image",s:"image widget",t:"Insert image or file",u:"Increase indent",v:"Decrease indent",w:"Numbered List",x:"Bulleted List",y:"Insert image",z:"Enter image caption",aa:"Align left",ab:"Align right",ac:"Align center",ad:"Justify",ae:"Text alignment",af:"Text alignment toolbar",ag:"Upload failed",ah:"media widget",ai:"Upload in progress",aj:"Widget toolbar",ak:"Horizontal line",al:"Insert media",am:"The URL must not be empty.",an:"This media URL is not supported.",ao:"Remove Format",ap:"Insert table",aq:"Header column",ar:"Insert column left",as:"Insert column right",at:"Delete column",au:"Column",av:"Header row",aw:"Insert row below",ax:"Insert row above",ay:"Delete row",az:"Row",ba:"Merge cell up",bb:"Merge cell right",bc:"Merge cell down",bd:"Merge cell left",be:"Split cell vertically",bf:"Split cell horizontally",bg:"Merge cells",bh:"Link",bi:"Change image text alternative",bj:"Could not obtain resized image URL.",bk:"Selecting resized image failed",bl:"Could not insert image at the current position.",bm:"Inserting image failed",bn:"Rich Text Editor",bo:"Rich Text Editor, %0",bp:"Font Background Color",bq:"Font Color",br:"Font Family",bs:"Default",bt:"Font Size",bu:"Tiny",bv:"Small",bw:"Big",bx:"Huge",by:"Editor toolbar",bz:"Show more items",ca:"Dropdown toolbar",cb:"Unlink",cc:"Edit link",cd:"Open link in new tab",ce:"This link has no URL",cf:"Save",cg:"Cancel",ch:"Paste the media URL in the input.",ci:"Tip: Paste the URL into the content to embed faster.",cj:"Media URL",ck:"Link URL",cl:"Text alternative",cm:"%0 of %1",cn:"Previous",co:"Next",cp:"Remove color",cq:"Document colors",cr:"Black",cs:"Dim grey",ct:"Grey",cu:"Light grey",cv:"White",cw:"Red",cx:"Orange",cy:"Yellow",cz:"Light green",da:"Green",db:"Aquamarine",dc:"Turquoise",dd:"Light blue",de:"Blue",df:"Purple",dg:"Open in a new tab",dh:"Downloadable",di:"Undo",dj:"Redo",dk:"Paragraph",dl:"Heading 1",dm:"Heading 2",dn:"Heading 3",do:"Heading 4",dp:"Heading 5",dq:"Heading 6"})}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})),function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClassicEditor=e():t.ClassicEditor=e()}(window,(function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,i),o.l=!0,o.exports}return i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)i.d(n,o,function(e){return t[e]}.bind(null,o));return n},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=104)}([function(t,e,i){"use strict";i.d(e,"b",(function(){return n})),i.d(e,"a",(function(){return o}));class n extends Error{constructor(t,e,i){t=o(t),i&&(t+=" "+JSON.stringify(i)),super(t),this.name="CKEditorError",this.context=e,this.data=i}is(t){return"CKEditorError"===t}static rethrowUnexpectedError(t,e){if(t.is&&t.is("CKEditorError"))throw t;const i=new n(t.message,e);throw i.stack=t.stack,i}}function o(t){const e=t.match(/^([^:]+):/);return e?t+` Read more: https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/error-codes.html#error-${e[1]}\n`:t}},function(t,e,i){"use strict";var n,o=function(){return void 0===n&&(n=Boolean(window&&document&&document.all&&!window.atob)),n},s=function(){var t={};return function(e){if(void 0===t[e]){var i=document.querySelector(e);if(window.HTMLIFrameElement&&i instanceof window.HTMLIFrameElement)try{i=i.contentDocument.head}catch(t){i=null}t[e]=i}return t[e]}}(),r=[];function a(t){for(var e=-1,i=0;i<r.length;i++)if(r[i].identifier===t){e=i;break}return e}function c(t,e){for(var i={},n=[],o=0;o<t.length;o++){var s=t[o],c=e.base?s[0]+e.base:s[0],l=i[c]||0,d="".concat(c," ").concat(l);i[c]=l+1;var h=a(d),u={css:s[1],media:s[2],sourceMap:s[3]};-1!==h?(r[h].references++,r[h].updater(u)):r.push({identifier:d,updater:p(u,e),references:1}),n.push(d)}return n}function l(t){var e=document.createElement("style"),n=t.attributes||{};if(void 0===n.nonce){var o=i.nc;o&&(n.nonce=o)}if(Object.keys(n).forEach((function(t){e.setAttribute(t,n[t])})),"function"==typeof t.insert)t.insert(e);else{var r=s(t.insert||"head");if(!r)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");r.appendChild(e)}return e}var d,h=(d=[],function(t,e){return d[t]=e,d.filter(Boolean).join("\n")});function u(t,e,i,n){var o=i?"":n.media?"@media ".concat(n.media," {").concat(n.css,"}"):n.css;if(t.styleSheet)t.styleSheet.cssText=h(e,o);else{var s=document.createTextNode(o),r=t.childNodes;r[e]&&t.removeChild(r[e]),r.length?t.insertBefore(s,r[e]):t.appendChild(s)}}function f(t,e,i){var n=i.css,o=i.media,s=i.sourceMap;if(o?t.setAttribute("media",o):t.removeAttribute("media"),s&&btoa&&(n+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(s))))," */")),t.styleSheet)t.styleSheet.cssText=n;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(n))}}var m=null,g=0;function p(t,e){var i,n,o;if(e.singleton){var s=g++;i=m||(m=l(e)),n=u.bind(null,i,s,!1),o=u.bind(null,i,s,!0)}else i=l(e),n=f.bind(null,i,e),o=function(){!function(t){if(null===t.parentNode)return!1;t.parentNode.removeChild(t)}(i)};return n(t),function(e){if(e){if(e.css===t.css&&e.media===t.media&&e.sourceMap===t.sourceMap)return;n(t=e)}else o()}}t.exports=function(t,e){(e=e||{}).singleton||"boolean"==typeof e.singleton||(e.singleton=o());var i=c(t=t||[],e);return function(t){if(t=t||[],"[object Array]"===Object.prototype.toString.call(t)){for(var n=0;n<i.length;n++){var o=a(i[n]);r[o].references--}for(var s=c(t,e),l=0;l<i.length;l++){var d=a(i[l]);0===r[d].references&&(r[d].updater(),r.splice(d,1))}i=s}}}},,function(t,e,i){"use strict";var n=i(7),o="object"==typeof self&&self&&self.Object===Object&&self,s=n.a||o||Function("return this")();e.a=s},function(t,e,i){"use strict";(function(t){var n=i(3),o=i(13),s="object"==typeof exports&&exports&&!exports.nodeType&&exports,r=s&&"object"==typeof t&&t&&!t.nodeType&&t,a=r&&r.exports===s?n.a.Buffer:void 0,c=(a?a.isBuffer:void 0)||o.a;e.a=c}).call(this,i(9)(t))},function(t,e,i){"use strict";(function(t){var n=i(7),o="object"==typeof exports&&exports&&!exports.nodeType&&exports,s=o&&"object"==typeof t&&t&&!t.nodeType&&t,r=s&&s.exports===o&&n.a.process,a=function(){try{var t=s&&s.require&&s.require("util").types;return t||r&&r.binding&&r.binding("util")}catch(t){}}();e.a=a}).call(this,i(9)(t))},function(t,e,i){"use strict";(function(t){var e=i(0);const n="object"==typeof window?window:t;if(n.CKEDITOR_VERSION)throw new e.b("ckeditor-duplicated-modules: Some CKEditor 5 modules are duplicated.",null);n.CKEDITOR_VERSION="17.0.0"}).call(this,i(10))},function(t,e,i){"use strict";(function(t){var i="object"==typeof t&&t&&t.Object===Object&&t;e.a=i}).call(this,i(10))},function(t,e,i){"use strict";(function(t){var n=i(3),o="object"==typeof exports&&exports&&!exports.nodeType&&exports,s=o&&"object"==typeof t&&t&&!t.nodeType&&t,r=s&&s.exports===o?n.a.Buffer:void 0,a=r?r.allocUnsafe:void 0;e.a=function(t,e){if(e)return t.slice();var i=t.length,n=a?a(i):new t.constructor(i);return t.copy(n),n}}).call(this,i(9)(t))},function(t,e){t.exports=function(t){if(!t.webpackPolyfill){var e=Object.create(t);e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),Object.defineProperty(e,"exports",{enumerable:!0}),e.webpackPolyfill=1}return e}},function(t,e){var i;i=function(){return this}();try{i=i||new Function("return this")()}catch(t){"object"==typeof window&&(i=window)}t.exports=i},function(t,e,i){var n=i(1),o=i(70);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e,i){var n=i(1),o=i(91);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e,i){"use strict";e.a=function(){return!1}},function(t,e,i){var n=i(1),o=i(15);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-placeholder:before,.ck .ck-placeholder:before{content:attr(data-placeholder);pointer-events:none}.ck.ck-read-only .ck-placeholder:before{display:none}.ck.ck-placeholder:before,.ck .ck-placeholder:before{cursor:text;color:var(--ck-color-engine-placeholder-text)}"},function(t,e,i){var n=i(1),o=i(17);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck-hidden{display:none!important}.ck.ck-reset,.ck.ck-reset_all,.ck.ck-reset_all *{box-sizing:border-box;width:auto;height:auto;position:static}:root{--ck-z-default:1;--ck-z-modal:calc(var(--ck-z-default) + 999);--ck-color-base-foreground:#fafafa;--ck-color-base-background:#fff;--ck-color-base-border:#c4c4c4;--ck-color-base-action:#61b045;--ck-color-base-focus:#6cb5f9;--ck-color-base-text:#333;--ck-color-base-active:#198cf0;--ck-color-base-active-focus:#0e7fe1;--ck-color-base-error:#db3700;--ck-color-focus-border:#1f89e5;--ck-color-focus-outer-shadow:#bcdefb;--ck-color-focus-disabled-shadow:rgba(119,186,248,0.3);--ck-color-focus-error-shadow:rgba(255,64,31,0.3);--ck-color-text:var(--ck-color-base-text);--ck-color-shadow-drop:rgba(0,0,0,0.15);--ck-color-shadow-drop-active:rgba(0,0,0,0.2);--ck-color-shadow-inner:rgba(0,0,0,0.1);--ck-color-button-default-background:transparent;--ck-color-button-default-hover-background:#e6e6e6;--ck-color-button-default-active-background:#d9d9d9;--ck-color-button-default-active-shadow:#bfbfbf;--ck-color-button-default-disabled-background:transparent;--ck-color-button-on-background:#dedede;--ck-color-button-on-hover-background:#c4c4c4;--ck-color-button-on-active-background:#bababa;--ck-color-button-on-active-shadow:#a1a1a1;--ck-color-button-on-disabled-background:#dedede;--ck-color-button-action-background:var(--ck-color-base-action);--ck-color-button-action-hover-background:#579e3d;--ck-color-button-action-active-background:#53973b;--ck-color-button-action-active-shadow:#498433;--ck-color-button-action-disabled-background:#7ec365;--ck-color-button-action-text:var(--ck-color-base-background);--ck-color-button-save:#008a00;--ck-color-button-cancel:#db3700;--ck-color-switch-button-off-background:#b0b0b0;--ck-color-switch-button-off-hover-background:#a3a3a3;--ck-color-switch-button-on-background:var(--ck-color-button-action-background);--ck-color-switch-button-on-hover-background:#579e3d;--ck-color-switch-button-inner-background:var(--ck-color-base-background);--ck-color-switch-button-inner-shadow:rgba(0,0,0,0.1);--ck-color-dropdown-panel-background:var(--ck-color-base-background);--ck-color-dropdown-panel-border:var(--ck-color-base-border);--ck-color-input-background:var(--ck-color-base-background);--ck-color-input-border:#c7c7c7;--ck-color-input-error-border:var(--ck-color-base-error);--ck-color-input-text:var(--ck-color-base-text);--ck-color-input-disabled-background:#f2f2f2;--ck-color-input-disabled-border:#c7c7c7;--ck-color-input-disabled-text:#5c5c5c;--ck-color-list-background:var(--ck-color-base-background);--ck-color-list-button-hover-background:var(--ck-color-button-default-hover-background);--ck-color-list-button-on-background:var(--ck-color-base-active);--ck-color-list-button-on-background-focus:var(--ck-color-base-active-focus);--ck-color-list-button-on-text:var(--ck-color-base-background);--ck-color-panel-background:var(--ck-color-base-background);--ck-color-panel-border:var(--ck-color-base-border);--ck-color-toolbar-background:var(--ck-color-base-foreground);--ck-color-toolbar-border:var(--ck-color-base-border);--ck-color-tooltip-background:var(--ck-color-base-text);--ck-color-tooltip-text:var(--ck-color-base-background);--ck-color-engine-placeholder-text:#707070;--ck-color-upload-bar-background:#6cb5f9;--ck-color-link-default:#0000f0;--ck-color-link-selected-background:rgba(31,177,255,0.1);--ck-disabled-opacity:.5;--ck-focus-outer-shadow-geometry:0 0 0 3px;--ck-focus-outer-shadow:var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-outer-shadow);--ck-focus-disabled-outer-shadow:var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-disabled-shadow);--ck-focus-error-outer-shadow:var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-error-shadow);--ck-focus-ring:1px solid var(--ck-color-focus-border);--ck-font-size-base:13px;--ck-line-height-base:1.84615;--ck-font-face:Helvetica,Arial,Tahoma,Verdana,Sans-Serif;--ck-font-size-tiny:0.7em;--ck-font-size-small:0.75em;--ck-font-size-normal:1em;--ck-font-size-big:1.4em;--ck-font-size-large:1.8em;--ck-ui-component-min-height:2.3em}.ck.ck-reset,.ck.ck-reset_all,.ck.ck-reset_all *{margin:0;padding:0;border:0;background:transparent;text-decoration:none;vertical-align:middle;transition:none;word-wrap:break-word}.ck.ck-reset_all,.ck.ck-reset_all *{border-collapse:collapse;font:normal normal normal var(--ck-font-size-base)/var(--ck-line-height-base) var(--ck-font-face);color:var(--ck-color-text);text-align:left;white-space:nowrap;cursor:auto;float:none}.ck.ck-reset_all .ck-rtl *{text-align:right}.ck.ck-reset_all iframe{vertical-align:inherit}.ck.ck-reset_all textarea{white-space:pre-wrap}.ck.ck-reset_all input[type=password],.ck.ck-reset_all input[type=text],.ck.ck-reset_all textarea{cursor:text}.ck.ck-reset_all input[type=password][disabled],.ck.ck-reset_all input[type=text][disabled],.ck.ck-reset_all textarea[disabled]{cursor:default}.ck.ck-reset_all fieldset{padding:10px;border:2px groove #dfdee3}.ck.ck-reset_all button::-moz-focus-inner{padding:0;border:0}.ck[dir=rtl],.ck[dir=rtl] .ck{text-align:right}:root{--ck-border-radius:2px;--ck-inner-shadow:2px 2px 3px var(--ck-color-shadow-inner) inset;--ck-drop-shadow:0 1px 2px 1px var(--ck-color-shadow-drop);--ck-drop-shadow-active:0 3px 6px 1px var(--ck-color-shadow-drop-active);--ck-spacing-unit:0.6em;--ck-spacing-large:calc(var(--ck-spacing-unit)*1.5);--ck-spacing-standard:var(--ck-spacing-unit);--ck-spacing-medium:calc(var(--ck-spacing-unit)*0.8);--ck-spacing-small:calc(var(--ck-spacing-unit)*0.5);--ck-spacing-tiny:calc(var(--ck-spacing-unit)*0.3);--ck-spacing-extra-tiny:calc(var(--ck-spacing-unit)*0.16)}"},function(t,e,i){var n=i(1),o=i(19);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-editor__editable:not(.ck-editor__nested-editable){border-radius:0}.ck-rounded-corners .ck.ck-editor__editable:not(.ck-editor__nested-editable),.ck.ck-editor__editable:not(.ck-editor__nested-editable).ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-editor__editable:not(.ck-editor__nested-editable).ck-focused{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-inner-shadow),0 0}.ck.ck-editor__editable_inline{overflow:auto;padding:0 var(--ck-spacing-standard);border:1px solid transparent}.ck.ck-editor__editable_inline[dir=ltr]{text-align:left}.ck.ck-editor__editable_inline[dir=rtl]{text-align:right}.ck.ck-editor__editable_inline>:first-child{margin-top:var(--ck-spacing-large)}.ck.ck-editor__editable_inline>:last-child{margin-bottom:var(--ck-spacing-large)}.ck.ck-balloon-panel.ck-toolbar-container[class*=arrow_n]:after{border-bottom-color:var(--ck-color-base-foreground)}.ck.ck-balloon-panel.ck-toolbar-container[class*=arrow_s]:after{border-top-color:var(--ck-color-base-foreground)}"},function(t,e,i){var n=i(1),o=i(21);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-label{display:block}.ck.ck-voice-label{display:none}.ck.ck-label{font-weight:700}"},function(t,e,i){var n=i(1),o=i(23);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-sticky-panel .ck-sticky-panel__content_sticky{z-index:var(--ck-z-modal);position:fixed;top:0}.ck.ck-sticky-panel .ck-sticky-panel__content_sticky_bottom-limit{top:auto;position:absolute}.ck.ck-sticky-panel .ck-sticky-panel__content_sticky{box-shadow:var(--ck-drop-shadow),0 0;border-width:0 1px 1px;border-top-left-radius:0;border-top-right-radius:0}"},function(t,e,i){var n=i(1),o=i(25);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-dropdown{display:inline-block;position:relative}.ck.ck-dropdown .ck-dropdown__arrow{pointer-events:none;z-index:var(--ck-z-default)}.ck.ck-dropdown .ck-button.ck-dropdown__button{width:100%}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on .ck-tooltip{display:none}.ck.ck-dropdown .ck-dropdown__panel{-webkit-backface-visibility:hidden;display:none;z-index:var(--ck-z-modal);position:absolute}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel-visible{display:inline-block}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_ne,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nw{bottom:100%}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw{top:100%;bottom:auto}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_ne,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se{left:0}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw{right:0}:root{--ck-dropdown-arrow-size:calc(0.5*var(--ck-icon-size))}.ck.ck-dropdown{font-size:inherit}.ck.ck-dropdown .ck-dropdown__arrow{width:var(--ck-dropdown-arrow-size)}[dir=ltr] .ck.ck-dropdown .ck-dropdown__arrow{right:var(--ck-spacing-standard);margin-left:var(--ck-spacing-small)}[dir=rtl] .ck.ck-dropdown .ck-dropdown__arrow{left:var(--ck-spacing-standard);margin-right:var(--ck-spacing-small)}.ck.ck-dropdown.ck-disabled .ck-dropdown__arrow{opacity:var(--ck-disabled-opacity)}[dir=ltr] .ck.ck-dropdown .ck-button.ck-dropdown__button:not(.ck-button_with-text){padding-left:var(--ck-spacing-small)}[dir=rtl] .ck.ck-dropdown .ck-button.ck-dropdown__button:not(.ck-button_with-text){padding-right:var(--ck-spacing-small)}.ck.ck-dropdown .ck-button.ck-dropdown__button .ck-button__label{width:7em;overflow:hidden;text-overflow:ellipsis}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-disabled .ck-button__label{opacity:var(--ck-disabled-opacity)}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on{border-bottom-left-radius:0;border-bottom-right-radius:0}.ck.ck-dropdown__panel{box-shadow:var(--ck-drop-shadow),0 0;border-radius:0}.ck-rounded-corners .ck.ck-dropdown__panel,.ck.ck-dropdown__panel.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0}.ck.ck-dropdown__panel{background:var(--ck-color-dropdown-panel-background);border:1px solid var(--ck-color-dropdown-panel-border);bottom:0;min-width:100%}"},function(t,e,i){var n=i(1),o=i(27);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-icon{vertical-align:middle}:root{--ck-icon-size:calc(var(--ck-line-height-base)*var(--ck-font-size-normal))}.ck.ck-icon{width:var(--ck-icon-size);height:var(--ck-icon-size);font-size:.8333350694em;will-change:transform}.ck.ck-icon,.ck.ck-icon *{color:inherit;cursor:inherit}.ck.ck-icon :not([fill]){fill:currentColor}"},function(t,e,i){var n=i(1),o=i(29);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports='.ck.ck-tooltip,.ck.ck-tooltip .ck-tooltip__text:after{position:absolute;pointer-events:none;-webkit-backface-visibility:hidden}.ck.ck-tooltip{visibility:hidden;opacity:0;display:none;z-index:var(--ck-z-modal)}.ck.ck-tooltip .ck-tooltip__text{display:inline-block}.ck.ck-tooltip .ck-tooltip__text:after{content:"";width:0;height:0}:root{--ck-tooltip-arrow-size:5px}.ck.ck-tooltip{left:50%;top:0;transition:opacity .2s ease-in-out .2s}.ck.ck-tooltip .ck-tooltip__text{border-radius:0}.ck-rounded-corners .ck.ck-tooltip .ck-tooltip__text,.ck.ck-tooltip .ck-tooltip__text.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-tooltip .ck-tooltip__text{font-size:.9em;line-height:1.5;color:var(--ck-color-tooltip-text);padding:var(--ck-spacing-small) var(--ck-spacing-medium);background:var(--ck-color-tooltip-background);position:relative;left:-50%}.ck.ck-tooltip .ck-tooltip__text:after{transition:opacity .2s ease-in-out .2s;border-style:solid;left:50%}.ck.ck-tooltip.ck-tooltip_s{bottom:calc(-1*var(--ck-tooltip-arrow-size));transform:translateY(100%)}.ck.ck-tooltip.ck-tooltip_s .ck-tooltip__text:after{top:calc(-1*var(--ck-tooltip-arrow-size));transform:translateX(-50%);border-left-color:transparent;border-bottom-color:var(--ck-color-tooltip-background);border-right-color:transparent;border-top-color:transparent;border-left-width:var(--ck-tooltip-arrow-size);border-bottom-width:var(--ck-tooltip-arrow-size);border-right-width:var(--ck-tooltip-arrow-size);border-top-width:0}.ck.ck-tooltip.ck-tooltip_n{top:calc(-1*var(--ck-tooltip-arrow-size));transform:translateY(-100%)}.ck.ck-tooltip.ck-tooltip_n .ck-tooltip__text:after{bottom:calc(-1*var(--ck-tooltip-arrow-size));transform:translateX(-50%);border-left-color:transparent;border-bottom-color:transparent;border-right-color:transparent;border-top-color:var(--ck-color-tooltip-background);border-left-width:var(--ck-tooltip-arrow-size);border-bottom-width:0;border-right-width:var(--ck-tooltip-arrow-size);border-top-width:var(--ck-tooltip-arrow-size)}'},function(t,e,i){var n=i(1),o=i(31);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-button,a.ck.ck-button{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.ck.ck-button .ck-tooltip,a.ck.ck-button .ck-tooltip{display:block}@media (hover:none){.ck.ck-button .ck-tooltip,a.ck.ck-button .ck-tooltip{display:none}}.ck.ck-button,a.ck.ck-button{position:relative;display:inline-flex;align-items:center;justify-content:left}.ck.ck-button .ck-button__label,a.ck.ck-button .ck-button__label{display:none}.ck.ck-button.ck-button_with-text .ck-button__label,a.ck.ck-button.ck-button_with-text .ck-button__label{display:inline-block}.ck.ck-button:not(.ck-button_with-text),a.ck.ck-button:not(.ck-button_with-text){justify-content:center}.ck.ck-button:hover .ck-tooltip,a.ck.ck-button:hover .ck-tooltip{visibility:visible;opacity:1}.ck.ck-button:focus:not(:hover) .ck-tooltip,a.ck.ck-button:focus:not(:hover) .ck-tooltip{display:none}.ck.ck-button,a.ck.ck-button{background:var(--ck-color-button-default-background)}.ck.ck-button:not(.ck-disabled):hover,a.ck.ck-button:not(.ck-disabled):hover{background:var(--ck-color-button-default-hover-background)}.ck.ck-button:not(.ck-disabled):active,a.ck.ck-button:not(.ck-disabled):active{background:var(--ck-color-button-default-active-background);box-shadow:inset 0 2px 2px var(--ck-color-button-default-active-shadow)}.ck.ck-button.ck-disabled,a.ck.ck-button.ck-disabled{background:var(--ck-color-button-default-disabled-background)}.ck.ck-button,a.ck.ck-button{border-radius:0}.ck-rounded-corners .ck.ck-button,.ck-rounded-corners a.ck.ck-button,.ck.ck-button.ck-rounded-corners,a.ck.ck-button.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-button,a.ck.ck-button{white-space:nowrap;cursor:default;vertical-align:middle;padding:var(--ck-spacing-tiny);text-align:center;min-width:var(--ck-ui-component-min-height);min-height:var(--ck-ui-component-min-height);line-height:1;font-size:inherit;border:1px solid transparent;transition:box-shadow .2s ease-in-out,border .2s ease-in-out;-webkit-appearance:none}.ck.ck-button:active,.ck.ck-button:focus,a.ck.ck-button:active,a.ck.ck-button:focus{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow),0 0}.ck.ck-button .ck-button__icon use,.ck.ck-button .ck-button__icon use *,a.ck.ck-button .ck-button__icon use,a.ck.ck-button .ck-button__icon use *{color:inherit}.ck.ck-button .ck-button__label,a.ck.ck-button .ck-button__label{font-size:inherit;font-weight:inherit;color:inherit;cursor:inherit;vertical-align:middle}[dir=ltr] .ck.ck-button .ck-button__label,[dir=ltr] a.ck.ck-button .ck-button__label{text-align:left}[dir=rtl] .ck.ck-button .ck-button__label,[dir=rtl] a.ck.ck-button .ck-button__label{text-align:right}.ck.ck-button .ck-button__keystroke,a.ck.ck-button .ck-button__keystroke{color:inherit}[dir=ltr] .ck.ck-button .ck-button__keystroke,[dir=ltr] a.ck.ck-button .ck-button__keystroke{margin-left:var(--ck-spacing-large)}[dir=rtl] .ck.ck-button .ck-button__keystroke,[dir=rtl] a.ck.ck-button .ck-button__keystroke{margin-right:var(--ck-spacing-large)}.ck.ck-button .ck-button__keystroke,a.ck.ck-button .ck-button__keystroke{font-weight:700;opacity:.7}.ck.ck-button.ck-disabled:active,.ck.ck-button.ck-disabled:focus,a.ck.ck-button.ck-disabled:active,a.ck.ck-button.ck-disabled:focus{box-shadow:var(--ck-focus-disabled-outer-shadow),0 0}.ck.ck-button.ck-disabled .ck-button__icon,a.ck.ck-button.ck-disabled .ck-button__icon{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-disabled .ck-button__label,a.ck.ck-button.ck-disabled .ck-button__label{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-disabled .ck-button__keystroke,a.ck.ck-button.ck-disabled .ck-button__keystroke{opacity:.3}.ck.ck-button.ck-button_with-text,a.ck.ck-button.ck-button_with-text{padding:var(--ck-spacing-tiny) var(--ck-spacing-standard)}[dir=ltr] .ck.ck-button.ck-button_with-text .ck-button__icon,[dir=ltr] a.ck.ck-button.ck-button_with-text .ck-button__icon{margin-left:calc(-1*var(--ck-spacing-small));margin-right:var(--ck-spacing-small)}[dir=rtl] .ck.ck-button.ck-button_with-text .ck-button__icon,[dir=rtl] a.ck.ck-button.ck-button_with-text .ck-button__icon{margin-right:calc(-1*var(--ck-spacing-small));margin-left:var(--ck-spacing-small)}.ck.ck-button.ck-button_with-keystroke .ck-button__label,a.ck.ck-button.ck-button_with-keystroke .ck-button__label{flex-grow:1}.ck.ck-button.ck-on,a.ck.ck-button.ck-on{background:var(--ck-color-button-on-background)}.ck.ck-button.ck-on:not(.ck-disabled):hover,a.ck.ck-button.ck-on:not(.ck-disabled):hover{background:var(--ck-color-button-on-hover-background)}.ck.ck-button.ck-on:not(.ck-disabled):active,a.ck.ck-button.ck-on:not(.ck-disabled):active{background:var(--ck-color-button-on-active-background);box-shadow:inset 0 2px 2px var(--ck-color-button-on-active-shadow)}.ck.ck-button.ck-on.ck-disabled,a.ck.ck-button.ck-on.ck-disabled{background:var(--ck-color-button-on-disabled-background)}.ck.ck-button.ck-button-save,a.ck.ck-button.ck-button-save{color:var(--ck-color-button-save)}.ck.ck-button.ck-button-cancel,a.ck.ck-button.ck-button-cancel{color:var(--ck-color-button-cancel)}.ck.ck-button-action,a.ck.ck-button-action{background:var(--ck-color-button-action-background)}.ck.ck-button-action:not(.ck-disabled):hover,a.ck.ck-button-action:not(.ck-disabled):hover{background:var(--ck-color-button-action-hover-background)}.ck.ck-button-action:not(.ck-disabled):active,a.ck.ck-button-action:not(.ck-disabled):active{background:var(--ck-color-button-action-active-background);box-shadow:inset 0 2px 2px var(--ck-color-button-action-active-shadow)}.ck.ck-button-action.ck-disabled,a.ck.ck-button-action.ck-disabled{background:var(--ck-color-button-action-disabled-background)}.ck.ck-button-action,a.ck.ck-button-action{color:var(--ck-color-button-action-text)}.ck.ck-button-bold,a.ck.ck-button-bold{font-weight:700}"},function(t,e,i){var n=i(1),o=i(33);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-list{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;display:flex;flex-direction:column}.ck.ck-list .ck-list__item,.ck.ck-list .ck-list__separator{display:block}.ck.ck-list .ck-list__item>:focus{position:relative;z-index:var(--ck-z-default)}.ck.ck-list{border-radius:0}.ck-rounded-corners .ck.ck-list,.ck.ck-list.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-list{list-style-type:none;background:var(--ck-color-list-background)}.ck.ck-list__item{cursor:default;min-width:12em}.ck.ck-list__item .ck-button{min-height:unset;width:100%;text-align:left;border-radius:0;padding:calc(0.2*var(--ck-line-height-base)*var(--ck-font-size-base)) calc(0.4*var(--ck-line-height-base)*var(--ck-font-size-base))}.ck.ck-list__item .ck-button .ck-button__label{line-height:calc(1.2*var(--ck-line-height-base)*var(--ck-font-size-base))}.ck.ck-list__item .ck-button:active{box-shadow:none}.ck.ck-list__item .ck-button.ck-on{background:var(--ck-color-list-button-on-background);color:var(--ck-color-list-button-on-text)}.ck.ck-list__item .ck-button.ck-on:active{box-shadow:none}.ck.ck-list__item .ck-button.ck-on:hover:not(.ck-disabled){background:var(--ck-color-list-button-on-background-focus)}.ck.ck-list__item .ck-button.ck-on:focus:not(.ck-disabled){border-color:var(--ck-color-base-background)}.ck.ck-list__item .ck-button:hover:not(.ck-disabled){background:var(--ck-color-list-button-hover-background)}.ck.ck-list__item .ck-switchbutton.ck-on{background:var(--ck-color-list-background);color:inherit}.ck.ck-list__item .ck-switchbutton.ck-on:hover:not(.ck-disabled){background:var(--ck-color-list-button-hover-background);color:inherit}.ck.ck-list__separator{height:1px;width:100%;background:var(--ck-color-base-border)}"},function(t,e,i){var n=i(1),o=i(35);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-button.ck-switchbutton .ck-button__toggle,.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{display:block}:root{--ck-switch-button-toggle-width:2.6153846154em;--ck-switch-button-toggle-inner-size:1.0769230769em;--ck-switch-button-toggle-spacing:1px;--ck-switch-button-translation:1.3846153847em}[dir=ltr] .ck.ck-button.ck-switchbutton .ck-button__label{margin-right:calc(2*var(--ck-spacing-large))}[dir=rtl] .ck.ck-button.ck-switchbutton .ck-button__label{margin-left:calc(2*var(--ck-spacing-large))}.ck.ck-button.ck-switchbutton .ck-button__toggle{border-radius:0}.ck-rounded-corners .ck.ck-button.ck-switchbutton .ck-button__toggle,.ck.ck-button.ck-switchbutton .ck-button__toggle.ck-rounded-corners{border-radius:var(--ck-border-radius)}[dir=ltr] .ck.ck-button.ck-switchbutton .ck-button__toggle{margin-left:auto}[dir=rtl] .ck.ck-button.ck-switchbutton .ck-button__toggle{margin-right:auto}.ck.ck-button.ck-switchbutton .ck-button__toggle{transition:background .4s ease;width:var(--ck-switch-button-toggle-width);background:var(--ck-color-switch-button-off-background)}.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{border-radius:0}.ck-rounded-corners .ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner,.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner.ck-rounded-corners{border-radius:var(--ck-border-radius);border-radius:calc(0.5*var(--ck-border-radius))}.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{margin:var(--ck-switch-button-toggle-spacing);width:var(--ck-switch-button-toggle-inner-size);height:var(--ck-switch-button-toggle-inner-size);background:var(--ck-color-switch-button-inner-background);transition:all .3s ease}.ck.ck-button.ck-switchbutton .ck-button__toggle:hover{background:var(--ck-color-switch-button-off-hover-background)}.ck.ck-button.ck-switchbutton .ck-button__toggle:hover .ck-button__toggle__inner{box-shadow:0 0 0 5px var(--ck-color-switch-button-inner-shadow)}.ck.ck-button.ck-switchbutton.ck-disabled .ck-button__toggle{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle{background:var(--ck-color-switch-button-on-background)}.ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle:hover{background:var(--ck-color-switch-button-on-hover-background)}[dir=ltr] .ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle .ck-button__toggle__inner{transform:translateX(var(--ck-switch-button-translation))}[dir=rtl] .ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle .ck-button__toggle__inner{transform:translateX(calc(-1*var(--ck-switch-button-translation)))}"},function(t,e,i){var n=i(1),o=i(37);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-toolbar-dropdown .ck.ck-toolbar .ck.ck-toolbar__items{flex-wrap:nowrap}.ck.ck-toolbar-dropdown .ck-dropdown__panel .ck-button:focus{z-index:calc(var(--ck-z-default) + 1)}.ck.ck-toolbar-dropdown .ck-toolbar{border:0}"},function(t,e,i){var n=i(1),o=i(39);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-dropdown .ck-dropdown__panel .ck-list{border-radius:0}.ck-rounded-corners .ck.ck-dropdown .ck-dropdown__panel .ck-list,.ck.ck-dropdown .ck-dropdown__panel .ck-list.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0}.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:first-child .ck-button{border-radius:0}.ck-rounded-corners .ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:first-child .ck-button,.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:first-child .ck-button.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0;border-bottom-left-radius:0;border-bottom-right-radius:0}.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:last-child .ck-button{border-radius:0}.ck-rounded-corners .ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:last-child .ck-button,.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:last-child .ck-button.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0;border-top-right-radius:0}"},function(t,e,i){var n=i(1),o=i(41);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-toolbar{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;display:flex;flex-flow:row nowrap;align-items:center}.ck.ck-toolbar>.ck-toolbar__items{display:flex;flex-flow:row wrap;align-items:center;flex-grow:1}.ck.ck-toolbar .ck.ck-toolbar__separator{display:inline-block}.ck.ck-toolbar .ck.ck-toolbar__separator:first-child,.ck.ck-toolbar .ck.ck-toolbar__separator:last-child{display:none}.ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items{flex-wrap:nowrap}.ck.ck-toolbar.ck-toolbar_vertical>.ck-toolbar__items{flex-direction:column}.ck.ck-toolbar.ck-toolbar_floating>.ck-toolbar__items{flex-wrap:nowrap}.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown>.ck-dropdown__button .ck-dropdown__arrow{display:none}.ck.ck-toolbar{border-radius:0}.ck-rounded-corners .ck.ck-toolbar,.ck.ck-toolbar.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-toolbar{background:var(--ck-color-toolbar-background);padding:0 var(--ck-spacing-small);border:1px solid var(--ck-color-toolbar-border)}.ck.ck-toolbar>.ck-toolbar__items>*{margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small);margin-right:var(--ck-spacing-small)}.ck.ck-toolbar.ck-toolbar_vertical{padding:0}.ck.ck-toolbar.ck-toolbar_vertical>.ck-toolbar__items>.ck{width:100%;margin:0;border-radius:0;border:0}.ck.ck-toolbar.ck-toolbar_compact{padding:0}.ck.ck-toolbar.ck-toolbar_compact .ck-toolbar__items>.ck{margin:0}.ck.ck-toolbar.ck-toolbar_compact .ck-toolbar__items>.ck:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.ck.ck-toolbar.ck-toolbar_compact .ck-toolbar__items>.ck:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.ck.ck-toolbar.ck-toolbar_compact .ck-toolbar__items>.ck:not(:first-child):not(:last-child){border-radius:0}.ck.ck-toolbar>.ck-toolbar__items>*,.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown{margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small)}.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown>.ck.ck-button.ck-dropdown__button{padding-left:var(--ck-spacing-tiny)}.ck.ck-toolbar .ck.ck-toolbar__separator{align-self:stretch;width:1px;min-width:1px;margin-top:0;margin-bottom:0;background:var(--ck-color-toolbar-border)}.ck-toolbar-container .ck.ck-toolbar{border:0}.ck.ck-toolbar[dir=rtl]>.ck.ck-toolbar__grouped-dropdown,[dir=rtl] .ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown{padding-right:var(--ck-spacing-small)}.ck.ck-toolbar[dir=rtl]>.ck.ck-toolbar__items>*,[dir=rtl] .ck.ck-toolbar>.ck.ck-toolbar__items>*{margin-left:var(--ck-spacing-small);margin-right:0}.ck.ck-toolbar[dir=rtl]>.ck.ck-toolbar__items>:last-child,[dir=rtl] .ck.ck-toolbar>.ck.ck-toolbar__items>:last-child{margin-left:0}.ck.ck-toolbar[dir=rtl].ck-toolbar_grouping>.ck-toolbar__items,[dir=rtl] .ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items{margin-left:var(--ck-spacing-small)}.ck.ck-toolbar[dir=ltr]>.ck.ck-toolbar__grouped-dropdown,[dir=ltr] .ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown{padding-left:var(--ck-spacing-small)}.ck.ck-toolbar[dir=ltr]>.ck.ck-toolbar__items>:last-child,[dir=ltr] .ck.ck-toolbar>.ck.ck-toolbar__items>:last-child{margin-right:0}.ck.ck-toolbar[dir=ltr].ck-toolbar_grouping>.ck-toolbar__items,[dir=ltr] .ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items{margin-right:var(--ck-spacing-small)}"},function(t,e,i){var n=i(1),o=i(43);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-editor{position:relative}.ck.ck-editor .ck-editor__top .ck-sticky-panel .ck-toolbar{z-index:var(--ck-z-modal)}.ck.ck-editor__top .ck-sticky-panel .ck-toolbar{border-radius:0}.ck-rounded-corners .ck.ck-editor__top .ck-sticky-panel .ck-toolbar,.ck.ck-editor__top .ck-sticky-panel .ck-toolbar.ck-rounded-corners{border-radius:var(--ck-border-radius);border-bottom-left-radius:0;border-bottom-right-radius:0}.ck.ck-editor__top .ck-sticky-panel .ck-toolbar{border-bottom-width:0}.ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content_sticky .ck-toolbar{border-bottom-width:1px;border-radius:0}.ck-rounded-corners .ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content_sticky .ck-toolbar,.ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content_sticky .ck-toolbar.ck-rounded-corners{border-radius:var(--ck-border-radius);border-radius:0}.ck.ck-editor__main>.ck-editor__editable{background:var(--ck-color-base-background);border-radius:0}.ck-rounded-corners .ck.ck-editor__main>.ck-editor__editable,.ck.ck-editor__main>.ck-editor__editable.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0;border-top-right-radius:0}.ck.ck-editor__main>.ck-editor__editable:not(.ck-focused){border-color:var(--ck-color-base-border)}"},function(t,e,i){var n=i(1),o=i(45);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck-content blockquote{overflow:hidden;padding-right:1.5em;padding-left:1.5em;margin-left:0;margin-right:0;font-style:italic;border-left:5px solid #ccc}.ck-content[dir=rtl] blockquote{border-left:0;border-right:5px solid #ccc}"},function(t,e,i){var n=i(1),o=i(47);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck .ck-link_selected{background:var(--ck-color-link-selected-background)}"},function(t,e,i){var n=i(1),o=i(49);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=":root{--ck-color-resizer:var(--ck-color-focus-border);--ck-resizer-size:10px;--ck-resizer-border-width:1px;--ck-resizer-border-radius:2px;--ck-resizer-offset:calc(var(--ck-resizer-size)/-2 - 2px);--ck-resizer-tooltip-offset:10px;--ck-color-resizer-tooltip-background:#262626;--ck-color-resizer-tooltip-text:#f2f2f2}.ck .ck-widget.ck-widget_with-selection-handle{position:relative}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{position:absolute}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon{display:block}.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected .ck-widget__selection-handle,.ck .ck-widget.ck-widget_with-selection-handle:hover .ck-widget__selection-handle{visibility:visible}.ck .ck-size-view{background:var(--ck-color-resizer-tooltip-background);color:var(--ck-color-resizer-tooltip-text);border:1px solid var(--ck-color-resizer-tooltip-text);border-radius:var(--ck-resizer-border-radius);font-size:var(--ck-font-size-tiny);display:block;padding:var(--ck-spacing-small)}.ck .ck-size-view.ck-orientation-bottom-left,.ck .ck-size-view.ck-orientation-bottom-right,.ck .ck-size-view.ck-orientation-top-left,.ck .ck-size-view.ck-orientation-top-right{position:absolute}.ck .ck-size-view.ck-orientation-top-left{top:var(--ck-resizer-tooltip-offset);left:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-top-right{top:var(--ck-resizer-tooltip-offset);right:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-bottom-right{bottom:var(--ck-resizer-tooltip-offset);right:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-bottom-left{bottom:var(--ck-resizer-tooltip-offset);left:var(--ck-resizer-tooltip-offset)}:root{--ck-widget-outline-thickness:3px;--ck-widget-handler-icon-size:16px;--ck-widget-handler-animation-duration:200ms;--ck-widget-handler-animation-curve:ease;--ck-color-widget-blurred-border:#dedede;--ck-color-widget-hover-border:#ffc83d;--ck-color-widget-editable-focus-background:var(--ck-color-base-background);--ck-color-widget-drag-handler-icon-color:var(--ck-color-base-background)}.ck .ck-widget{outline-width:var(--ck-widget-outline-thickness);outline-style:solid;outline-color:transparent;transition:outline-color var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve)}.ck .ck-widget.ck-widget_selected,.ck .ck-widget.ck-widget_selected:hover{outline:var(--ck-widget-outline-thickness) solid var(--ck-color-focus-border)}.ck .ck-widget:hover{outline-color:var(--ck-color-widget-hover-border)}.ck .ck-editor__nested-editable{border:1px solid transparent}.ck .ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck .ck-editor__nested-editable:focus{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-inner-shadow),0 0;background-color:var(--ck-color-widget-editable-focus-background)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{padding:4px;box-sizing:border-box;background-color:transparent;opacity:0;transition:background-color var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve),visibility var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve),opacity var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);border-radius:var(--ck-border-radius) var(--ck-border-radius) 0 0;transform:translateY(-100%);left:calc(0px - var(--ck-widget-outline-thickness))}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon{width:var(--ck-widget-handler-icon-size);height:var(--ck-widget-handler-icon-size);color:var(--ck-color-widget-drag-handler-icon-color)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{opacity:0;transition:opacity .3s var(--ck-widget-handler-animation-curve)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle:hover .ck-icon .ck-icon__selected-indicator{opacity:1}.ck .ck-widget.ck-widget_with-selection-handle:hover .ck-widget__selection-handle{opacity:1;background-color:var(--ck-color-widget-hover-border)}.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected .ck-widget__selection-handle,.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected:hover .ck-widget__selection-handle{opacity:1;background-color:var(--ck-color-focus-border)}.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator,.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected:hover .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{opacity:1}.ck-editor__editable>.ck-widget.ck-widget_with-selection-handle:first-child,.ck-editor__editable blockquote>.ck-widget.ck-widget_with-selection-handle:first-child{margin-top:calc(1em + var(--ck-widget-handler-icon-size))}.ck[dir=rtl] .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{left:auto;right:calc(0px - var(--ck-widget-outline-thickness))}.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected,.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover{outline-color:var(--ck-color-widget-blurred-border)}.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected.ck-widget_with-selection-handle .ck-widget__selection-handle,.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected.ck-widget_with-selection-handle .ck-widget__selection-handle:hover,.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover.ck-widget_with-selection-handle .ck-widget__selection-handle,.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover.ck-widget_with-selection-handle .ck-widget__selection-handle:hover{background:var(--ck-color-widget-blurred-border)}.ck-editor__editable.ck-read-only .ck-widget{--ck-widget-outline-thickness:0}"},function(t,e,i){var n=i(1),o=i(51);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-labeled-input .ck-labeled-input__status{font-size:var(--ck-font-size-small);margin-top:var(--ck-spacing-small);white-space:normal}.ck.ck-labeled-input .ck-labeled-input__status_error{color:var(--ck-color-base-error)}"},function(t,e,i){var n=i(1),o=i(53);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=":root{--ck-input-text-width:18em}.ck.ck-input-text{border-radius:0}.ck-rounded-corners .ck.ck-input-text,.ck.ck-input-text.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-input-text{box-shadow:var(--ck-inner-shadow),0 0;background:var(--ck-color-input-background);border:1px solid var(--ck-color-input-border);padding:var(--ck-spacing-extra-tiny) var(--ck-spacing-medium);min-width:var(--ck-input-text-width);min-height:var(--ck-ui-component-min-height);transition:box-shadow .2s ease-in-out,border .2s ease-in-out}.ck.ck-input-text:focus{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow),var(--ck-inner-shadow)}.ck.ck-input-text[readonly]{border:1px solid var(--ck-color-input-disabled-border);background:var(--ck-color-input-disabled-background);color:var(--ck-color-input-disabled-text)}.ck.ck-input-text[readonly]:focus{box-shadow:var(--ck-focus-disabled-outer-shadow),var(--ck-inner-shadow)}.ck.ck-input-text.ck-error{border-color:var(--ck-color-input-error-border);animation:ck-text-input-shake .3s ease both}.ck.ck-input-text.ck-error:focus{box-shadow:var(--ck-focus-error-outer-shadow),var(--ck-inner-shadow)}@keyframes ck-text-input-shake{20%{transform:translateX(-2px)}40%{transform:translateX(2px)}60%{transform:translateX(-1px)}80%{transform:translateX(1px)}}"},function(t,e,i){var n=i(1),o=i(55);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-text-alternative-form{display:flex;flex-direction:row;flex-wrap:nowrap}.ck.ck-text-alternative-form .ck-labeled-input{display:inline-block}.ck.ck-text-alternative-form .ck-label{display:none}@media screen and (max-width:600px){.ck.ck-text-alternative-form{flex-wrap:wrap}.ck.ck-text-alternative-form .ck-labeled-input{flex-basis:100%}.ck.ck-text-alternative-form .ck-button{flex-basis:50%}}.ck.ck-text-alternative-form{padding:var(--ck-spacing-standard)}.ck.ck-text-alternative-form:focus{outline:none}[dir=ltr] .ck.ck-text-alternative-form>:not(:first-child),[dir=rtl] .ck.ck-text-alternative-form>:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-text-alternative-form{padding:0;width:calc(0.8*var(--ck-input-text-width))}.ck.ck-text-alternative-form .ck-labeled-input{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) 0}.ck.ck-text-alternative-form .ck-labeled-input .ck-input-text{min-width:0;width:100%}.ck.ck-text-alternative-form .ck-button{padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-standard);border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border)}[dir=ltr] .ck.ck-text-alternative-form .ck-button{margin-left:0}[dir=ltr] .ck.ck-text-alternative-form .ck-button:first-of-type{border-right:1px solid var(--ck-color-base-border)}[dir=rtl] .ck.ck-text-alternative-form .ck-button{margin-left:0}[dir=rtl] .ck.ck-text-alternative-form .ck-button:last-of-type{border-right:1px solid var(--ck-color-base-border)}}"},function(t,e,i){var n=i(1),o=i(57);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=':root{--ck-balloon-panel-arrow-z-index:calc(var(--ck-z-default) - 3)}.ck.ck-balloon-panel{display:none;position:absolute;z-index:var(--ck-z-modal)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after,.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{content:"";position:absolute}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel[class*=arrow_n]:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel[class*=arrow_n]:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel[class*=arrow_s]:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel[class*=arrow_s]:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel.ck-balloon-panel_visible{display:block}:root{--ck-balloon-arrow-offset:2px;--ck-balloon-arrow-height:10px;--ck-balloon-arrow-half-width:8px}.ck.ck-balloon-panel{border-radius:0}.ck-rounded-corners .ck.ck-balloon-panel,.ck.ck-balloon-panel.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-balloon-panel{box-shadow:var(--ck-drop-shadow),0 0;min-height:15px;background:var(--ck-color-panel-background);border:1px solid var(--ck-color-panel-border)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after,.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{width:0;height:0;border-style:solid}.ck.ck-balloon-panel[class*=arrow_n]:after,.ck.ck-balloon-panel[class*=arrow_n]:before{border-left-width:var(--ck-balloon-arrow-half-width);border-bottom-width:var(--ck-balloon-arrow-height);border-right-width:var(--ck-balloon-arrow-half-width);border-top-width:0}.ck.ck-balloon-panel[class*=arrow_n]:before{border-bottom-color:var(--ck-color-panel-border)}.ck.ck-balloon-panel[class*=arrow_n]:after,.ck.ck-balloon-panel[class*=arrow_n]:before{border-left-color:transparent;border-right-color:transparent;border-top-color:transparent}.ck.ck-balloon-panel[class*=arrow_n]:after{border-bottom-color:var(--ck-color-panel-background);margin-top:var(--ck-balloon-arrow-offset)}.ck.ck-balloon-panel[class*=arrow_s]:after,.ck.ck-balloon-panel[class*=arrow_s]:before{border-left-width:var(--ck-balloon-arrow-half-width);border-bottom-width:0;border-right-width:var(--ck-balloon-arrow-half-width);border-top-width:var(--ck-balloon-arrow-height)}.ck.ck-balloon-panel[class*=arrow_s]:before{border-top-color:var(--ck-color-panel-border)}.ck.ck-balloon-panel[class*=arrow_s]:after,.ck.ck-balloon-panel[class*=arrow_s]:before{border-left-color:transparent;border-bottom-color:transparent;border-right-color:transparent}.ck.ck-balloon-panel[class*=arrow_s]:after{border-top-color:var(--ck-color-panel-background);margin-bottom:var(--ck-balloon-arrow-offset)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_n:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_n:before{left:50%;margin-left:calc(-1*var(--ck-balloon-arrow-half-width));top:calc(-1*var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_nw:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_nw:before{left:calc(2*var(--ck-balloon-arrow-half-width));top:calc(-1*var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_ne:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_ne:before{right:calc(2*var(--ck-balloon-arrow-half-width));top:calc(-1*var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_s:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_s:before{left:50%;margin-left:calc(-1*var(--ck-balloon-arrow-half-width));bottom:calc(-1*var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_sw:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_sw:before{left:calc(2*var(--ck-balloon-arrow-half-width));bottom:calc(-1*var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_se:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_se:before{right:calc(2*var(--ck-balloon-arrow-half-width));bottom:calc(-1*var(--ck-balloon-arrow-height))}'},function(t,e,i){var n=i(1),o=i(59);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck .ck-balloon-rotator__navigation{display:flex;align-items:center;justify-content:center}.ck .ck-balloon-rotator__content .ck-toolbar{justify-content:center}.ck .ck-balloon-rotator__navigation{background:var(--ck-color-toolbar-background);border-bottom:1px solid var(--ck-color-toolbar-border);padding:0 var(--ck-spacing-small)}.ck .ck-balloon-rotator__navigation>*{margin-right:var(--ck-spacing-small);margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small)}.ck .ck-balloon-rotator__navigation .ck-balloon-rotator__counter{margin-right:var(--ck-spacing-standard);margin-left:var(--ck-spacing-small)}.ck .ck-balloon-rotator__content .ck.ck-annotation-wrapper{box-shadow:none}"},function(t,e,i){var n=i(1),o=i(61);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck .ck-fake-panel{position:absolute;z-index:calc(var(--ck-z-modal) - 1)}.ck .ck-fake-panel div{position:absolute}.ck .ck-fake-panel div:first-child{z-index:2}.ck .ck-fake-panel div:nth-child(2){z-index:1}:root{--ck-balloon-fake-panel-offset-horizontal:6px;--ck-balloon-fake-panel-offset-vertical:6px}.ck .ck-fake-panel div{box-shadow:var(--ck-drop-shadow),0 0;min-height:15px;background:var(--ck-color-panel-background);border:1px solid var(--ck-color-panel-border);border-radius:var(--ck-border-radius);width:100%;height:100%}.ck .ck-fake-panel div:first-child{margin-left:var(--ck-balloon-fake-panel-offset-horizontal);margin-top:var(--ck-balloon-fake-panel-offset-vertical)}.ck .ck-fake-panel div:nth-child(2){margin-left:calc(var(--ck-balloon-fake-panel-offset-horizontal)*2);margin-top:calc(var(--ck-balloon-fake-panel-offset-vertical)*2)}.ck .ck-fake-panel div:nth-child(3){margin-left:calc(var(--ck-balloon-fake-panel-offset-horizontal)*3);margin-top:calc(var(--ck-balloon-fake-panel-offset-vertical)*3)}.ck .ck-balloon-panel_arrow_s+.ck-fake-panel,.ck .ck-balloon-panel_arrow_se+.ck-fake-panel,.ck .ck-balloon-panel_arrow_sw+.ck-fake-panel{--ck-balloon-fake-panel-offset-vertical:-6px}"},function(t,e,i){var n=i(1),o=i(63);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck-content .image{display:table;clear:both;text-align:center;margin:1em auto}.ck-content .image>img{display:block;margin:0 auto;max-width:100%;min-width:50px}"},function(t,e,i){var n=i(1),o=i(65);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-editor__editable .image{position:relative}.ck.ck-editor__editable .image .ck-progress-bar{position:absolute;top:0;left:0}.ck.ck-editor__editable .image.ck-appear{animation:fadeIn .7s}.ck.ck-editor__editable .image .ck-progress-bar{height:2px;width:0;background:var(--ck-color-upload-bar-background);transition:width .1s}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}"},function(t,e,i){var n=i(1),o=i(67);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports='.ck-image-upload-complete-icon{display:block;position:absolute;top:10px;right:10px;border-radius:50%}.ck-image-upload-complete-icon:after{content:"";position:absolute}:root{--ck-color-image-upload-icon:#fff;--ck-color-image-upload-icon-background:#008a00;--ck-image-upload-icon-size:20px;--ck-image-upload-icon-width:2px}.ck-image-upload-complete-icon{width:var(--ck-image-upload-icon-size);height:var(--ck-image-upload-icon-size);opacity:0;background:var(--ck-color-image-upload-icon-background);animation-name:ck-upload-complete-icon-show,ck-upload-complete-icon-hide;animation-fill-mode:forwards,forwards;animation-duration:.5s,.5s;font-size:var(--ck-image-upload-icon-size);animation-delay:0ms,3s}.ck-image-upload-complete-icon:after{left:25%;top:50%;opacity:0;height:0;width:0;transform:scaleX(-1) rotate(135deg);transform-origin:left top;border-top:var(--ck-image-upload-icon-width) solid var(--ck-color-image-upload-icon);border-right:var(--ck-image-upload-icon-width) solid var(--ck-color-image-upload-icon);animation-name:ck-upload-complete-icon-check;animation-duration:.5s;animation-delay:.5s;animation-fill-mode:forwards;box-sizing:border-box}@keyframes ck-upload-complete-icon-show{0%{opacity:0}to{opacity:1}}@keyframes ck-upload-complete-icon-hide{0%{opacity:1}to{opacity:0}}@keyframes ck-upload-complete-icon-check{0%{opacity:1;width:0;height:0}33%{width:.3em;height:0}to{opacity:1;width:.3em;height:.45em}}'},function(t,e,i){var n=i(1),o=i(69);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports='.ck .ck-upload-placeholder-loader{position:absolute;display:flex;align-items:center;justify-content:center;top:0;left:0}.ck .ck-upload-placeholder-loader:before{content:"";position:relative}:root{--ck-color-upload-placeholder-loader:#b3b3b3;--ck-upload-placeholder-loader-size:32px}.ck .ck-image-upload-placeholder{width:100%;margin:0}.ck .ck-upload-placeholder-loader{width:100%;height:100%}.ck .ck-upload-placeholder-loader:before{width:var(--ck-upload-placeholder-loader-size);height:var(--ck-upload-placeholder-loader-size);border-radius:50%;border-top:3px solid var(--ck-color-upload-placeholder-loader);border-right:2px solid transparent;animation:ck-upload-placeholder-loader 1s linear infinite}@keyframes ck-upload-placeholder-loader{to{transform:rotate(1turn)}}'},function(t,e){t.exports=".ck.ck-heading_heading1{font-size:20px}.ck.ck-heading_heading2{font-size:17px}.ck.ck-heading_heading3{font-size:14px}.ck[class*=ck-heading_heading]{font-weight:700}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__button .ck-button__label{width:8em}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__panel .ck-list__item{min-width:18em}"},function(t,e,i){var n=i(1),o=i(72);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck-content .image>figcaption{display:table-caption;caption-side:bottom;word-break:break-word;color:#333;background-color:#f7f7f7;padding:.6em;font-size:.75em;outline-offset:-1px}"},function(t,e,i){var n=i(1),o=i(74);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=":root{--ck-image-style-spacing:1.5em}.ck-content .image-style-align-center,.ck-content .image-style-align-left,.ck-content .image-style-align-right,.ck-content .image-style-side{max-width:50%}.ck-content .image-style-side{float:right;margin-left:var(--ck-image-style-spacing)}.ck-content .image-style-align-left{float:left;margin-right:var(--ck-image-style-spacing)}.ck-content .image-style-align-center{margin-left:auto;margin-right:auto}.ck-content .image-style-align-right{float:right;margin-left:var(--ck-image-style-spacing)}"},function(t,e,i){var n=i(1),o=i(76);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-link-form{display:flex}.ck.ck-link-form .ck-label{display:none}@media screen and (max-width:600px){.ck.ck-link-form{flex-wrap:wrap}.ck.ck-link-form .ck-labeled-input{flex-basis:100%}.ck.ck-link-form .ck-button{flex-basis:50%}}.ck.ck-link-form_layout-vertical{display:block}.ck.ck-link-form{padding:var(--ck-spacing-standard)}.ck.ck-link-form:focus{outline:none}[dir=ltr] .ck.ck-link-form>:not(:first-child),[dir=rtl] .ck.ck-link-form>:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-link-form{padding:0;width:calc(0.8*var(--ck-input-text-width))}.ck.ck-link-form .ck-labeled-input{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) 0}.ck.ck-link-form .ck-labeled-input .ck-input-text{min-width:0;width:100%}.ck.ck-link-form .ck-button{padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-standard);border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border)}[dir=ltr] .ck.ck-link-form .ck-button{margin-left:0}[dir=ltr] .ck.ck-link-form .ck-button:first-of-type{border-right:1px solid var(--ck-color-base-border)}[dir=rtl] .ck.ck-link-form .ck-button{margin-left:0}[dir=rtl] .ck.ck-link-form .ck-button:last-of-type{border-right:1px solid var(--ck-color-base-border)}}.ck.ck-link-form_layout-vertical{padding:0;min-width:var(--ck-input-text-width)}.ck.ck-link-form_layout-vertical .ck-labeled-input{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) var(--ck-spacing-small)}.ck.ck-link-form_layout-vertical .ck-labeled-input .ck-input-text{min-width:0;width:100%}.ck.ck-link-form_layout-vertical .ck-button{padding:var(--ck-spacing-standard);margin:0;border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border);width:50%}[dir=ltr] .ck.ck-link-form_layout-vertical .ck-button{margin-left:0}[dir=ltr] .ck.ck-link-form_layout-vertical .ck-button:first-of-type{border-right:1px solid var(--ck-color-base-border)}[dir=rtl] .ck.ck-link-form_layout-vertical .ck-button{margin-left:0}[dir=rtl] .ck.ck-link-form_layout-vertical .ck-button:last-of-type{border-right:1px solid var(--ck-color-base-border)}.ck.ck-link-form_layout-vertical .ck.ck-list{margin-left:0}.ck.ck-link-form_layout-vertical .ck.ck-list .ck-button.ck-switchbutton{border:0;width:100%}.ck.ck-link-form_layout-vertical .ck.ck-list .ck-button.ck-switchbutton:hover{background:none}"},function(t,e,i){var n=i(1),o=i(78);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-link-actions{display:flex;flex-direction:row;flex-wrap:nowrap}.ck.ck-link-actions .ck-link-actions__preview{display:inline-block}.ck.ck-link-actions .ck-link-actions__preview .ck-button__label{overflow:hidden}@media screen and (max-width:600px){.ck.ck-link-actions{flex-wrap:wrap}.ck.ck-link-actions .ck-link-actions__preview{flex-basis:100%}.ck.ck-link-actions .ck-button:not(.ck-link-actions__preview){flex-basis:50%}}.ck.ck-link-actions{padding:var(--ck-spacing-standard)}.ck.ck-link-actions .ck-button.ck-link-actions__preview{padding-left:0;padding-right:0}.ck.ck-link-actions .ck-button.ck-link-actions__preview .ck-button__label{padding:0 var(--ck-spacing-medium);color:var(--ck-color-link-default);text-overflow:ellipsis;cursor:pointer;max-width:var(--ck-input-text-width);min-width:3em;text-align:center}.ck.ck-link-actions .ck-button.ck-link-actions__preview .ck-button__label:hover{text-decoration:underline}.ck.ck-link-actions .ck-button.ck-link-actions__preview,.ck.ck-link-actions .ck-button.ck-link-actions__preview:active,.ck.ck-link-actions .ck-button.ck-link-actions__preview:focus,.ck.ck-link-actions .ck-button.ck-link-actions__preview:hover{background:none}.ck.ck-link-actions .ck-button.ck-link-actions__preview:active{box-shadow:none}.ck.ck-link-actions .ck-button.ck-link-actions__preview:focus .ck-button__label{text-decoration:underline}.ck.ck-link-actions:focus{outline:none}[dir=ltr] .ck.ck-link-actions .ck-button:not(:first-child),[dir=rtl] .ck.ck-link-actions .ck-button:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-link-actions{padding:0;width:calc(0.8*var(--ck-input-text-width))}.ck.ck-link-actions .ck-button.ck-link-actions__preview{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) 0}.ck.ck-link-actions .ck-button.ck-link-actions__preview .ck-button__label{min-width:0;max-width:100%}.ck.ck-link-actions .ck-button:not(.ck-link-actions__preview){padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-standard);border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border)}[dir=ltr] .ck.ck-link-actions .ck-button:not(.ck-link-actions__preview){margin-left:0}[dir=ltr] .ck.ck-link-actions .ck-button:not(.ck-link-actions__preview):first-of-type{border-right:1px solid var(--ck-color-base-border)}[dir=rtl] .ck.ck-link-actions .ck-button:not(.ck-link-actions__preview){margin-left:0}[dir=rtl] .ck.ck-link-actions .ck-button:not(.ck-link-actions__preview):last-of-type{border-right:1px solid var(--ck-color-base-border)}}"},function(t,e,i){var n=i(1),o=i(80);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports='.ck-media__wrapper .ck-media__placeholder{display:flex;flex-direction:column;align-items:center}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url .ck-tooltip{display:block}@media (hover:none){.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url .ck-tooltip{display:none}}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url{max-width:100%;position:relative}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url:hover .ck-tooltip{visibility:visible;opacity:1}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url .ck-media__placeholder__url__text{overflow:hidden;display:block}.ck-media__wrapper[data-oembed-url*="facebook.com"] .ck-media__placeholder__icon *,.ck-media__wrapper[data-oembed-url*="google.com/maps"] .ck-media__placeholder__icon *,.ck-media__wrapper[data-oembed-url*="instagram.com"] .ck-media__placeholder__icon *,.ck-media__wrapper[data-oembed-url*="twitter.com"] .ck-media__placeholder__icon *{display:none}.ck-editor__editable:not(.ck-read-only) .ck-media__wrapper>:not(.ck-media__placeholder),.ck-editor__editable:not(.ck-read-only) .ck-widget:not(.ck-widget_selected) .ck-media__placeholder{pointer-events:none}:root{--ck-media-embed-placeholder-icon-size:3em;--ck-color-media-embed-placeholder-url-text:#757575;--ck-color-media-embed-placeholder-url-text-hover:var(--ck-color-base-text)}.ck-media__wrapper{margin:0 auto}.ck-media__wrapper .ck-media__placeholder{padding:calc(3*var(--ck-spacing-standard));background:var(--ck-color-base-foreground)}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__icon{min-width:var(--ck-media-embed-placeholder-icon-size);height:var(--ck-media-embed-placeholder-icon-size);margin-bottom:var(--ck-spacing-large);background-position:50%;background-size:cover}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__icon .ck-icon{width:100%;height:100%}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url__text{color:var(--ck-color-media-embed-placeholder-url-text);white-space:nowrap;text-align:center;font-style:italic;text-overflow:ellipsis}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url__text:hover{color:var(--ck-color-media-embed-placeholder-url-text-hover);cursor:pointer;text-decoration:underline}.ck-media__wrapper[data-oembed-url*="open.spotify.com"]{max-width:300px;max-height:380px}.ck-media__wrapper[data-oembed-url*="google.com/maps"] .ck-media__placeholder__icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNTAuMzc4IiBoZWlnaHQ9IjI1NC4xNjciIHZpZXdCb3g9IjAgMCA2Ni4yNDYgNjcuMjQ4Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTcyLjUzMSAtMjE4LjQ1NSkgc2NhbGUoLjk4MDEyKSI+PHJlY3Qgcnk9IjUuMjM4IiByeD0iNS4yMzgiIHk9IjIzMS4zOTkiIHg9IjE3Ni4wMzEiIGhlaWdodD0iNjAuMDk5IiB3aWR0aD0iNjAuMDk5IiBmaWxsPSIjMzRhNjY4IiBwYWludC1vcmRlcj0ibWFya2VycyBzdHJva2UgZmlsbCIvPjxwYXRoIGQ9Ik0yMDYuNDc3IDI2MC45bC0yOC45ODcgMjguOTg3YTUuMjE4IDUuMjE4IDAgMDAzLjc4IDEuNjFoNDkuNjIxYzEuNjk0IDAgMy4xOS0uNzk4IDQuMTQ2LTIuMDM3eiIgZmlsbD0iIzVjODhjNSIvPjxwYXRoIGQ9Ik0yMjYuNzQyIDIyMi45ODhjLTkuMjY2IDAtMTYuNzc3IDcuMTctMTYuNzc3IDE2LjAxNC4wMDcgMi43NjIuNjYzIDUuNDc0IDIuMDkzIDcuODc1LjQzLjcwMy44MyAxLjQwOCAxLjE5IDIuMTA3LjMzMy41MDIuNjUgMS4wMDUuOTUgMS41MDguMzQzLjQ3Ny42NzMuOTU3Ljk4OCAxLjQ0IDEuMzEgMS43NjkgMi41IDMuNTAyIDMuNjM3IDUuMTY4Ljc5MyAxLjI3NSAxLjY4MyAyLjY0IDIuNDY2IDMuOTkgMi4zNjMgNC4wOTQgNC4wMDcgOC4wOTIgNC42IDEzLjkxNHYuMDEyYy4xODIuNDEyLjUxNi42NjYuODc5LjY2Ny40MDMtLjAwMS43NjgtLjMxNC45My0uNzk5LjYwMy01Ljc1NiAyLjIzOC05LjcyOSA0LjU4NS0xMy43OTQuNzgyLTEuMzUgMS42NzMtMi43MTUgMi40NjUtMy45OSAxLjEzNy0xLjY2NiAyLjMyOC0zLjQgMy42MzgtNS4xNjkuMzE1LS40ODIuNjQ1LS45NjIuOTg4LTEuNDM5LjMtLjUwMy42MTctMS4wMDYuOTUtMS41MDguMzU5LS43Ljc2LTEuNDA0IDEuMTktMi4xMDcgMS40MjYtMi40MDIgMi01LjExNCAyLjAwNC03Ljg3NSAwLTguODQ0LTcuNTExLTE2LjAxNC0xNi43NzYtMTYuMDE0eiIgZmlsbD0iI2RkNGIzZSIgcGFpbnQtb3JkZXI9Im1hcmtlcnMgc3Ryb2tlIGZpbGwiLz48ZWxsaXBzZSByeT0iNS41NjQiIHJ4PSI1LjgyOCIgY3k9IjIzOS4wMDIiIGN4PSIyMjYuNzQyIiBmaWxsPSIjODAyZDI3IiBwYWludC1vcmRlcj0ibWFya2VycyBzdHJva2UgZmlsbCIvPjxwYXRoIGQ9Ik0xOTAuMzAxIDIzNy4yODNjLTQuNjcgMC04LjQ1NyAzLjg1My04LjQ1NyA4LjYwNnMzLjc4NiA4LjYwNyA4LjQ1NyA4LjYwN2MzLjA0MyAwIDQuODA2LS45NTggNi4zMzctMi41MTYgMS41My0xLjU1NyAyLjA4Ny0zLjkxMyAyLjA4Ny02LjI5IDAtLjM2Mi0uMDIzLS43MjItLjA2NC0xLjA3OWgtOC4yNTd2My4wNDNoNC44NWMtLjE5Ny43NTktLjUzMSAxLjQ1LTEuMDU4IDEuOTg2LS45NDIuOTU4LTIuMDI4IDEuNTQ4LTMuOTAxIDEuNTQ4LTIuODc2IDAtNS4yMDgtMi4zNzItNS4yMDgtNS4yOTkgMC0yLjkyNiAyLjMzMi01LjI5OSA1LjIwOC01LjI5OSAxLjM5OSAwIDIuNjE4LjQwNyAzLjU4NCAxLjI5M2wyLjM4MS0yLjM4YzAtLjAwMi0uMDAzLS4wMDQtLjAwNC0uMDA1LTEuNTg4LTEuNTI0LTMuNjItMi4yMTUtNS45NTUtMi4yMTV6bTQuNDMgNS42NmwuMDAzLjAwNnYtLjAwM3oiIGZpbGw9IiNmZmYiIHBhaW50LW9yZGVyPSJtYXJrZXJzIHN0cm9rZSBmaWxsIi8+PHBhdGggZD0iTTIxNS4xODQgMjUxLjkyOWwtNy45OCA3Ljk3OSAyOC40NzcgMjguNDc1YTUuMjMzIDUuMjMzIDAgMDAuNDQ5LTIuMTIzdi0zMS4xNjVjLS40NjkuNjc1LS45MzQgMS4zNDktMS4zODIgMi4wMDUtLjc5MiAxLjI3NS0xLjY4MiAyLjY0LTIuNDY1IDMuOTktMi4zNDcgNC4wNjUtMy45ODIgOC4wMzgtNC41ODUgMTMuNzk0LS4xNjIuNDg1LS41MjcuNzk4LS45My43OTktLjM2My0uMDAxLS42OTctLjI1NS0uODc5LS42Njd2LS4wMTJjLS41OTMtNS44MjItMi4yMzctOS44Mi00LjYtMTMuOTE0LS43ODMtMS4zNS0xLjY3My0yLjcxNS0yLjQ2Ni0zLjk5LTEuMTM3LTEuNjY2LTIuMzI3LTMuNC0zLjYzNy01LjE2OWwtLjAwMi0uMDAzeiIgZmlsbD0iI2MzYzNjMyIvPjxwYXRoIGQ9Ik0yMTIuOTgzIDI0OC40OTVsLTM2Ljk1MiAzNi45NTN2LjgxMmE1LjIyNyA1LjIyNyAwIDAwNS4yMzggNS4yMzhoMS4wMTVsMzUuNjY2LTM1LjY2NmExMzYuMjc1IDEzNi4yNzUgMCAwMC0yLjc2NC0zLjkgMzcuNTc1IDM3LjU3NSAwIDAwLS45ODktMS40NCAzNS4xMjcgMzUuMTI3IDAgMDAtLjk1LTEuNTA4Yy0uMDgzLS4xNjItLjE3Ni0uMzI2LS4yNjQtLjQ4OXoiIGZpbGw9IiNmZGRjNGYiIHBhaW50LW9yZGVyPSJtYXJrZXJzIHN0cm9rZSBmaWxsIi8+PHBhdGggZD0iTTIxMS45OTggMjYxLjA4M2wtNi4xNTIgNi4xNTEgMjQuMjY0IDI0LjI2NGguNzgxYTUuMjI3IDUuMjI3IDAgMDA1LjIzOS01LjIzOHYtMS4wNDV6IiBmaWxsPSIjZmZmIiBwYWludC1vcmRlcj0ibWFya2VycyBzdHJva2UgZmlsbCIvPjwvZz48L3N2Zz4=)}.ck-media__wrapper[data-oembed-url*="facebook.com"] .ck-media__placeholder{background:#4268b3}.ck-media__wrapper[data-oembed-url*="facebook.com"] .ck-media__placeholder .ck-media__placeholder__icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAyNCIgaGVpZ2h0PSIxMDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik05NjcuNDg0IDBINTYuNTE3QzI1LjMwNCAwIDAgMjUuMzA0IDAgNTYuNTE3djkxMC45NjZDMCA5OTguNjk0IDI1LjI5NyAxMDI0IDU2LjUyMiAxMDI0SDU0N1Y2MjhINDE0VjQ3M2gxMzNWMzU5LjAyOWMwLTEzMi4yNjIgODAuNzczLTIwNC4yODIgMTk4Ljc1Ni0yMDQuMjgyIDU2LjUxMyAwIDEwNS4wODYgNC4yMDggMTE5LjI0NCA2LjA4OVYyOTlsLTgxLjYxNi4wMzdjLTYzLjk5MyAwLTc2LjM4NCAzMC40OTItNzYuMzg0IDc1LjIzNlY0NzNoMTUzLjQ4N2wtMTkuOTg2IDE1NUg3MDd2Mzk2aDI2MC40ODRjMzEuMjEzIDAgNTYuNTE2LTI1LjMwMyA1Ni41MTYtNTYuNTE2VjU2LjUxNUMxMDI0IDI1LjMwMyA5OTguNjk3IDAgOTY3LjQ4NCAwIiBmaWxsPSIjRkZGRkZFIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.ck-media__wrapper[data-oembed-url*="facebook.com"] .ck-media__placeholder .ck-media__placeholder__url__text{color:#cdf}.ck-media__wrapper[data-oembed-url*="facebook.com"] .ck-media__placeholder .ck-media__placeholder__url__text:hover{color:#fff}.ck-media__wrapper[data-oembed-url*="instagram.com"] .ck-media__placeholder{background:linear-gradient(-135deg,#1400c8,#b900b4,#f50000)}.ck-media__wrapper[data-oembed-url*="instagram.com"] .ck-media__placeholder .ck-media__placeholder__icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTA0IiBoZWlnaHQ9IjUwNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGRlZnM+PHBhdGggaWQ9ImEiIGQ9Ik0wIC4xNTloNTAzLjg0MVY1MDMuOTRIMHoiLz48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48bWFzayBpZD0iYiIgZmlsbD0iI2ZmZiI+PHVzZSB4bGluazpocmVmPSIjYSIvPjwvbWFzaz48cGF0aCBkPSJNMjUxLjkyMS4xNTljLTY4LjQxOCAwLTc2Ljk5Ny4yOS0xMDMuODY3IDEuNTE2LTI2LjgxNCAxLjIyMy00NS4xMjcgNS40ODItNjEuMTUxIDExLjcxLTE2LjU2NiA2LjQzNy0zMC42MTUgMTUuMDUxLTQ0LjYyMSAyOS4wNTYtMTQuMDA1IDE0LjAwNi0yMi42MTkgMjguMDU1LTI5LjA1NiA0NC42MjEtNi4yMjggMTYuMDI0LTEwLjQ4NyAzNC4zMzctMTEuNzEgNjEuMTUxQy4yOSAxNzUuMDgzIDAgMTgzLjY2MiAwIDI1Mi4wOGMwIDY4LjQxNy4yOSA3Ni45OTYgMS41MTYgMTAzLjg2NiAxLjIyMyAyNi44MTQgNS40ODIgNDUuMTI3IDExLjcxIDYxLjE1MSA2LjQzNyAxNi41NjYgMTUuMDUxIDMwLjYxNSAyOS4wNTYgNDQuNjIxIDE0LjAwNiAxNC4wMDUgMjguMDU1IDIyLjYxOSA0NC42MjEgMjkuMDU3IDE2LjAyNCA2LjIyNyAzNC4zMzcgMTAuNDg2IDYxLjE1MSAxMS43MDkgMjYuODcgMS4yMjYgMzUuNDQ5IDEuNTE2IDEwMy44NjcgMS41MTYgNjguNDE3IDAgNzYuOTk2LS4yOSAxMDMuODY2LTEuNTE2IDI2LjgxNC0xLjIyMyA0NS4xMjctNS40ODIgNjEuMTUxLTExLjcwOSAxNi41NjYtNi40MzggMzAuNjE1LTE1LjA1MiA0NC42MjEtMjkuMDU3IDE0LjAwNS0xNC4wMDYgMjIuNjE5LTI4LjA1NSAyOS4wNTctNDQuNjIxIDYuMjI3LTE2LjAyNCAxMC40ODYtMzQuMzM3IDExLjcwOS02MS4xNTEgMS4yMjYtMjYuODcgMS41MTYtMzUuNDQ5IDEuNTE2LTEwMy44NjYgMC02OC40MTgtLjI5LTc2Ljk5Ny0xLjUxNi0xMDMuODY3LTEuMjIzLTI2LjgxNC01LjQ4Mi00NS4xMjctMTEuNzA5LTYxLjE1MS02LjQzOC0xNi41NjYtMTUuMDUyLTMwLjYxNS0yOS4wNTctNDQuNjIxLTE0LjAwNi0xNC4wMDUtMjguMDU1LTIyLjYxOS00NC42MjEtMjkuMDU2LTE2LjAyNC02LjIyOC0zNC4zMzctMTAuNDg3LTYxLjE1MS0xMS43MUMzMjguOTE3LjQ0OSAzMjAuMzM4LjE1OSAyNTEuOTIxLjE1OXptMCA0NS4zOTFjNjcuMjY1IDAgNzUuMjMzLjI1NyAxMDEuNzk3IDEuNDY5IDI0LjU2MiAxLjEyIDM3LjkwMSA1LjIyNCA0Ni43NzggOC42NzQgMTEuNzU5IDQuNTcgMjAuMTUxIDEwLjAyOSAyOC45NjYgMTguODQ1IDguODE2IDguODE1IDE0LjI3NSAxNy4yMDcgMTguODQ1IDI4Ljk2NiAzLjQ1IDguODc3IDcuNTU0IDIyLjIxNiA4LjY3NCA0Ni43NzggMS4yMTIgMjYuNTY0IDEuNDY5IDM0LjUzMiAxLjQ2OSAxMDEuNzk4IDAgNjcuMjY1LS4yNTcgNzUuMjMzLTEuNDY5IDEwMS43OTctMS4xMiAyNC41NjItNS4yMjQgMzcuOTAxLTguNjc0IDQ2Ljc3OC00LjU3IDExLjc1OS0xMC4wMjkgMjAuMTUxLTE4Ljg0NSAyOC45NjYtOC44MTUgOC44MTYtMTcuMjA3IDE0LjI3NS0yOC45NjYgMTguODQ1LTguODc3IDMuNDUtMjIuMjE2IDcuNTU0LTQ2Ljc3OCA4LjY3NC0yNi41NiAxLjIxMi0zNC41MjcgMS40NjktMTAxLjc5NyAxLjQ2OS02Ny4yNzEgMC03NS4yMzctLjI1Ny0xMDEuNzk4LTEuNDY5LTI0LjU2Mi0xLjEyLTM3LjkwMS01LjIyNC00Ni43NzgtOC42NzQtMTEuNzU5LTQuNTctMjAuMTUxLTEwLjAyOS0yOC45NjYtMTguODQ1LTguODE1LTguODE1LTE0LjI3NS0xNy4yMDctMTguODQ1LTI4Ljk2Ni0zLjQ1LTguODc3LTcuNTU0LTIyLjIxNi04LjY3NC00Ni43NzgtMS4yMTItMjYuNTY0LTEuNDY5LTM0LjUzMi0xLjQ2OS0xMDEuNzk3IDAtNjcuMjY2LjI1Ny03NS4yMzQgMS40NjktMTAxLjc5OCAxLjEyLTI0LjU2MiA1LjIyNC0zNy45MDEgOC42NzQtNDYuNzc4IDQuNTctMTEuNzU5IDEwLjAyOS0yMC4xNTEgMTguODQ1LTI4Ljk2NiA4LjgxNS04LjgxNiAxNy4yMDctMTQuMjc1IDI4Ljk2Ni0xOC44NDUgOC44NzctMy40NSAyMi4yMTYtNy41NTQgNDYuNzc4LTguNjc0IDI2LjU2NC0xLjIxMiAzNC41MzItMS40NjkgMTAxLjc5OC0xLjQ2OXoiIGZpbGw9IiNGRkYiIG1hc2s9InVybCgjYikiLz48cGF0aCBkPSJNMjUxLjkyMSAzMzYuMDUzYy00Ni4zNzggMC04My45NzQtMzcuNTk2LTgzLjk3NC04My45NzMgMC00Ni4zNzggMzcuNTk2LTgzLjk3NCA4My45NzQtODMuOTc0IDQ2LjM3NyAwIDgzLjk3MyAzNy41OTYgODMuOTczIDgzLjk3NCAwIDQ2LjM3Ny0zNy41OTYgODMuOTczLTgzLjk3MyA4My45NzN6bTAtMjEzLjMzOGMtNzEuNDQ3IDAtMTI5LjM2NSA1Ny45MTgtMTI5LjM2NSAxMjkuMzY1IDAgNzEuNDQ2IDU3LjkxOCAxMjkuMzY0IDEyOS4zNjUgMTI5LjM2NCA3MS40NDYgMCAxMjkuMzY0LTU3LjkxOCAxMjkuMzY0LTEyOS4zNjQgMC03MS40NDctNTcuOTE4LTEyOS4zNjUtMTI5LjM2NC0xMjkuMzY1ek00MTYuNjI3IDExNy42MDRjMCAxNi42OTYtMTMuNTM1IDMwLjIzLTMwLjIzMSAzMC4yMy0xNi42OTUgMC0zMC4yMy0xMy41MzQtMzAuMjMtMzAuMjMgMC0xNi42OTYgMTMuNTM1LTMwLjIzMSAzMC4yMy0zMC4yMzEgMTYuNjk2IDAgMzAuMjMxIDEzLjUzNSAzMC4yMzEgMzAuMjMxIiBmaWxsPSIjRkZGIi8+PC9nPjwvc3ZnPg==)}.ck-media__wrapper[data-oembed-url*="instagram.com"] .ck-media__placeholder .ck-media__placeholder__url__text{color:#ffe0fe}.ck-media__wrapper[data-oembed-url*="instagram.com"] .ck-media__placeholder .ck-media__placeholder__url__text:hover{color:#fff}.ck-media__wrapper[data-oembed-url*="twitter.com"] .ck.ck-media__placeholder{background:linear-gradient(90deg,#71c6f4,#0d70a5)}.ck-media__wrapper[data-oembed-url*="twitter.com"] .ck.ck-media__placeholder .ck-media__placeholder__icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MDAgNDAwIj48cGF0aCBkPSJNNDAwIDIwMGMwIDExMC41LTg5LjUgMjAwLTIwMCAyMDBTMCAzMTAuNSAwIDIwMCA4OS41IDAgMjAwIDBzMjAwIDg5LjUgMjAwIDIwMHpNMTYzLjQgMzA1LjVjODguNyAwIDEzNy4yLTczLjUgMTM3LjItMTM3LjIgMC0yLjEgMC00LjItLjEtNi4yIDkuNC02LjggMTcuNi0xNS4zIDI0LjEtMjUtOC42IDMuOC0xNy45IDYuNC0yNy43IDcuNiAxMC02IDE3LjYtMTUuNCAyMS4yLTI2LjctOS4zIDUuNS0xOS42IDkuNS0zMC42IDExLjctOC44LTkuNC0yMS4zLTE1LjItMzUuMi0xNS4yLTI2LjYgMC00OC4yIDIxLjYtNDguMiA0OC4yIDAgMy44LjQgNy41IDEuMyAxMS00MC4xLTItNzUuNi0yMS4yLTk5LjQtNTAuNC00LjEgNy4xLTYuNSAxNS40LTYuNSAyNC4yIDAgMTYuNyA4LjUgMzEuNSAyMS41IDQwLjEtNy45LS4yLTE1LjMtMi40LTIxLjgtNnYuNmMwIDIzLjQgMTYuNiA0Mi44IDM4LjcgNDcuMy00IDEuMS04LjMgMS43LTEyLjcgMS43LTMuMSAwLTYuMS0uMy05LjEtLjkgNi4xIDE5LjIgMjMuOSAzMy4xIDQ1IDMzLjUtMTYuNSAxMi45LTM3LjMgMjAuNi01OS45IDIwLjYtMy45IDAtNy43LS4yLTExLjUtLjcgMjEuMSAxMy44IDQ2LjUgMjEuOCA3My43IDIxLjgiIGZpbGw9IiNmZmYiLz48L3N2Zz4=)}.ck-media__wrapper[data-oembed-url*="twitter.com"] .ck.ck-media__placeholder .ck-media__placeholder__url__text{color:#b8e6ff}.ck-media__wrapper[data-oembed-url*="twitter.com"] .ck.ck-media__placeholder .ck-media__placeholder__url__text:hover{color:#fff}'},function(t,e,i){var n=i(1),o=i(82);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-media-form{display:flex;align-items:flex-start;flex-direction:row;flex-wrap:nowrap}.ck.ck-media-form .ck-labeled-input{display:inline-block}.ck.ck-media-form .ck-label{display:none}@media screen and (max-width:600px){.ck.ck-media-form{flex-wrap:wrap}.ck.ck-media-form .ck-labeled-input{flex-basis:100%}.ck.ck-media-form .ck-button{flex-basis:50%}}.ck.ck-media-form{padding:var(--ck-spacing-standard)}.ck.ck-media-form:focus{outline:none}[dir=ltr] .ck.ck-media-form>:not(:first-child),[dir=rtl] .ck.ck-media-form>:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-media-form{padding:0;width:calc(0.8*var(--ck-input-text-width))}.ck.ck-media-form .ck-labeled-input{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) 0}.ck.ck-media-form .ck-labeled-input .ck-input-text{min-width:0;width:100%}.ck.ck-media-form .ck-labeled-input .ck-labeled-input__error{white-space:normal}.ck.ck-media-form .ck-button{padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-standard);border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border)}[dir=ltr] .ck.ck-media-form .ck-button{margin-left:0}[dir=ltr] .ck.ck-media-form .ck-button:first-of-type{border-right:1px solid var(--ck-color-base-border)}[dir=rtl] .ck.ck-media-form .ck-button{margin-left:0}[dir=rtl] .ck.ck-media-form .ck-button:last-of-type{border-right:1px solid var(--ck-color-base-border)}}"},function(t,e,i){var n=i(1),o=i(84);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck-content .media{clear:both;margin:1em 0;display:block;min-width:15em}"},function(t,e,i){var n=i(1),o=i(86);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=":root{--ck-color-table-focused-cell-background:#f5fafe}.ck-widget.table td.ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck-widget.table th.ck-editor__nested-editable.ck-editor__nested-editable_focused{background:var(--ck-color-table-focused-cell-background);border-style:none;outline:1px solid var(--ck-color-focus-border);outline-offset:-1px}"},function(t,e,i){var n=i(1),o=i(88);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck .ck-insert-table-dropdown__grid{display:flex;flex-direction:row;flex-wrap:wrap}:root{--ck-insert-table-dropdown-padding:10px;--ck-insert-table-dropdown-box-height:11px;--ck-insert-table-dropdown-box-width:12px;--ck-insert-table-dropdown-box-margin:1px}.ck .ck-insert-table-dropdown__grid{width:calc(var(--ck-insert-table-dropdown-box-width)*10 + var(--ck-insert-table-dropdown-box-margin)*20 + var(--ck-insert-table-dropdown-padding)*2);padding:var(--ck-insert-table-dropdown-padding) var(--ck-insert-table-dropdown-padding) 0}.ck .ck-insert-table-dropdown__label{text-align:center}.ck .ck-insert-table-dropdown-grid-box{width:var(--ck-insert-table-dropdown-box-width);height:var(--ck-insert-table-dropdown-box-height);margin:var(--ck-insert-table-dropdown-box-margin);border:1px solid var(--ck-color-base-border);border-radius:1px}.ck .ck-insert-table-dropdown-grid-box.ck-on{border-color:var(--ck-color-focus-border);background:var(--ck-color-focus-outer-shadow)}"},function(t,e,i){var n=i(1),o=i(90);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck-content .table{margin:1em auto;display:table}.ck-content .table table{border-collapse:collapse;border-spacing:0;width:100%;height:100%;border:1px double #b3b3b3}.ck-content .table table td,.ck-content .table table th{min-width:2em;padding:.4em;border-color:#d9d9d9}.ck-content .table table th{font-weight:700;background:#fafafa}"},function(t,e){t.exports=".ck-content code{background-color:hsla(0,0%,78%,.3);padding:.15em;border-radius:2px}"},function(t,e,i){var n=i(1),o=i(93);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck-editor__editable .ck-horizontal-line{overflow:hidden}.ck-content hr{border:solid #5e5e5e;border-width:1px 0 0;margin:0}.ck-editor__editable .ck-horizontal-line{padding:5px 0}"},function(t,e,i){var n=i(1),o=i(95);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck .ck-widget_with-resizer{position:relative}.ck .ck-widget__resizer{display:none;position:absolute;pointer-events:none;left:0;top:0;outline:1px solid var(--ck-color-resizer)}.ck-focused .ck-widget_with-resizer.ck-widget_selected>.ck-widget__resizer{display:block}.ck .ck-widget__resizer__handle{position:absolute;pointer-events:all;width:var(--ck-resizer-size);height:var(--ck-resizer-size);background:var(--ck-color-focus-border);border:var(--ck-resizer-border-width) solid #fff;border-radius:var(--ck-resizer-border-radius)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-left{top:var(--ck-resizer-offset);left:var(--ck-resizer-offset);cursor:nwse-resize}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-right{top:var(--ck-resizer-offset);right:var(--ck-resizer-offset);cursor:nesw-resize}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-right{bottom:var(--ck-resizer-offset);right:var(--ck-resizer-offset);cursor:nwse-resize}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-left{bottom:var(--ck-resizer-offset);left:var(--ck-resizer-offset);cursor:nesw-resize}"},function(t,e,i){var n=i(1),o=i(97);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck-content .image.image_resized{max-width:100%;display:block;box-sizing:border-box}.ck-content .image.image_resized img{width:100%}.ck-content .image.image_resized>figcaption{display:block}"},function(t,e,i){var n=i(1),o=i(99);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck.ck-color-grid{display:grid}:root{--ck-color-grid-tile-size:24px;--ck-color-color-grid-check-icon:#000}.ck.ck-color-grid{grid-gap:5px;padding:8px}.ck.ck-color-grid__tile{width:var(--ck-color-grid-tile-size);height:var(--ck-color-grid-tile-size);min-width:var(--ck-color-grid-tile-size);min-height:var(--ck-color-grid-tile-size);padding:0;transition:box-shadow .2s ease;border:0}.ck.ck-color-grid__tile.ck-disabled{cursor:unset;transition:unset}.ck.ck-color-grid__tile.ck-color-table__color-tile_bordered{box-shadow:0 0 0 1px var(--ck-color-base-border)}.ck.ck-color-grid__tile .ck.ck-icon{display:none;color:var(--ck-color-color-grid-check-icon)}.ck.ck-color-grid__tile.ck-on{box-shadow:inset 0 0 0 1px var(--ck-color-base-background),0 0 0 2px var(--ck-color-base-text)}.ck.ck-color-grid__tile.ck-on .ck.ck-icon{display:block}.ck.ck-color-grid__tile.ck-on,.ck.ck-color-grid__tile:focus:not(.ck-disabled),.ck.ck-color-grid__tile:hover:not(.ck-disabled){border:0}.ck.ck-color-grid__tile:focus:not(.ck-disabled),.ck.ck-color-grid__tile:hover:not(.ck-disabled){box-shadow:inset 0 0 0 1px var(--ck-color-base-background),0 0 0 2px var(--ck-color-focus-border)}.ck.ck-color-grid__label{padding:0 var(--ck-spacing-standard)}"},function(t,e,i){var n=i(1),o=i(101);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".ck .ck-button.ck-color-table__remove-color{display:flex;align-items:center;width:100%}label.ck.ck-color-grid__label{font-weight:unset}.ck .ck-button.ck-color-table__remove-color{padding:calc(var(--ck-spacing-standard)/2) var(--ck-spacing-standard);border-bottom-left-radius:0;border-bottom-right-radius:0}.ck .ck-button.ck-color-table__remove-color:not(:focus){border-bottom:1px solid var(--ck-color-base-border)}[dir=ltr] .ck .ck-button.ck-color-table__remove-color .ck.ck-icon{margin-right:var(--ck-spacing-standard)}[dir=rtl] .ck .ck-button.ck-color-table__remove-color .ck.ck-icon{margin-left:var(--ck-spacing-standard)}"},function(t,e,i){var n=i(1),o=i(103);"string"==typeof(o=o.__esModule?o.default:o)&&(o=[[t.i,o,""]]);var s={injectType:"singletonStyleTag",insert:"head",singleton:!0},r=(n(o,s),o.locals?o.locals:{});t.exports=r},function(t,e){t.exports=".text-tiny{font-size:.7em}.text-small{font-size:.85em}.text-big{font-size:1.4em}.text-huge{font-size:1.8em}"},function(t,e,i){"use strict";i.r(e);var n=i(3),o=n.a.Symbol,s=Object.prototype,r=s.hasOwnProperty,a=s.toString,c=o?o.toStringTag:void 0;var l=function(t){var e=r.call(t,c),i=t[c];try{t[c]=void 0;var n=!0}catch(t){}var o=a.call(t);return n&&(e?t[c]=i:delete t[c]),o},d=Object.prototype.toString;var h=function(t){return d.call(t)},u=o?o.toStringTag:void 0;var f=function(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":u&&u in Object(t)?l(t):h(t)};var m=function(t,e){return function(i){return t(e(i))}},g=m(Object.getPrototypeOf,Object);var p=function(t){return null!=t&&"object"==typeof t},b=Function.prototype,w=Object.prototype,k=b.toString,_=w.hasOwnProperty,v=k.call(Object);var y=function(t){if(!p(t)||"[object Object]"!=f(t))return!1;var e=g(t);if(null===e)return!0;var i=_.call(e,"constructor")&&e.constructor;return"function"==typeof i&&i instanceof i&&k.call(i)==v};var x=function(){this.__data__=[],this.size=0};var A=function(t,e){return t===e||t!=t&&e!=e};var C=function(t,e){for(var i=t.length;i--;)if(A(t[i][0],e))return i;return-1},T=Array.prototype.splice;var P=function(t){var e=this.__data__,i=C(e,t);return!(i<0)&&(i==e.length-1?e.pop():T.call(e,i,1),--this.size,!0)};var S=function(t){var e=this.__data__,i=C(e,t);return i<0?void 0:e[i][1]};var E=function(t){return C(this.__data__,t)>-1};var M=function(t,e){var i=this.__data__,n=C(i,t);return n<0?(++this.size,i.push([t,e])):i[n][1]=e,this};function I(t){var e=-1,i=null==t?0:t.length;for(this.clear();++e<i;){var n=t[e];this.set(n[0],n[1])}}I.prototype.clear=x,I.prototype.delete=P,I.prototype.get=S,I.prototype.has=E,I.prototype.set=M;var N=I;var O=function(){this.__data__=new N,this.size=0};var R=function(t){var e=this.__data__,i=e.delete(t);return this.size=e.size,i};var L=function(t){return this.__data__.get(t)};var D=function(t){return this.__data__.has(t)};var z=function(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)};var j,V=function(t){if(!z(t))return!1;var e=f(t);return"[object Function]"==e||"[object GeneratorFunction]"==e||"[object AsyncFunction]"==e||"[object Proxy]"==e},B=n.a["__core-js_shared__"],F=(j=/[^.]+$/.exec(B&&B.keys&&B.keys.IE_PROTO||""))?"Symbol(src)_1."+j:"";var H=function(t){return!!F&&F in t},U=Function.prototype.toString;var W=function(t){if(null!=t){try{return U.call(t)}catch(t){}try{return t+""}catch(t){}}return""},q=/^\[object .+?Constructor\]$/,$=Function.prototype,Y=Object.prototype,G=$.toString,Q=Y.hasOwnProperty,K=RegExp("^"+G.call(Q).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");var J=function(t){return!(!z(t)||H(t))&&(V(t)?K:q).test(W(t))};var Z=function(t,e){return null==t?void 0:t[e]};var X=function(t,e){var i=Z(t,e);return J(i)?i:void 0},tt=X(n.a,"Map"),et=X(Object,"create");var it=function(){this.__data__=et?et(null):{},this.size=0};var nt=function(t){var e=this.has(t)&&delete this.__data__[t];return this.size-=e?1:0,e},ot=Object.prototype.hasOwnProperty;var st=function(t){var e=this.__data__;if(et){var i=e[t];return"__lodash_hash_undefined__"===i?void 0:i}return ot.call(e,t)?e[t]:void 0},rt=Object.prototype.hasOwnProperty;var at=function(t){var e=this.__data__;return et?void 0!==e[t]:rt.call(e,t)};var ct=function(t,e){var i=this.__data__;return this.size+=this.has(t)?0:1,i[t]=et&&void 0===e?"__lodash_hash_undefined__":e,this};function lt(t){var e=-1,i=null==t?0:t.length;for(this.clear();++e<i;){var n=t[e];this.set(n[0],n[1])}}lt.prototype.clear=it,lt.prototype.delete=nt,lt.prototype.get=st,lt.prototype.has=at,lt.prototype.set=ct;var dt=lt;var ht=function(){this.size=0,this.__data__={hash:new dt,map:new(tt||N),string:new dt}};var ut=function(t){var e=typeof t;return"string"==e||"number"==e||"symbol"==e||"boolean"==e?"__proto__"!==t:null===t};var ft=function(t,e){var i=t.__data__;return ut(e)?i["string"==typeof e?"string":"hash"]:i.map};var mt=function(t){var e=ft(this,t).delete(t);return this.size-=e?1:0,e};var gt=function(t){return ft(this,t).get(t)};var pt=function(t){return ft(this,t).has(t)};var bt=function(t,e){var i=ft(this,t),n=i.size;return i.set(t,e),this.size+=i.size==n?0:1,this};function wt(t){var e=-1,i=null==t?0:t.length;for(this.clear();++e<i;){var n=t[e];this.set(n[0],n[1])}}wt.prototype.clear=ht,wt.prototype.delete=mt,wt.prototype.get=gt,wt.prototype.has=pt,wt.prototype.set=bt;var kt=wt;var _t=function(t,e){var i=this.__data__;if(i instanceof N){var n=i.__data__;if(!tt||n.length<199)return n.push([t,e]),this.size=++i.size,this;i=this.__data__=new kt(n)}return i.set(t,e),this.size=i.size,this};function vt(t){var e=this.__data__=new N(t);this.size=e.size}vt.prototype.clear=O,vt.prototype.delete=R,vt.prototype.get=L,vt.prototype.has=D,vt.prototype.set=_t;var yt=vt;var xt=function(t,e){for(var i=-1,n=null==t?0:t.length;++i<n&&!1!==e(t[i],i,t););return t},At=function(){try{var t=X(Object,"defineProperty");return t({},"",{}),t}catch(t){}}();var Ct=function(t,e,i){"__proto__"==e&&At?At(t,e,{configurable:!0,enumerable:!0,value:i,writable:!0}):t[e]=i},Tt=Object.prototype.hasOwnProperty;var Pt=function(t,e,i){var n=t[e];Tt.call(t,e)&&A(n,i)&&(void 0!==i||e in t)||Ct(t,e,i)};var St=function(t,e,i,n){var o=!i;i||(i={});for(var s=-1,r=e.length;++s<r;){var a=e[s],c=n?n(i[a],t[a],a,i,t):void 0;void 0===c&&(c=t[a]),o?Ct(i,a,c):Pt(i,a,c)}return i};var Et=function(t,e){for(var i=-1,n=Array(t);++i<t;)n[i]=e(i);return n};var Mt=function(t){return p(t)&&"[object Arguments]"==f(t)},It=Object.prototype,Nt=It.hasOwnProperty,Ot=It.propertyIsEnumerable,Rt=Mt(function(){return arguments}())?Mt:function(t){return p(t)&&Nt.call(t,"callee")&&!Ot.call(t,"callee")},Lt=Array.isArray,Dt=i(4),zt=/^(?:0|[1-9]\d*)$/;var jt=function(t,e){var i=typeof t;return!!(e=null==e?9007199254740991:e)&&("number"==i||"symbol"!=i&&zt.test(t))&&t>-1&&t%1==0&&t<e};var Vt=function(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=9007199254740991},Bt={};Bt["[object Float32Array]"]=Bt["[object Float64Array]"]=Bt["[object Int8Array]"]=Bt["[object Int16Array]"]=Bt["[object Int32Array]"]=Bt["[object Uint8Array]"]=Bt["[object Uint8ClampedArray]"]=Bt["[object Uint16Array]"]=Bt["[object Uint32Array]"]=!0,Bt["[object Arguments]"]=Bt["[object Array]"]=Bt["[object ArrayBuffer]"]=Bt["[object Boolean]"]=Bt["[object DataView]"]=Bt["[object Date]"]=Bt["[object Error]"]=Bt["[object Function]"]=Bt["[object Map]"]=Bt["[object Number]"]=Bt["[object Object]"]=Bt["[object RegExp]"]=Bt["[object Set]"]=Bt["[object String]"]=Bt["[object WeakMap]"]=!1;var Ft=function(t){return p(t)&&Vt(t.length)&&!!Bt[f(t)]};var Ht=function(t){return function(e){return t(e)}},Ut=i(5),Wt=Ut.a&&Ut.a.isTypedArray,qt=Wt?Ht(Wt):Ft,$t=Object.prototype.hasOwnProperty;var Yt=function(t,e){var i=Lt(t),n=!i&&Rt(t),o=!i&&!n&&Object(Dt.a)(t),s=!i&&!n&&!o&&qt(t),r=i||n||o||s,a=r?Et(t.length,String):[],c=a.length;for(var l in t)!e&&!$t.call(t,l)||r&&("length"==l||o&&("offset"==l||"parent"==l)||s&&("buffer"==l||"byteLength"==l||"byteOffset"==l)||jt(l,c))||a.push(l);return a},Gt=Object.prototype;var Qt=function(t){var e=t&&t.constructor;return t===("function"==typeof e&&e.prototype||Gt)},Kt=m(Object.keys,Object),Jt=Object.prototype.hasOwnProperty;var Zt=function(t){if(!Qt(t))return Kt(t);var e=[];for(var i in Object(t))Jt.call(t,i)&&"constructor"!=i&&e.push(i);return e};var Xt=function(t){return null!=t&&Vt(t.length)&&!V(t)};var te=function(t){return Xt(t)?Yt(t):Zt(t)};var ee=function(t,e){return t&&St(e,te(e),t)};var ie=function(t){var e=[];if(null!=t)for(var i in Object(t))e.push(i);return e},ne=Object.prototype.hasOwnProperty;var oe=function(t){if(!z(t))return ie(t);var e=Qt(t),i=[];for(var n in t)("constructor"!=n||!e&&ne.call(t,n))&&i.push(n);return i};var se=function(t){return Xt(t)?Yt(t,!0):oe(t)};var re=function(t,e){return t&&St(e,se(e),t)},ae=i(8);var ce=function(t,e){var i=-1,n=t.length;for(e||(e=Array(n));++i<n;)e[i]=t[i];return e};var le=function(t,e){for(var i=-1,n=null==t?0:t.length,o=0,s=[];++i<n;){var r=t[i];e(r,i,t)&&(s[o++]=r)}return s};var de=function(){return[]},he=Object.prototype.propertyIsEnumerable,ue=Object.getOwnPropertySymbols,fe=ue?function(t){return null==t?[]:(t=Object(t),le(ue(t),(function(e){return he.call(t,e)})))}:de;var me=function(t,e){return St(t,fe(t),e)};var ge=function(t,e){for(var i=-1,n=e.length,o=t.length;++i<n;)t[o+i]=e[i];return t},pe=Object.getOwnPropertySymbols?function(t){for(var e=[];t;)ge(e,fe(t)),t=g(t);return e}:de;var be=function(t,e){return St(t,pe(t),e)};var we=function(t,e,i){var n=e(t);return Lt(t)?n:ge(n,i(t))};var ke=function(t){return we(t,te,fe)};var _e=function(t){return we(t,se,pe)},ve=X(n.a,"DataView"),ye=X(n.a,"Promise"),xe=X(n.a,"Set"),Ae=X(n.a,"WeakMap"),Ce=W(ve),Te=W(tt),Pe=W(ye),Se=W(xe),Ee=W(Ae),Me=f;(ve&&"[object DataView]"!=Me(new ve(new ArrayBuffer(1)))||tt&&"[object Map]"!=Me(new tt)||ye&&"[object Promise]"!=Me(ye.resolve())||xe&&"[object Set]"!=Me(new xe)||Ae&&"[object WeakMap]"!=Me(new Ae))&&(Me=function(t){var e=f(t),i="[object Object]"==e?t.constructor:void 0,n=i?W(i):"";if(n)switch(n){case Ce:return"[object DataView]";case Te:return"[object Map]";case Pe:return"[object Promise]";case Se:return"[object Set]";case Ee:return"[object WeakMap]"}return e});var Ie=Me,Ne=Object.prototype.hasOwnProperty;var Oe=function(t){var e=t.length,i=new t.constructor(e);return e&&"string"==typeof t[0]&&Ne.call(t,"index")&&(i.index=t.index,i.input=t.input),i},Re=n.a.Uint8Array;var Le=function(t){var e=new t.constructor(t.byteLength);return new Re(e).set(new Re(t)),e};var De=function(t,e){var i=e?Le(t.buffer):t.buffer;return new t.constructor(i,t.byteOffset,t.byteLength)},ze=/\w*$/;var je=function(t){var e=new t.constructor(t.source,ze.exec(t));return e.lastIndex=t.lastIndex,e},Ve=o?o.prototype:void 0,Be=Ve?Ve.valueOf:void 0;var Fe=function(t){return Be?Object(Be.call(t)):{}};var He=function(t,e){var i=e?Le(t.buffer):t.buffer;return new t.constructor(i,t.byteOffset,t.length)};var Ue=function(t,e,i){var n=t.constructor;switch(e){case"[object ArrayBuffer]":return Le(t);case"[object Boolean]":case"[object Date]":return new n(+t);case"[object DataView]":return De(t,i);case"[object Float32Array]":case"[object Float64Array]":case"[object Int8Array]":case"[object Int16Array]":case"[object Int32Array]":case"[object Uint8Array]":case"[object Uint8ClampedArray]":case"[object Uint16Array]":case"[object Uint32Array]":return He(t,i);case"[object Map]":return new n;case"[object Number]":case"[object String]":return new n(t);case"[object RegExp]":return je(t);case"[object Set]":return new n;case"[object Symbol]":return Fe(t)}},We=Object.create,qe=function(){function t(){}return function(e){if(!z(e))return{};if(We)return We(e);t.prototype=e;var i=new t;return t.prototype=void 0,i}}();var $e=function(t){return"function"!=typeof t.constructor||Qt(t)?{}:qe(g(t))};var Ye=function(t){return p(t)&&"[object Map]"==Ie(t)},Ge=Ut.a&&Ut.a.isMap,Qe=Ge?Ht(Ge):Ye;var Ke=function(t){return p(t)&&"[object Set]"==Ie(t)},Je=Ut.a&&Ut.a.isSet,Ze=Je?Ht(Je):Ke,Xe={};Xe["[object Arguments]"]=Xe["[object Array]"]=Xe["[object ArrayBuffer]"]=Xe["[object DataView]"]=Xe["[object Boolean]"]=Xe["[object Date]"]=Xe["[object Float32Array]"]=Xe["[object Float64Array]"]=Xe["[object Int8Array]"]=Xe["[object Int16Array]"]=Xe["[object Int32Array]"]=Xe["[object Map]"]=Xe["[object Number]"]=Xe["[object Object]"]=Xe["[object RegExp]"]=Xe["[object Set]"]=Xe["[object String]"]=Xe["[object Symbol]"]=Xe["[object Uint8Array]"]=Xe["[object Uint8ClampedArray]"]=Xe["[object Uint16Array]"]=Xe["[object Uint32Array]"]=!0,Xe["[object Error]"]=Xe["[object Function]"]=Xe["[object WeakMap]"]=!1;var ti=function t(e,i,n,o,s,r){var a,c=1&i,l=2&i,d=4&i;if(n&&(a=s?n(e,o,s,r):n(e)),void 0!==a)return a;if(!z(e))return e;var h=Lt(e);if(h){if(a=Oe(e),!c)return ce(e,a)}else{var u=Ie(e),f="[object Function]"==u||"[object GeneratorFunction]"==u;if(Object(Dt.a)(e))return Object(ae.a)(e,c);if("[object Object]"==u||"[object Arguments]"==u||f&&!s){if(a=l||f?{}:$e(e),!c)return l?be(e,re(a,e)):me(e,ee(a,e))}else{if(!Xe[u])return s?e:{};a=Ue(e,u,c)}}r||(r=new yt);var m=r.get(e);if(m)return m;r.set(e,a),Ze(e)?e.forEach((function(o){a.add(t(o,i,n,o,e,r))})):Qe(e)&&e.forEach((function(o,s){a.set(s,t(o,i,n,s,e,r))}));var g=d?l?_e:ke:l?keysIn:te,p=h?void 0:g(e);return xt(p||e,(function(o,s){p&&(o=e[s=o]),Pt(a,s,t(o,i,n,s,e,r))})),a};var ei=function(t,e){return ti(t,5,e="function"==typeof e?e:void 0)};var ii=function(t){return p(t)&&1===t.nodeType&&!y(t)};class ni{constructor(t,e){this._config={},e&&this.define(oi(e)),t&&this._setObjectToTarget(this._config,t)}set(t,e){this._setToTarget(this._config,t,e)}define(t,e){this._setToTarget(this._config,t,e,!0)}get(t){return this._getFromSource(this._config,t)}*names(){for(const t of Object.keys(this._config))yield t}_setToTarget(t,e,i,n=!1){if(y(e))return void this._setObjectToTarget(t,e,n);const o=e.split(".");e=o.pop();for(const e of o)y(t[e])||(t[e]={}),t=t[e];if(y(i))return y(t[e])||(t[e]={}),t=t[e],void this._setObjectToTarget(t,i,n);n&&void 0!==t[e]||(t[e]=i)}_getFromSource(t,e){const i=e.split(".");e=i.pop();for(const e of i){if(!y(t[e])){t=null;break}t=t[e]}return t?oi(t[e]):void 0}_setObjectToTarget(t,e,i){Object.keys(e).forEach(n=>{this._setToTarget(t,n,e[n],i)})}}function oi(t){return ei(t,si)}function si(t){return ii(t)?t:void 0}var ri=function(){return function t(){t.called=!0}};class ai{constructor(t,e){this.source=t,this.name=e,this.path=[],this.stop=ri(),this.off=ri()}}const ci=new Array(256).fill().map((t,e)=>("0"+e.toString(16)).slice(-2));function li(){const t=4294967296*Math.random()>>>0,e=4294967296*Math.random()>>>0,i=4294967296*Math.random()>>>0,n=4294967296*Math.random()>>>0;return"e"+ci[t>>0&255]+ci[t>>8&255]+ci[t>>16&255]+ci[t>>24&255]+ci[e>>0&255]+ci[e>>8&255]+ci[e>>16&255]+ci[e>>24&255]+ci[i>>0&255]+ci[i>>8&255]+ci[i>>16&255]+ci[i>>24&255]+ci[n>>0&255]+ci[n>>8&255]+ci[n>>16&255]+ci[n>>24&255]}var di={get(t){return"number"!=typeof t?this[t]||this.normal:t},highest:1e5,high:1e3,normal:0,low:-1e3,lowest:-1e5},hi=(i(6),i(0));const ui=Symbol("listeningTo"),fi=Symbol("emitterId");var mi={on(t,e,i={}){this.listenTo(this,t,e,i)},once(t,e,i){let n=!1;this.listenTo(this,t,(function(t,...i){n||(n=!0,t.off(),e.call(this,t,...i))}),i)},off(t,e){this.stopListening(this,t,e)},listenTo(t,e,i,n={}){let o,s;this[ui]||(this[ui]={});const r=this[ui];pi(t)||gi(t);const a=pi(t);(o=r[a])||(o=r[a]={emitter:t,callbacks:{}}),(s=o.callbacks[e])||(s=o.callbacks[e]=[]),s.push(i),function(t,e){const i=bi(t);if(i[e])return;let n=e,o=null;const s=[];for(;""!==n&&!i[n];)i[n]={callbacks:[],childEvents:[]},s.push(i[n]),o&&i[n].childEvents.push(o),o=n,n=n.substr(0,n.lastIndexOf(":"));if(""!==n){for(const t of s)t.callbacks=i[n].callbacks.slice();i[n].childEvents.push(o)}}(t,e);const c=wi(t,e),l=di.get(n.priority),d={callback:i,priority:l};for(const t of c){let e=!1;for(let i=0;i<t.length;i++)if(t[i].priority<l){t.splice(i,0,d),e=!0;break}e||t.push(d)}},stopListening(t,e,i){const n=this[ui];let o=t&&pi(t);const s=n&&o&&n[o],r=s&&e&&s.callbacks[e];if(!(!n||t&&!s||e&&!r))if(i)_i(t,e,i);else if(r){for(;i=r.pop();)_i(t,e,i);delete s.callbacks[e]}else if(s){for(e in s.callbacks)this.stopListening(t,e);delete n[o]}else{for(o in n)this.stopListening(n[o].emitter);delete this[ui]}},fire(t,...e){try{const i=t instanceof ai?t:new ai(this,t),n=i.name;let o=function t(e,i){let n;if(!e._events||!(n=e._events[i])||!n.callbacks.length)return i.indexOf(":")>-1?t(e,i.substr(0,i.lastIndexOf(":"))):null;return n.callbacks}(this,n);if(i.path.push(this),o){const t=[i,...e];o=Array.from(o);for(let e=0;e<o.length&&(o[e].callback.apply(this,t),i.off.called&&(delete i.off.called,_i(this,n,o[e].callback)),!i.stop.called);e++);}if(this._delegations){const t=this._delegations.get(n),o=this._delegations.get("*");t&&ki(t,i,e),o&&ki(o,i,e)}return i.return}catch(t){hi.b.rethrowUnexpectedError(t,this)}},delegate(...t){return{to:(e,i)=>{this._delegations||(this._delegations=new Map),t.forEach(t=>{const n=this._delegations.get(t);n?n.set(e,i):this._delegations.set(t,new Map([[e,i]]))})}}},stopDelegating(t,e){if(this._delegations)if(t)if(e){const i=this._delegations.get(t);i&&i.delete(e)}else this._delegations.delete(t);else this._delegations.clear()}};function gi(t,e){t[fi]||(t[fi]=e||li())}function pi(t){return t[fi]}function bi(t){return t._events||Object.defineProperty(t,"_events",{value:{}}),t._events}function wi(t,e){const i=bi(t)[e];if(!i)return[];let n=[i.callbacks];for(let e=0;e<i.childEvents.length;e++){const o=wi(t,i.childEvents[e]);n=n.concat(o)}return n}function ki(t,e,i){for(let[n,o]of t){o?"function"==typeof o&&(o=o(e.name)):o=e.name;const t=new ai(e.source,o);t.path=[...e.path],n.fire(t,...i)}}function _i(t,e,i){const n=wi(t,e);for(const t of n)for(let e=0;e<t.length;e++)t[e].callback==i&&(t.splice(e,1),e--)}function vi(t,...e){e.forEach(e=>{Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e)).forEach(i=>{if(i in t.prototype)return;const n=Object.getOwnPropertyDescriptor(e,i);n.enumerable=!1,Object.defineProperty(t.prototype,i,n)})})}class yi{constructor(t={}){this._items=[],this._itemMap=new Map,this._idProperty=t.idProperty||"id",this._bindToExternalToInternalMap=new WeakMap,this._bindToInternalToExternalMap=new WeakMap,this._skippedIndexesFromExternal=[]}get length(){return this._items.length}get first(){return this._items[0]||null}get last(){return this._items[this.length-1]||null}add(t,e){let i;const n=this._idProperty;if(n in t){if(i=t[n],"string"!=typeof i)throw new hi.b("collection-add-invalid-id",this);if(this.get(i))throw new hi.b("collection-add-item-already-exists",this)}else t[n]=i=li();if(void 0===e)e=this._items.length;else if(e>this._items.length||e<0)throw new hi.b("collection-add-item-invalid-index",this);return this._items.splice(e,0,t),this._itemMap.set(i,t),this.fire("add",t,e),this}get(t){let e;if("string"==typeof t)e=this._itemMap.get(t);else{if("number"!=typeof t)throw new hi.b("collection-get-invalid-arg: Index or id must be given.",this);e=this._items[t]}return e||null}has(t){if("string"==typeof t)return this._itemMap.has(t);{const e=t[this._idProperty];return this._itemMap.has(e)}}getIndex(t){let e;return e="string"==typeof t?this._itemMap.get(t):t,this._items.indexOf(e)}remove(t){let e,i,n,o=!1;const s=this._idProperty;if("string"==typeof t?(i=t,n=this._itemMap.get(i),o=!n,n&&(e=this._items.indexOf(n))):"number"==typeof t?(e=t,n=this._items[e],o=!n,n&&(i=n[s])):(n=t,i=n[s],e=this._items.indexOf(n),o=-1==e||!this._itemMap.get(i)),o)throw new hi.b("collection-remove-404: Item not found.",this);this._items.splice(e,1),this._itemMap.delete(i);const r=this._bindToInternalToExternalMap.get(n);return this._bindToInternalToExternalMap.delete(n),this._bindToExternalToInternalMap.delete(r),this.fire("remove",n,e),n}map(t,e){return this._items.map(t,e)}find(t,e){return this._items.find(t,e)}filter(t,e){return this._items.filter(t,e)}clear(){for(this._bindToCollection&&(this.stopListening(this._bindToCollection),this._bindToCollection=null);this.length;)this.remove(0)}bindTo(t){if(this._bindToCollection)throw new hi.b("collection-bind-to-rebind: The collection cannot be bound more than once.",this);return this._bindToCollection=t,{as:t=>{this._setUpBindToBinding(e=>new t(e))},using:t=>{"function"==typeof t?this._setUpBindToBinding(e=>t(e)):this._setUpBindToBinding(e=>e[t])}}}_setUpBindToBinding(t){const e=this._bindToCollection,i=(i,n,o)=>{const s=e._bindToCollection==this,r=e._bindToInternalToExternalMap.get(n);if(s&&r)this._bindToExternalToInternalMap.set(n,r),this._bindToInternalToExternalMap.set(r,n);else{const i=t(n);if(!i)return void this._skippedIndexesFromExternal.push(o);let s=o;for(const t of this._skippedIndexesFromExternal)o>t&&s--;for(const t of e._skippedIndexesFromExternal)s>=t&&s++;this._bindToExternalToInternalMap.set(n,i),this._bindToInternalToExternalMap.set(i,n),this.add(i,s);for(let t=0;t<e._skippedIndexesFromExternal.length;t++)s<=e._skippedIndexesFromExternal[t]&&e._skippedIndexesFromExternal[t]++}};for(const t of e)i(0,t,e.getIndex(t));this.listenTo(e,"add",i),this.listenTo(e,"remove",(t,e,i)=>{const n=this._bindToExternalToInternalMap.get(e);n&&this.remove(n),this._skippedIndexesFromExternal=this._skippedIndexesFromExternal.reduce((t,e)=>(i<e&&t.push(e-1),i>e&&t.push(e),t),[])})}[Symbol.iterator](){return this._items[Symbol.iterator]()}}vi(yi,mi);class xi{constructor(t,e=[],i=[]){this._context=t,this._plugins=new Map,this._availablePlugins=new Map;for(const t of e)t.pluginName&&this._availablePlugins.set(t.pluginName,t);this._contextPlugins=new Map;for(const[t,e]of i)this._contextPlugins.set(t,e),this._contextPlugins.set(e,t),t.pluginName&&this._availablePlugins.set(t.pluginName,t)}*[Symbol.iterator](){for(const t of this._plugins)"function"==typeof t[0]&&(yield t)}get(t){const e=this._plugins.get(t);if(!e){const e="plugincollection-plugin-not-loaded: The requested plugin is not loaded.";let i=t;throw"function"==typeof t&&(i=t.pluginName||t.name),new hi.b(e,this._context,{plugin:i})}return e}has(t){return this._plugins.has(t)}init(t,e=[]){const i=this,n=this._context,o=new Set,s=[],r=u(t),a=u(e),c=function(t){const e=[];for(const i of t)h(i)||e.push(i);return e.length?e:null}(t);if(c){const t="plugincollection-plugin-not-found: Some plugins are not available and could not be loaded.";return console.error(Object(hi.a)(t),{plugins:c}),Promise.reject(new hi.b(t,n,{plugins:c}))}return Promise.all(r.map(l)).then(()=>d(s,"init")).then(()=>d(s,"afterInit")).then(()=>s);function l(t){if(!a.includes(t)&&!i._plugins.has(t)&&!o.has(t))return function(t){return new Promise(r=>{o.add(t),t.requires&&t.requires.forEach(i=>{const o=h(i);if(t.isContextPlugin&&!o.isContextPlugin)throw new hi.b("plugincollection-context-required: Context plugin can not require plugin which is not a context plugin",null,{plugin:o.name,requiredBy:t.name});if(e.includes(o))throw new hi.b("plugincollection-required: Cannot load a plugin because one of its dependencies is listed inthe `removePlugins` option.",n,{plugin:o.name,requiredBy:t.name});l(o)});const a=i._contextPlugins.get(t)||new t(n);i._add(t,a),s.push(a),r()})}(t).catch(e=>{throw console.error(Object(hi.a)("plugincollection-load: It was not possible to load the plugin."),{plugin:t}),e})}function d(t,e){return t.reduce((t,n)=>n[e]?i._contextPlugins.has(n)?t:t.then(n[e].bind(n)):t,Promise.resolve())}function h(t){return"function"==typeof t?t:i._availablePlugins.get(t)}function u(t){return t.map(t=>h(t)).filter(t=>!!t)}}destroy(){const t=[];for(const[,e]of this)"function"!=typeof e.destroy||this._contextPlugins.has(e)||t.push(e.destroy());return Promise.all(t)}_add(t,e){this._plugins.set(t,e);const i=t.pluginName;if(i){if(this._plugins.has(i))throw new hi.b("plugincollection-plugin-name-conflict: Two plugins with the same name were loaded.",null,{pluginName:i,plugin1:this._plugins.get(i).constructor,plugin2:t});this._plugins.set(i,e)}}}function Ai(t,e){const i=Object.keys(window.CKEDITOR_TRANSLATIONS).length;return 1===i&&(t=Object.keys(window.CKEDITOR_TRANSLATIONS)[0]),0!==i&&function(t,e){return t in window.CKEDITOR_TRANSLATIONS&&e in window.CKEDITOR_TRANSLATIONS[t]}(t,e)?window.CKEDITOR_TRANSLATIONS[t][e].replace(/ \[context: [^\]]+\]$/,""):e.replace(/ \[context: [^\]]+\]$/,"")}vi(xi,mi),window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={});const Ci=["ar","fa","he","ku","ug"];class Ti{constructor(t={}){this.uiLanguage=t.uiLanguage||"en",this.contentLanguage=t.contentLanguage||this.uiLanguage,this.uiLanguageDirection=Pi(this.uiLanguage),this.contentLanguageDirection=Pi(this.contentLanguage),this.t=(...t)=>this._t(...t)}get language(){return console.warn("locale-deprecated-language-property: The Locale#language property has been deprecated and will be removed in the near future. Please use #uiLanguage and #contentLanguage properties instead."),this.uiLanguage}_t(t,e){let i=Ai(this.uiLanguage,t);return e&&(i=i.replace(/%(\d+)/g,(t,i)=>i<e.length?e[i]:t)),i}}function Pi(t){return Ci.includes(t)?"rtl":"ltr"}class Si{constructor(t){this.config=new ni(t,this.constructor.defaultConfig);const e=this.constructor.builtinPlugins;this.config.define("plugins",e),this.plugins=new xi(this,e);const i=this.config.get("language")||{};this.locale=new Ti({uiLanguage:"string"==typeof i?i:i.ui,contentLanguage:this.config.get("language.content")}),this.t=this.locale.t,this.editors=new yi,this._contextOwner=null}initPlugins(){const t=this.config.get("plugins")||[];for(const e of t){if("function"!=typeof e)throw new hi.b("context-initplugins-constructor-only: Only a constructor function is allowed as a context plugin.",null,{Plugin:e});if(!0!==e.isContextPlugin)throw new hi.b("context-initplugins-invalid-plugin: Only a plugin marked as a context plugin is allowed to be used with a context.",null,{Plugin:e})}return this.plugins.init(t)}destroy(){return Promise.all(Array.from(this.editors,t=>t.destroy())).then(()=>this.plugins.destroy())}_addEditor(t,e){if(this._contextOwner)throw new hi.b("context-addEditor-private-context: Cannot add multiple editors to the context which is created by the editor.");this.editors.add(t),e&&(this._contextOwner=t)}_removeEditor(t){return this.editors.has(t)&&this.editors.remove(t),this._contextOwner===t?this.destroy():Promise.resolve()}_getEditorConfig(){const t={};for(const e of this.config.names())["plugins","removePlugins","extraPlugins"].includes(e)||(t[e]=this.config.get(e));return t}static create(t){return new Promise(e=>{const i=new this(t);e(i.initPlugins().then(()=>i))})}}function Ei(t,e){const i=Math.min(t.length,e.length);for(let n=0;n<i;n++)if(t[n]!=e[n])return n;return t.length==e.length?"same":t.length<e.length?"prefix":"extension"}var Mi=function(t){return ti(t,4)};class Ii{constructor(){this.parent=null}get index(){let t;if(!this.parent)return null;if(-1==(t=this.parent.getChildIndex(this)))throw new hi.b("view-node-not-found-in-parent: The node's parent does not contain this node.",this);return t}get nextSibling(){const t=this.index;return null!==t&&this.parent.getChild(t+1)||null}get previousSibling(){const t=this.index;return null!==t&&this.parent.getChild(t-1)||null}get root(){let t=this;for(;t.parent;)t=t.parent;return t}get document(){return this.parent instanceof Ii?this.parent.document:null}getPath(){const t=[];let e=this;for(;e.parent;)t.unshift(e.index),e=e.parent;return t}getAncestors(t={includeSelf:!1,parentFirst:!1}){const e=[];let i=t.includeSelf?this:this.parent;for(;i;)e[t.parentFirst?"push":"unshift"](i),i=i.parent;return e}getCommonAncestor(t,e={}){const i=this.getAncestors(e),n=t.getAncestors(e);let o=0;for(;i[o]==n[o]&&i[o];)o++;return 0===o?null:i[o-1]}isBefore(t){if(this==t)return!1;if(this.root!==t.root)return!1;const e=this.getPath(),i=t.getPath(),n=Ei(e,i);switch(n){case"prefix":return!0;case"extension":return!1;default:return e[n]<i[n]}}isAfter(t){return this!=t&&(this.root===t.root&&!this.isBefore(t))}_remove(){this.parent._removeChildren(this.index)}_fireChange(t,e){this.fire("change:"+t,e),this.parent&&this.parent._fireChange(t,e)}toJSON(){const t=Mi(this);return delete t.parent,t}is(t){return"node"==t||"view:node"==t}}vi(Ii,mi);class Ni extends Ii{constructor(t){super(),this._textData=t}is(t){return"text"==t||"view:text"==t||super.is(t)}get data(){return this._textData}get _data(){return this.data}set _data(t){this._fireChange("text",this),this._textData=t}isSimilar(t){return t instanceof Ni&&(this===t||this.data===t.data)}_clone(){return new Ni(this.data)}}class Oi{constructor(t,e,i){if(this.textNode=t,e<0||e>t.data.length)throw new hi.b("view-textproxy-wrong-offsetintext: Given offsetInText value is incorrect.",this);if(i<0||e+i>t.data.length)throw new hi.b("view-textproxy-wrong-length: Given length value is incorrect.",this);this.data=t.data.substring(e,e+i),this.offsetInText=e}get offsetSize(){return this.data.length}get isPartial(){return this.data.length!==this.textNode.data.length}get parent(){return this.textNode.parent}get root(){return this.textNode.root}get document(){return this.textNode.document}is(t){return"textProxy"==t||"view:textProxy"==t}getAncestors(t={includeSelf:!1,parentFirst:!1}){const e=[];let i=t.includeSelf?this.textNode:this.parent;for(;null!==i;)e[t.parentFirst?"push":"unshift"](i),i=i.parent;return e}}function Ri(t){return!(!t||!t[Symbol.iterator])}function Li(t){return Ri(t)?new Map(t):function(t){const e=new Map;for(const i in t)e.set(i,t[i]);return e}(t)}class Di{constructor(...t){this._patterns=[],this.add(...t)}add(...t){for(let e of t)("string"==typeof e||e instanceof RegExp)&&(e={name:e}),e.classes&&("string"==typeof e.classes||e.classes instanceof RegExp)&&(e.classes=[e.classes]),this._patterns.push(e)}match(...t){for(const e of t)for(const t of this._patterns){const i=zi(e,t);if(i)return{element:e,pattern:t,match:i}}return null}matchAll(...t){const e=[];for(const i of t)for(const t of this._patterns){const n=zi(i,t);n&&e.push({element:i,pattern:t,match:n})}return e.length>0?e:null}getElementName(){if(1!==this._patterns.length)return null;const t=this._patterns[0],e=t.name;return"function"==typeof t||!e||e instanceof RegExp?null:e}}function zi(t,e){if("function"==typeof e)return e(t);const i={};return e.name&&(i.name=function(t,e){if(t instanceof RegExp)return t.test(e);return t===e}(e.name,t.name),!i.name)||e.attributes&&(i.attributes=function(t,e){const i=[];for(const n in t){const o=t[n];if(!e.hasAttribute(n))return null;{const t=e.getAttribute(n);if(!0===o)i.push(n);else if(o instanceof RegExp){if(!o.test(t))return null;i.push(n)}else{if(t!==o)return null;i.push(n)}}}return i}(e.attributes,t),!i.attributes)?null:!(e.classes&&(i.classes=function(t,e){const i=[];for(const n of t)if(n instanceof RegExp){const t=e.getClassNames();for(const e of t)n.test(e)&&i.push(e);if(0===i.length)return null}else{if(!e.hasClass(n))return null;i.push(n)}return i}(e.classes,t),!i.classes))&&(!(e.styles&&(i.styles=function(t,e){const i=[];for(const n in t){const o=t[n];if(!e.hasStyle(n))return null;{const t=e.getStyle(n);if(o instanceof RegExp){if(!o.test(t))return null;i.push(n)}else{if(t!==o)return null;i.push(n)}}}return i}(e.styles,t),!i.styles))&&i)}var ji=function(t){return"symbol"==typeof t||p(t)&&"[object Symbol]"==f(t)},Vi=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Bi=/^\w*$/;var Fi=function(t,e){if(Lt(t))return!1;var i=typeof t;return!("number"!=i&&"symbol"!=i&&"boolean"!=i&&null!=t&&!ji(t))||(Bi.test(t)||!Vi.test(t)||null!=e&&t in Object(e))};function Hi(t,e){if("function"!=typeof t||null!=e&&"function"!=typeof e)throw new TypeError("Expected a function");var i=function(){var n=arguments,o=e?e.apply(this,n):n[0],s=i.cache;if(s.has(o))return s.get(o);var r=t.apply(this,n);return i.cache=s.set(o,r)||s,r};return i.cache=new(Hi.Cache||kt),i}Hi.Cache=kt;var Ui=Hi;var Wi=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,qi=/\\(\\)?/g,$i=function(t){var e=Ui(t,(function(t){return 500===i.size&&i.clear(),t})),i=e.cache;return e}((function(t){var e=[];return 46===t.charCodeAt(0)&&e.push(""),t.replace(Wi,(function(t,i,n,o){e.push(n?o.replace(qi,"$1"):i||t)})),e}));var Yi=function(t,e){for(var i=-1,n=null==t?0:t.length,o=Array(n);++i<n;)o[i]=e(t[i],i,t);return o},Gi=o?o.prototype:void 0,Qi=Gi?Gi.toString:void 0;var Ki=function t(e){if("string"==typeof e)return e;if(Lt(e))return Yi(e,t)+"";if(ji(e))return Qi?Qi.call(e):"";var i=e+"";return"0"==i&&1/e==-1/0?"-0":i};var Ji=function(t){return null==t?"":Ki(t)};var Zi=function(t,e){return Lt(t)?t:Fi(t,e)?[t]:$i(Ji(t))};var Xi=function(t){var e=null==t?0:t.length;return e?t[e-1]:void 0};var tn=function(t){if("string"==typeof t||ji(t))return t;var e=t+"";return"0"==e&&1/t==-1/0?"-0":e};var en=function(t,e){for(var i=0,n=(e=Zi(e,t)).length;null!=t&&i<n;)t=t[tn(e[i++])];return i&&i==n?t:void 0};var nn=function(t,e,i){var n=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(i=i>o?o:i)<0&&(i+=o),o=e>i?0:i-e>>>0,e>>>=0;for(var s=Array(o);++n<o;)s[n]=t[n+e];return s};var on=function(t,e){return e.length<2?t:en(t,nn(e,0,-1))};var sn=function(t,e){return e=Zi(e,t),null==(t=on(t,e))||delete t[tn(Xi(e))]};var rn=function(t,e){return null==t||sn(t,e)};var an=function(t,e,i){var n=null==t?void 0:en(t,e);return void 0===n?i:n};var cn=function(t,e,i){(void 0===i||A(t[e],i))&&(void 0!==i||e in t)||Ct(t,e,i)};var ln=function(t){return function(e,i,n){for(var o=-1,s=Object(e),r=n(e),a=r.length;a--;){var c=r[t?a:++o];if(!1===i(s[c],c,s))break}return e}}();var dn=function(t){return p(t)&&Xt(t)};var hn=function(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]};var un=function(t){return St(t,se(t))};var fn=function(t,e,i,n,o,s,r){var a=hn(t,i),c=hn(e,i),l=r.get(c);if(l)cn(t,i,l);else{var d=s?s(a,c,i+"",t,e,r):void 0,h=void 0===d;if(h){var u=Lt(c),f=!u&&Object(Dt.a)(c),m=!u&&!f&&qt(c);d=c,u||f||m?Lt(a)?d=a:dn(a)?d=ce(a):f?(h=!1,d=Object(ae.a)(c,!0)):m?(h=!1,d=He(c,!0)):d=[]:y(c)||Rt(c)?(d=a,Rt(a)?d=un(a):z(a)&&!V(a)||(d=$e(c))):h=!1}h&&(r.set(c,d),o(d,c,n,s,r),r.delete(c)),cn(t,i,d)}};var mn=function t(e,i,n,o,s){e!==i&&ln(i,(function(r,a){if(s||(s=new yt),z(r))fn(e,i,a,n,t,o,s);else{var c=o?o(hn(e,a),r,a+"",e,i,s):void 0;void 0===c&&(c=r),cn(e,a,c)}}),se)};var gn=function(t){return t};var pn=function(t,e,i){switch(i.length){case 0:return t.call(e);case 1:return t.call(e,i[0]);case 2:return t.call(e,i[0],i[1]);case 3:return t.call(e,i[0],i[1],i[2])}return t.apply(e,i)},bn=Math.max;var wn=function(t,e,i){return e=bn(void 0===e?t.length-1:e,0),function(){for(var n=arguments,o=-1,s=bn(n.length-e,0),r=Array(s);++o<s;)r[o]=n[e+o];o=-1;for(var a=Array(e+1);++o<e;)a[o]=n[o];return a[e]=i(r),pn(t,this,a)}};var kn=function(t){return function(){return t}},_n=At?function(t,e){return At(t,"toString",{configurable:!0,enumerable:!1,value:kn(e),writable:!0})}:gn,vn=Date.now;var yn=function(t){var e=0,i=0;return function(){var n=vn(),o=16-(n-i);if(i=n,o>0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}(_n);var xn=function(t,e){return yn(wn(t,e,gn),t+"")};var An=function(t,e,i){if(!z(i))return!1;var n=typeof e;return!!("number"==n?Xt(i)&&jt(e,i.length):"string"==n&&e in i)&&A(i[e],t)};var Cn=function(t){return xn((function(e,i){var n=-1,o=i.length,s=o>1?i[o-1]:void 0,r=o>2?i[2]:void 0;for(s=t.length>3&&"function"==typeof s?(o--,s):void 0,r&&An(i[0],i[1],r)&&(s=o<3?void 0:s,o=1),e=Object(e);++n<o;){var a=i[n];a&&t(e,a,n,s)}return e}))},Tn=Cn((function(t,e,i){mn(t,e,i)}));var Pn=function(t,e,i,n){if(!z(t))return t;for(var o=-1,s=(e=Zi(e,t)).length,r=s-1,a=t;null!=a&&++o<s;){var c=tn(e[o]),l=i;if(o!=r){var d=a[c];void 0===(l=n?n(d,c,a):void 0)&&(l=z(d)?d:jt(e[o+1])?[]:{})}Pt(a,c,l),a=a[c]}return t};var Sn=function(t,e,i){return null==t?t:Pn(t,e,i)};class En{constructor(){this._styles={},Object.defineProperty(this,"_styleProcessor",{get:()=>En._styleProcessor,enumerable:!1})}get isEmpty(){const t=Object.entries(this._styles);return!Array.from(t).length}get size(){return this.isEmpty?0:this.getStyleNames().length}setTo(t){this.clear();const e=Array.from(function(t){let e=null,i=0,n=0,o=null;const s=new Map;if(""===t)return s;";"!=t.charAt(t.length-1)&&(t+=";");for(let r=0;r<t.length;r++){const a=t.charAt(r);if(null===e)switch(a){case":":o||(o=t.substr(i,r-i),n=r+1);break;case'"':case"'":e=a;break;case";":{const e=t.substr(n,r-n);o&&s.set(o.trim(),e.trim()),o=null,i=r+1;break}}else a===e&&(e=null)}return s}(t).entries());for(const[t,i]of e)this._styleProcessor.toNormalizedForm(t,i,this._styles)}has(t){if(this.isEmpty)return!1;const e=this._styleProcessor.getReducedForm(t,this._styles).find(([e])=>e===t);return Array.isArray(e)}set(t,e){if(z(t))for(const[e,i]of Object.entries(t))this._styleProcessor.toNormalizedForm(e,i,this._styles);else this._styleProcessor.toNormalizedForm(t,e,this._styles)}remove(t){const e=In(t);rn(this._styles,e),delete this._styles[t],this._cleanEmptyObjectsOnPath(e)}getNormalized(t){return this._styleProcessor.getNormalized(t,this._styles)}toString(){return this.isEmpty?"":this._getStylesEntries().map(t=>t.join(":")).sort().join(";")+";"}getAsString(t){if(this.isEmpty)return;if(this._styles[t]&&!z(this._styles[t]))return this._styles[t];const e=this._styleProcessor.getReducedForm(t,this._styles).find(([e])=>e===t);return Array.isArray(e)?e[1]:void 0}getStyleNames(){if(this.isEmpty)return[];return this._getStylesEntries().map(([t])=>t)}clear(){this._styles={}}static getRelatedStyles(t){return this._styleProcessor.getRelatedStyles(t)}_getStylesEntries(){const t=[],e=Object.keys(this._styles);for(const i of e)t.push(...this._styleProcessor.getReducedForm(i,this._styles));return t}_cleanEmptyObjectsOnPath(t){const e=t.split(".");if(!(e.length>1))return;const i=e.splice(0,e.length-1).join("."),n=an(this._styles,i);n&&!Array.from(Object.keys(n)).length&&this.remove(i)}static get _styleProcessor(){return this._processor||(this._processor=new Mn),this._processor}static _setProcessor(t){this._processor=t}}class Mn{constructor(){this._normalizers=new Map,this._extractors=new Map,this._reducers=new Map,this._consumables=new Map}toNormalizedForm(t,e,i){if(z(e))Nn(i,In(t),e);else if(this._normalizers.has(t)){const n=this._normalizers.get(t),{path:o,value:s}=n(e);Nn(i,o,s)}else Nn(i,t,e)}getNormalized(t,e){if(!t)return Tn({},e);if(void 0!==e[t])return e[t];if(this._extractors.has(t)){const i=this._extractors.get(t);if("string"==typeof i)return an(e,i);const n=i(t,e);if(n)return n}return an(e,In(t))}getReducedForm(t,e){const i=this.getNormalized(t,e);if(void 0===i)return[];if(this._reducers.has(t)){return this._reducers.get(t)(i)}return[[t,i]]}getRelatedStyles(t){return this._consumables.get(t)||[]}setNormalizer(t,e){this._normalizers.set(t,e)}setExtractor(t,e){this._extractors.set(t,e)}setReducer(t,e){this._reducers.set(t,e)}setStyleRelation(t,e){this._mapStyleNames(t,e);for(const i of e)this._mapStyleNames(i,[t])}_mapStyleNames(t,e){this._consumables.has(t)||this._consumables.set(t,[]),this._consumables.get(t).push(...e)}}function In(t){return t.replace("-",".")}function Nn(t,e,i){let n=i;z(i)&&(n=Tn({},an(t,e),i)),Sn(t,e,n)}class On extends Ii{constructor(t,e,i){if(super(),this.name=t,this._attrs=function(t){t=Li(t);for(const[e,i]of t)null===i?t.delete(e):"string"!=typeof i&&t.set(e,String(i));return t}(e),this._children=[],i&&this._insertChild(0,i),this._classes=new Set,this._attrs.has("class")){const t=this._attrs.get("class");Rn(this._classes,t),this._attrs.delete("class")}this._styles=new En,this._attrs.has("style")&&(this._styles.setTo(this._attrs.get("style")),this._attrs.delete("style")),this._customProperties=new Map}get childCount(){return this._children.length}get isEmpty(){return 0===this._children.length}is(t,e=null){const i=t.replace(/^view:/,"");return e?"element"==i&&e==this.name:"element"==i||i==this.name||super.is(t)}getChild(t){return this._children[t]}getChildIndex(t){return this._children.indexOf(t)}getChildren(){return this._children[Symbol.iterator]()}*getAttributeKeys(){this._classes.size>0&&(yield"class"),this._styles.isEmpty||(yield"style"),yield*this._attrs.keys()}*getAttributes(){yield*this._attrs.entries(),this._classes.size>0&&(yield["class",this.getAttribute("class")]),this._styles.isEmpty||(yield["style",this.getAttribute("style")])}getAttribute(t){if("class"==t)return this._classes.size>0?[...this._classes].join(" "):void 0;if("style"==t){const t=this._styles.toString();return""==t?void 0:t}return this._attrs.get(t)}hasAttribute(t){return"class"==t?this._classes.size>0:"style"==t?!this._styles.isEmpty:this._attrs.has(t)}isSimilar(t){if(!(t instanceof On))return!1;if(this===t)return!0;if(this.name!=t.name)return!1;if(this._attrs.size!==t._attrs.size||this._classes.size!==t._classes.size||this._styles.size!==t._styles.size)return!1;for(const[e,i]of this._attrs)if(!t._attrs.has(e)||t._attrs.get(e)!==i)return!1;for(const e of this._classes)if(!t._classes.has(e))return!1;for(const e of this._styles.getStyleNames())if(!t._styles.has(e)||t._styles.getAsString(e)!==this._styles.getAsString(e))return!1;return!0}hasClass(...t){for(const e of t)if(!this._classes.has(e))return!1;return!0}getClassNames(){return this._classes.keys()}getStyle(t){return this._styles.getAsString(t)}getNormalizedStyle(t){return this._styles.getNormalized(t)}getStyleNames(){return this._styles.getStyleNames()}hasStyle(...t){for(const e of t)if(!this._styles.has(e))return!1;return!0}findAncestor(...t){const e=new Di(...t);let i=this.parent;for(;i;){if(e.match(i))return i;i=i.parent}return null}getCustomProperty(t){return this._customProperties.get(t)}*getCustomProperties(){yield*this._customProperties.entries()}getIdentity(){const t=Array.from(this._classes).sort().join(","),e=this._styles.toString(),i=Array.from(this._attrs).map(t=>`${t[0]}="${t[1]}"`).sort().join(" ");return this.name+(""==t?"":` class="${t}"`)+(e?` style="${e}"`:"")+(""==i?"":` ${i}`)}_clone(t=!1){const e=[];if(t)for(const i of this.getChildren())e.push(i._clone(t));const i=new this.constructor(this.name,this._attrs,e);return i._classes=new Set(this._classes),i._styles.set(this._styles.getNormalized()),i._customProperties=new Map(this._customProperties),i.getFillerOffset=this.getFillerOffset,i}_appendChild(t){return this._insertChild(this.childCount,t)}_insertChild(t,e){this._fireChange("children",this);let i=0;const n=function(t){if("string"==typeof t)return[new Ni(t)];Ri(t)||(t=[t]);return Array.from(t).map(t=>"string"==typeof t?new Ni(t):t instanceof Oi?new Ni(t.data):t)}(e);for(const e of n)null!==e.parent&&e._remove(),e.parent=this,this._children.splice(t,0,e),t++,i++;return i}_removeChildren(t,e=1){this._fireChange("children",this);for(let i=t;i<t+e;i++)this._children[i].parent=null;return this._children.splice(t,e)}_setAttribute(t,e){e=String(e),this._fireChange("attributes",this),"class"==t?Rn(this._classes,e):"style"==t?this._styles.setTo(e):this._attrs.set(t,e)}_removeAttribute(t){return this._fireChange("attributes",this),"class"==t?this._classes.size>0&&(this._classes.clear(),!0):"style"==t?!this._styles.isEmpty&&(this._styles.clear(),!0):this._attrs.delete(t)}_addClass(t){this._fireChange("attributes",this),(t=Array.isArray(t)?t:[t]).forEach(t=>this._classes.add(t))}_removeClass(t){this._fireChange("attributes",this),(t=Array.isArray(t)?t:[t]).forEach(t=>this._classes.delete(t))}_setStyle(t,e){this._fireChange("attributes",this),this._styles.set(t,e)}_removeStyle(t){this._fireChange("attributes",this),(t=Array.isArray(t)?t:[t]).forEach(t=>this._styles.remove(t))}_setCustomProperty(t,e){this._customProperties.set(t,e)}_removeCustomProperty(t){return this._customProperties.delete(t)}}function Rn(t,e){const i=e.split(/\s+/);t.clear(),i.forEach(e=>t.add(e))}class Ln extends On{constructor(t,e,i){super(t,e,i),this.getFillerOffset=Dn}is(t,e=null){const i=t&&t.replace(/^view:/,"");return e?"containerElement"==i&&e==this.name||super.is(t,e):"containerElement"==i||super.is(t)}}function Dn(){const t=[...this.getChildren()],e=t[this.childCount-1];if(e&&e.is("element","br"))return this.childCount;for(const e of t)if(!e.is("uiElement"))return null;return this.childCount}var zn=Cn((function(t,e){St(e,se(e),t)}));const jn=Symbol("observableProperties"),Vn=Symbol("boundObservables"),Bn=Symbol("boundProperties"),Fn={set(t,e){if(z(t))return void Object.keys(t).forEach(e=>{this.set(e,t[e])},this);Un(this);const i=this[jn];if(t in this&&!i.has(t))throw new hi.b("observable-set-cannot-override: Cannot override an existing property.",this);Object.defineProperty(this,t,{enumerable:!0,configurable:!0,get:()=>i.get(t),set(e){const n=i.get(t);let o=this.fire("set:"+t,t,e,n);void 0===o&&(o=e),n===o&&i.has(t)||(i.set(t,o),this.fire("change:"+t,t,o,n))}}),this[t]=e},bind(...t){if(!t.length||!$n(t))throw new hi.b("observable-bind-wrong-properties: All properties must be strings.",this);if(new Set(t).size!==t.length)throw new hi.b("observable-bind-duplicate-properties: Properties must be unique.",this);Un(this);const e=this[Bn];t.forEach(t=>{if(e.has(t))throw new hi.b("observable-bind-rebind: Cannot bind the same property more than once.",this)});const i=new Map;return t.forEach(t=>{const n={property:t,to:[]};e.set(t,n),i.set(t,n)}),{to:Wn,toMany:qn,_observable:this,_bindProperties:t,_to:[],_bindings:i}},unbind(...t){if(!(jn in this))return;const e=this[Bn],i=this[Vn];if(t.length){if(!$n(t))throw new hi.b("observable-unbind-wrong-properties: Properties must be strings.",this);t.forEach(t=>{const n=e.get(t);if(!n)return;let o,s,r,a;n.to.forEach(t=>{o=t[0],s=t[1],r=i.get(o),a=r[s],a.delete(n),a.size||delete r[s],Object.keys(r).length||(i.delete(o),this.stopListening(o,"change"))}),e.delete(t)})}else i.forEach((t,e)=>{this.stopListening(e,"change")}),i.clear(),e.clear()},decorate(t){const e=this[t];if(!e)throw new hi.b("observablemixin-cannot-decorate-undefined: Cannot decorate an undefined method.",this,{object:this,methodName:t});this.on(t,(t,i)=>{t.return=e.apply(this,i)}),this[t]=function(...e){return this.fire(t,e)}}};zn(Fn,mi);var Hn=Fn;function Un(t){jn in t||(Object.defineProperty(t,jn,{value:new Map}),Object.defineProperty(t,Vn,{value:new Map}),Object.defineProperty(t,Bn,{value:new Map}))}function Wn(...t){const e=function(...t){if(!t.length)throw new hi.b("observable-bind-to-parse-error: Invalid argument syntax in `to()`.",null);const e={to:[]};let i;"function"==typeof t[t.length-1]&&(e.callback=t.pop());return t.forEach(t=>{if("string"==typeof t)i.properties.push(t);else{if("object"!=typeof t)throw new hi.b("observable-bind-to-parse-error: Invalid argument syntax in `to()`.",null);i={observable:t,properties:[]},e.to.push(i)}}),e}(...t),i=Array.from(this._bindings.keys()),n=i.length;if(!e.callback&&e.to.length>1)throw new hi.b("observable-bind-to-no-callback: Binding multiple observables only possible with callback.",this);if(n>1&&e.callback)throw new hi.b("observable-bind-to-extra-callback: Cannot bind multiple properties and use a callback in one binding.",this);var o;e.to.forEach(t=>{if(t.properties.length&&t.properties.length!==n)throw new hi.b("observable-bind-to-properties-length: The number of properties must match.",this);t.properties.length||(t.properties=this._bindProperties)}),this._to=e.to,e.callback&&(this._bindings.get(i[0]).callback=e.callback),o=this._observable,this._to.forEach(t=>{const e=o[Vn];let i;e.get(t.observable)||o.listenTo(t.observable,"change",(n,s)=>{i=e.get(t.observable)[s],i&&i.forEach(t=>{Yn(o,t.property)})})}),function(t){let e;t._bindings.forEach((i,n)=>{t._to.forEach(o=>{e=o.properties[i.callback?0:t._bindProperties.indexOf(n)],i.to.push([o.observable,e]),function(t,e,i,n){const o=t[Vn],s=o.get(i),r=s||{};r[n]||(r[n]=new Set);r[n].add(e),s||o.set(i,r)}(t._observable,i,o.observable,e)})})}(this),this._bindProperties.forEach(t=>{Yn(this._observable,t)})}function qn(t,e,i){if(this._bindings.size>1)throw new hi.b("observable-bind-to-many-not-one-binding: Cannot bind multiple properties with toMany().",this);this.to(...function(t,e){const i=t.map(t=>[t,e]);return Array.prototype.concat.apply([],i)}(t,e),i)}function $n(t){return t.every(t=>"string"==typeof t)}function Yn(t,e){const i=t[Bn].get(e);let n;i.callback?n=i.callback.apply(t,i.to.map(t=>t[0][t[1]])):(n=i.to[0],n=n[0][n[1]]),t.hasOwnProperty(e)?t[e]=n:t.set(e,n)}const Gn=Symbol("document");class Qn extends Ln{constructor(t,e,i){super(t,e,i),this.set("isReadOnly",!1),this.set("isFocused",!1)}is(t,e=null){const i=t&&t.replace(/^view:/,"");return e?"editableElement"==i&&e==this.name||super.is(t,e):"editableElement"==i||super.is(t)}destroy(){this.stopListening()}get document(){return this.getCustomProperty(Gn)}set _document(t){if(this.getCustomProperty(Gn))throw new hi.b("view-editableelement-document-already-set: View document is already set.",this);this._setCustomProperty(Gn,t),this.bind("isReadOnly").to(t),this.bind("isFocused").to(t,"isFocused",e=>e&&t.selection.editableElement==this),this.listenTo(t.selection,"change",()=>{this.isFocused=t.isFocused&&t.selection.editableElement==this})}}vi(Qn,Hn);const Kn=Symbol("rootName");class Jn extends Qn{constructor(t){super(t),this.rootName="main"}is(t,e=null){const i=t.replace(/^view:/,"");return e?"rootElement"==i&&e==this.name||super.is(t,e):"rootElement"==i||super.is(t)}get rootName(){return this.getCustomProperty(Kn)}set rootName(t){this._setCustomProperty(Kn,t)}set _name(t){this.name=t}}class Zn{constructor(t={}){if(!t.boundaries&&!t.startPosition)throw new hi.b("view-tree-walker-no-start-position: Neither boundaries nor starting position have been defined.",null);if(t.direction&&"forward"!=t.direction&&"backward"!=t.direction)throw new hi.b("view-tree-walker-unknown-direction: Only `backward` and `forward` direction allowed.",t.startPosition,{direction:t.direction});this.boundaries=t.boundaries||null,t.startPosition?this.position=Xn._createAt(t.startPosition):this.position=Xn._createAt(t.boundaries["backward"==t.direction?"end":"start"]),this.direction=t.direction||"forward",this.singleCharacters=!!t.singleCharacters,this.shallow=!!t.shallow,this.ignoreElementEnd=!!t.ignoreElementEnd,this._boundaryStartParent=this.boundaries?this.boundaries.start.parent:null,this._boundaryEndParent=this.boundaries?this.boundaries.end.parent:null}[Symbol.iterator](){return this}skip(t){let e,i,n;do{n=this.position,({done:e,value:i}=this.next())}while(!e&&t(i));e||(this.position=n)}next(){return"forward"==this.direction?this._next():this._previous()}_next(){let t=this.position.clone();const e=this.position,i=t.parent;if(null===i.parent&&t.offset===i.childCount)return{done:!0};if(i===this._boundaryEndParent&&t.offset==this.boundaries.end.offset)return{done:!0};let n;if(i instanceof Ni){if(t.isAtEnd)return this.position=Xn._createAfter(i),this._next();n=i.data[t.offset]}else n=i.getChild(t.offset);if(n instanceof On)return this.shallow?t.offset++:t=new Xn(n,0),this.position=t,this._formatReturnValue("elementStart",n,e,t,1);if(n instanceof Ni){if(this.singleCharacters)return t=new Xn(n,0),this.position=t,this._next();{let i,o=n.data.length;return n==this._boundaryEndParent?(o=this.boundaries.end.offset,i=new Oi(n,0,o),t=Xn._createAfter(i)):(i=new Oi(n,0,n.data.length),t.offset++),this.position=t,this._formatReturnValue("text",i,e,t,o)}}if("string"==typeof n){let n;if(this.singleCharacters)n=1;else{n=(i===this._boundaryEndParent?this.boundaries.end.offset:i.data.length)-t.offset}const o=new Oi(i,t.offset,n);return t.offset+=n,this.position=t,this._formatReturnValue("text",o,e,t,n)}return t=Xn._createAfter(i),this.position=t,this.ignoreElementEnd?this._next():this._formatReturnValue("elementEnd",i,e,t)}_previous(){let t=this.position.clone();const e=this.position,i=t.parent;if(null===i.parent&&0===t.offset)return{done:!0};if(i==this._boundaryStartParent&&t.offset==this.boundaries.start.offset)return{done:!0};let n;if(i instanceof Ni){if(t.isAtStart)return this.position=Xn._createBefore(i),this._previous();n=i.data[t.offset-1]}else n=i.getChild(t.offset-1);if(n instanceof On)return this.shallow?(t.offset--,this.position=t,this._formatReturnValue("elementStart",n,e,t,1)):(t=new Xn(n,n.childCount),this.position=t,this.ignoreElementEnd?this._previous():this._formatReturnValue("elementEnd",n,e,t));if(n instanceof Ni){if(this.singleCharacters)return t=new Xn(n,n.data.length),this.position=t,this._previous();{let i,o=n.data.length;if(n==this._boundaryStartParent){const e=this.boundaries.start.offset;i=new Oi(n,e,n.data.length-e),o=i.data.length,t=Xn._createBefore(i)}else i=new Oi(n,0,n.data.length),t.offset--;return this.position=t,this._formatReturnValue("text",i,e,t,o)}}if("string"==typeof n){let n;if(this.singleCharacters)n=1;else{const e=i===this._boundaryStartParent?this.boundaries.start.offset:0;n=t.offset-e}t.offset-=n;const o=new Oi(i,t.offset,n);return this.position=t,this._formatReturnValue("text",o,e,t,n)}return t=Xn._createBefore(i),this.position=t,this._formatReturnValue("elementStart",i,e,t,1)}_formatReturnValue(t,e,i,n,o){return e instanceof Oi&&(e.offsetInText+e.data.length==e.textNode.data.length&&("forward"!=this.direction||this.boundaries&&this.boundaries.end.isEqual(this.position)?i=Xn._createAfter(e.textNode):(n=Xn._createAfter(e.textNode),this.position=n)),0===e.offsetInText&&("backward"!=this.direction||this.boundaries&&this.boundaries.start.isEqual(this.position)?i=Xn._createBefore(e.textNode):(n=Xn._createBefore(e.textNode),this.position=n))),{done:!1,value:{type:t,item:e,previousPosition:i,nextPosition:n,length:o}}}}class Xn{constructor(t,e){this.parent=t,this.offset=e}get nodeAfter(){return this.parent.is("text")?null:this.parent.getChild(this.offset)||null}get nodeBefore(){return this.parent.is("text")?null:this.parent.getChild(this.offset-1)||null}get isAtStart(){return 0===this.offset}get isAtEnd(){const t=this.parent.is("text")?this.parent.data.length:this.parent.childCount;return this.offset===t}get root(){return this.parent.root}get editableElement(){let t=this.parent;for(;!(t instanceof Qn);){if(!t.parent)return null;t=t.parent}return t}getShiftedBy(t){const e=Xn._createAt(this),i=e.offset+t;return e.offset=i<0?0:i,e}getLastMatchingPosition(t,e={}){e.startPosition=this;const i=new Zn(e);return i.skip(t),i.position}getAncestors(){return this.parent.is("documentFragment")?[this.parent]:this.parent.getAncestors({includeSelf:!0})}getCommonAncestor(t){const e=this.getAncestors(),i=t.getAncestors();let n=0;for(;e[n]==i[n]&&e[n];)n++;return 0===n?null:e[n-1]}is(t){return"position"==t||"view:position"==t}isEqual(t){return this.parent==t.parent&&this.offset==t.offset}isBefore(t){return"before"==this.compareWith(t)}isAfter(t){return"after"==this.compareWith(t)}compareWith(t){if(this.root!==t.root)return"different";if(this.isEqual(t))return"same";const e=this.parent.is("node")?this.parent.getPath():[],i=t.parent.is("node")?t.parent.getPath():[];e.push(this.offset),i.push(t.offset);const n=Ei(e,i);switch(n){case"prefix":return"before";case"extension":return"after";default:return e[n]<i[n]?"before":"after"}}getWalker(t={}){return t.startPosition=this,new Zn(t)}clone(){return new Xn(this.parent,this.offset)}static _createAt(t,e){if(t instanceof Xn)return new this(t.parent,t.offset);{const i=t;if("end"==e)e=i.is("text")?i.data.length:i.childCount;else{if("before"==e)return this._createBefore(i);if("after"==e)return this._createAfter(i);if(0!==e&&!e)throw new hi.b("view-createPositionAt-offset-required: View#createPositionAt() requires the offset when the first parameter is a view item.",i)}return new Xn(i,e)}}static _createAfter(t){if(t.is("textProxy"))return new Xn(t.textNode,t.offsetInText+t.data.length);if(!t.parent)throw new hi.b("view-position-after-root: You can not make position after root.",t,{root:t});return new Xn(t.parent,t.index+1)}static _createBefore(t){if(t.is("textProxy"))return new Xn(t.textNode,t.offsetInText);if(!t.parent)throw new hi.b("view-position-before-root: You can not make position before root.",t,{root:t});return new Xn(t.parent,t.index)}}class to{constructor(t,e=null){this.start=t.clone(),this.end=e?e.clone():t.clone()}*[Symbol.iterator](){yield*new Zn({boundaries:this,ignoreElementEnd:!0})}get isCollapsed(){return this.start.isEqual(this.end)}get isFlat(){return this.start.parent===this.end.parent}get root(){return this.start.root}getEnlarged(){let t=this.start.getLastMatchingPosition(eo,{direction:"backward"}),e=this.end.getLastMatchingPosition(eo);return t.parent.is("text")&&t.isAtStart&&(t=Xn._createBefore(t.parent)),e.parent.is("text")&&e.isAtEnd&&(e=Xn._createAfter(e.parent)),new to(t,e)}getTrimmed(){let t=this.start.getLastMatchingPosition(eo);if(t.isAfter(this.end)||t.isEqual(this.end))return new to(t,t);let e=this.end.getLastMatchingPosition(eo,{direction:"backward"});const i=t.nodeAfter,n=e.nodeBefore;return i&&i.is("text")&&(t=new Xn(i,0)),n&&n.is("text")&&(e=new Xn(n,n.data.length)),new to(t,e)}isEqual(t){return this==t||this.start.isEqual(t.start)&&this.end.isEqual(t.end)}containsPosition(t){return t.isAfter(this.start)&&t.isBefore(this.end)}containsRange(t,e=!1){t.isCollapsed&&(e=!1);const i=this.containsPosition(t.start)||e&&this.start.isEqual(t.start),n=this.containsPosition(t.end)||e&&this.end.isEqual(t.end);return i&&n}getDifference(t){const e=[];return this.isIntersecting(t)?(this.containsPosition(t.start)&&e.push(new to(this.start,t.start)),this.containsPosition(t.end)&&e.push(new to(t.end,this.end))):e.push(this.clone()),e}getIntersection(t){if(this.isIntersecting(t)){let e=this.start,i=this.end;return this.containsPosition(t.start)&&(e=t.start),this.containsPosition(t.end)&&(i=t.end),new to(e,i)}return null}getWalker(t={}){return t.boundaries=this,new Zn(t)}getCommonAncestor(){return this.start.getCommonAncestor(this.end)}clone(){return new to(this.start,this.end)}*getItems(t={}){t.boundaries=this,t.ignoreElementEnd=!0;const e=new Zn(t);for(const t of e)yield t.item}*getPositions(t={}){t.boundaries=this;const e=new Zn(t);yield e.position;for(const t of e)yield t.nextPosition}is(t){return"range"==t||"view:range"==t}isIntersecting(t){return this.start.isBefore(t.end)&&this.end.isAfter(t.start)}static _createFromParentsAndOffsets(t,e,i,n){return new this(new Xn(t,e),new Xn(i,n))}static _createFromPositionAndShift(t,e){const i=t,n=t.getShiftedBy(e);return e>0?new this(i,n):new this(n,i)}static _createIn(t){return this._createFromParentsAndOffsets(t,0,t,t.childCount)}static _createOn(t){const e=t.is("textProxy")?t.offsetSize:1;return this._createFromPositionAndShift(Xn._createBefore(t),e)}}function eo(t){return!(!t.item.is("attributeElement")&&!t.item.is("uiElement"))}function io(t){let e=0;for(const i of t)e++;return e}class no{constructor(t=null,e,i){this._ranges=[],this._lastRangeBackward=!1,this._isFake=!1,this._fakeSelectionLabel="",this.setTo(t,e,i)}get isFake(){return this._isFake}get fakeSelectionLabel(){return this._fakeSelectionLabel}get anchor(){if(!this._ranges.length)return null;const t=this._ranges[this._ranges.length-1];return(this._lastRangeBackward?t.end:t.start).clone()}get focus(){if(!this._ranges.length)return null;const t=this._ranges[this._ranges.length-1];return(this._lastRangeBackward?t.start:t.end).clone()}get isCollapsed(){return 1===this.rangeCount&&this._ranges[0].isCollapsed}get rangeCount(){return this._ranges.length}get isBackward(){return!this.isCollapsed&&this._lastRangeBackward}get editableElement(){return this.anchor?this.anchor.editableElement:null}*getRanges(){for(const t of this._ranges)yield t.clone()}getFirstRange(){let t=null;for(const e of this._ranges)t&&!e.start.isBefore(t.start)||(t=e);return t?t.clone():null}getLastRange(){let t=null;for(const e of this._ranges)t&&!e.end.isAfter(t.end)||(t=e);return t?t.clone():null}getFirstPosition(){const t=this.getFirstRange();return t?t.start.clone():null}getLastPosition(){const t=this.getLastRange();return t?t.end.clone():null}isEqual(t){if(this.isFake!=t.isFake)return!1;if(this.isFake&&this.fakeSelectionLabel!=t.fakeSelectionLabel)return!1;if(this.rangeCount!=t.rangeCount)return!1;if(0===this.rangeCount)return!0;if(!this.anchor.isEqual(t.anchor)||!this.focus.isEqual(t.focus))return!1;for(const e of this._ranges){let i=!1;for(const n of t._ranges)if(e.isEqual(n)){i=!0;break}if(!i)return!1}return!0}isSimilar(t){if(this.isBackward!=t.isBackward)return!1;const e=io(this.getRanges());if(e!=io(t.getRanges()))return!1;if(0==e)return!0;for(let e of this.getRanges()){e=e.getTrimmed();let i=!1;for(let n of t.getRanges())if(n=n.getTrimmed(),e.start.isEqual(n.start)&&e.end.isEqual(n.end)){i=!0;break}if(!i)return!1}return!0}getSelectedElement(){if(1!==this.rangeCount)return null;const t=this.getFirstRange();let e=t.start.nodeAfter,i=t.end.nodeBefore;return t.start.parent.is("text")&&t.start.isAtEnd&&t.start.parent.nextSibling&&(e=t.start.parent.nextSibling),t.end.parent.is("text")&&t.end.isAtStart&&t.end.parent.previousSibling&&(i=t.end.parent.previousSibling),e instanceof On&&e==i?e:null}setTo(t,e,i){if(null===t)this._setRanges([]),this._setFakeOptions(e);else if(t instanceof no||t instanceof oo)this._setRanges(t.getRanges(),t.isBackward),this._setFakeOptions({fake:t.isFake,label:t.fakeSelectionLabel});else if(t instanceof to)this._setRanges([t],e&&e.backward),this._setFakeOptions(e);else if(t instanceof Xn)this._setRanges([new to(t)]),this._setFakeOptions(e);else if(t instanceof Ii){const n=!!i&&!!i.backward;let o;if(void 0===e)throw new hi.b("view-selection-setTo-required-second-parameter: selection.setTo requires the second parameter when the first parameter is a node.",this);o="in"==e?to._createIn(t):"on"==e?to._createOn(t):new to(Xn._createAt(t,e)),this._setRanges([o],n),this._setFakeOptions(i)}else{if(!Ri(t))throw new hi.b("view-selection-setTo-not-selectable: Cannot set selection to given place.",this);this._setRanges(t,e&&e.backward),this._setFakeOptions(e)}this.fire("change")}setFocus(t,e){if(null===this.anchor)throw new hi.b("view-selection-setFocus-no-ranges: Cannot set selection focus if there are no ranges in selection.",this);const i=Xn._createAt(t,e);if("same"==i.compareWith(this.focus))return;const n=this.anchor;this._ranges.pop(),"before"==i.compareWith(n)?this._addRange(new to(i,n),!0):this._addRange(new to(n,i)),this.fire("change")}is(t){return"selection"==t||"view:selection"==t}_setRanges(t,e=!1){t=Array.from(t),this._ranges=[];for(const e of t)this._addRange(e);this._lastRangeBackward=!!e}_setFakeOptions(t={}){this._isFake=!!t.fake,this._fakeSelectionLabel=t.fake&&t.label||""}_addRange(t,e=!1){if(!(t instanceof to))throw new hi.b("view-selection-add-range-not-range: Selection range set to an object that is not an instance of view.Range",this);this._pushRange(t),this._lastRangeBackward=!!e}_pushRange(t){for(const e of this._ranges)if(t.isIntersecting(e))throw new hi.b("view-selection-range-intersects: Trying to add a range that intersects with another range from selection.",this,{addedRange:t,intersectingRange:e});this._ranges.push(new to(t.start,t.end))}}vi(no,mi);class oo{constructor(t=null,e,i){this._selection=new no,this._selection.delegate("change").to(this),this._selection.setTo(t,e,i)}get isFake(){return this._selection.isFake}get fakeSelectionLabel(){return this._selection.fakeSelectionLabel}get anchor(){return this._selection.anchor}get focus(){return this._selection.focus}get isCollapsed(){return this._selection.isCollapsed}get rangeCount(){return this._selection.rangeCount}get isBackward(){return this._selection.isBackward}get editableElement(){return this._selection.editableElement}get _ranges(){return this._selection._ranges}*getRanges(){yield*this._selection.getRanges()}getFirstRange(){return this._selection.getFirstRange()}getLastRange(){return this._selection.getLastRange()}getFirstPosition(){return this._selection.getFirstPosition()}getLastPosition(){return this._selection.getLastPosition()}getSelectedElement(){return this._selection.getSelectedElement()}isEqual(t){return this._selection.isEqual(t)}isSimilar(t){return this._selection.isSimilar(t)}is(t){return"selection"==t||"documentSelection"==t||"view:selection"==t||"view:documentSelection"==t}_setTo(t,e,i){this._selection.setTo(t,e,i)}_setFocus(t,e){this._selection.setFocus(t,e)}}vi(oo,mi);class so{constructor(){this.selection=new oo,this.roots=new yi({idProperty:"rootName"}),this.set("isReadOnly",!1),this.set("isFocused",!1),this.set("isComposing",!1),this._postFixers=new Set}getRoot(t="main"){return this.roots.get(t)}registerPostFixer(t){this._postFixers.add(t)}destroy(){this.roots.map(t=>t.destroy()),this.stopListening()}addStyleProcessorRules(t){t(En._styleProcessor)}_callPostFixers(t){let e=!1;do{for(const i of this._postFixers)if(e=i(t),e)break}while(e)}}vi(so,Hn);class ro extends On{constructor(t,e,i){super(t,e,i),this.getFillerOffset=ao,this._priority=10,this._id=null,this._clonesGroup=null}get priority(){return this._priority}get id(){return this._id}getElementsWithSameId(){if(null===this.id)throw new hi.b("attribute-element-get-elements-with-same-id-no-id: Cannot get elements with the same id for an attribute element without id.",this);return new Set(this._clonesGroup)}is(t,e=null){const i=t&&t.replace(/^view:/,"");return e?"attributeElement"==i&&e==this.name||super.is(t,e):"attributeElement"==i||super.is(t)}isSimilar(t){return null!==this.id||null!==t.id?this.id===t.id:super.isSimilar(t)&&this.priority==t.priority}_clone(t){const e=super._clone(t);return e._priority=this._priority,e._id=this._id,e}}function ao(){if(co(this))return null;let t=this.parent;for(;t&&t.is("attributeElement");){if(co(t)>1)return null;t=t.parent}return!t||co(t)>1?null:this.childCount}function co(t){return Array.from(t.getChildren()).filter(t=>!t.is("uiElement")).length}ro.DEFAULT_PRIORITY=10;class lo extends On{constructor(t,e,i){super(t,e,i),this.getFillerOffset=ho}is(t,e=null){const i=t.replace(/^view:/,"");return e?"emptyElement"==i&&e==this.name||super.is(t,e):"emptyElement"==i||super.is(t)}_insertChild(t,e){if(e&&(e instanceof Ii||Array.from(e).length>0))throw new hi.b("view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.",[this,e])}}function ho(){return null}const uo=navigator.userAgent.toLowerCase();var fo={isMac:function(t){return t.indexOf("macintosh")>-1}(uo),isEdge:function(t){return!!t.match(/edge\/(\d+.?\d*)/)}(uo),isGecko:function(t){return!!t.match(/gecko\/\d+/)}(uo),isSafari:function(t){return t.indexOf(" applewebkit/")>-1&&-1===t.indexOf("chrome")}(uo),isAndroid:function(t){return t.indexOf("android")>-1}(uo),features:{isRegExpUnicodePropertySupported:function(){let t=!1;try{t=0==="ć".search(new RegExp("[\\p{L}]","u"))}catch(t){}return t}()}};const mo={"⌘":"ctrl","⇧":"shift","⌥":"alt"},go={ctrl:"⌘",shift:"⇧",alt:"⌥"},po=function(){const t={arrowleft:37,arrowup:38,arrowright:39,arrowdown:40,backspace:8,delete:46,enter:13,space:32,esc:27,tab:9,ctrl:1114112,cmd:1114112,shift:2228224,alt:4456448};for(let e=65;e<=90;e++){const i=String.fromCharCode(e);t[i.toLowerCase()]=e}for(let e=48;e<=57;e++)t[e-48]=e;for(let e=112;e<=123;e++)t["f"+(e-111)]=e;return t}();function bo(t){let e;if("string"==typeof t){if(e=po[t.toLowerCase()],!e)throw new hi.b("keyboard-unknown-key: Unknown key name.",null,{key:t})}else e=t.keyCode+(t.altKey?po.alt:0)+(t.ctrlKey?po.ctrl:0)+(t.shiftKey?po.shift:0);return e}function wo(t){return"string"==typeof t&&(t=_o(t)),t.map(t=>"string"==typeof t?bo(t):t).reduce((t,e)=>e+t,0)}function ko(t){return fo.isMac?_o(t).map(t=>go[t.toLowerCase()]||t).reduce((t,e)=>t.slice(-1)in mo?t+e:t+"+"+e):t}function _o(t){return t.split(/\s*\+\s*/)}class vo extends On{constructor(t,e,i){super(t,e,i),this.getFillerOffset=xo}is(t,e=null){const i=t.replace(/^view:/,"");return e?"uiElement"==i&&e==this.name||super.is(t,e):"uiElement"==i||super.is(t)}_insertChild(t,e){if(e&&(e instanceof Ii||Array.from(e).length>0))throw new hi.b("view-uielement-cannot-add: Cannot add child nodes to UIElement instance.",this)}render(t){return this.toDomElement(t)}toDomElement(t){const e=t.createElement(this.name);for(const t of this.getAttributeKeys())e.setAttribute(t,this.getAttribute(t));return e}}function yo(t){t.document.on("keydown",(e,i)=>function(t,e,i){if(e.keyCode==po.arrowright){const t=e.domTarget.ownerDocument.defaultView.getSelection(),n=1==t.rangeCount&&t.getRangeAt(0).collapsed;if(n||e.shiftKey){const e=t.focusNode,o=t.focusOffset,s=i.domPositionToView(e,o);if(null===s)return;let r=!1;const a=s.getLastMatchingPosition(t=>(t.item.is("uiElement")&&(r=!0),!(!t.item.is("uiElement")&&!t.item.is("attributeElement"))));if(r){const e=i.viewPositionToDom(a);n?t.collapse(e.parent,e.offset):t.extend(e.parent,e.offset)}}}}(0,i,t.domConverter))}function xo(){return null}class Ao{constructor(t){this._children=[],t&&this._insertChild(0,t)}[Symbol.iterator](){return this._children[Symbol.iterator]()}get childCount(){return this._children.length}get isEmpty(){return 0===this.childCount}get root(){return this}get parent(){return null}is(t){return"documentFragment"==t||"view:documentFragment"==t}_appendChild(t){return this._insertChild(this.childCount,t)}getChild(t){return this._children[t]}getChildIndex(t){return this._children.indexOf(t)}getChildren(){return this._children[Symbol.iterator]()}_insertChild(t,e){this._fireChange("children",this);let i=0;const n=function(t){if("string"==typeof t)return[new Ni(t)];Ri(t)||(t=[t]);return Array.from(t).map(t=>"string"==typeof t?new Ni(t):t instanceof Oi?new Ni(t.data):t)}(e);for(const e of n)null!==e.parent&&e._remove(),e.parent=this,this._children.splice(t,0,e),t++,i++;return i}_removeChildren(t,e=1){this._fireChange("children",this);for(let i=t;i<t+e;i++)this._children[i].parent=null;return this._children.splice(t,e)}_fireChange(t,e){this.fire("change:"+t,e)}}vi(Ao,mi);class Co{constructor(t){this.document=t,this._cloneGroups=new Map}setSelection(t,e,i){this.document.selection._setTo(t,e,i)}setSelectionFocus(t,e){this.document.selection._setFocus(t,e)}createText(t){return new Ni(t)}createAttributeElement(t,e,i={}){const n=new ro(t,e);return i.priority&&(n._priority=i.priority),i.id&&(n._id=i.id),n}createContainerElement(t,e){return new Ln(t,e)}createEditableElement(t,e){const i=new Qn(t,e);return i._document=this.document,i}createEmptyElement(t,e){return new lo(t,e)}createUIElement(t,e,i){const n=new vo(t,e);return i&&(n.render=i),n}setAttribute(t,e,i){i._setAttribute(t,e)}removeAttribute(t,e){e._removeAttribute(t)}addClass(t,e){e._addClass(t)}removeClass(t,e){e._removeClass(t)}setStyle(t,e,i){y(t)&&void 0===i&&(i=e),i._setStyle(t,e)}removeStyle(t,e){e._removeStyle(t)}setCustomProperty(t,e,i){i._setCustomProperty(t,e)}removeCustomProperty(t,e){return e._removeCustomProperty(t)}breakAttributes(t){return t instanceof Xn?this._breakAttributes(t):this._breakAttributesRange(t)}breakContainer(t){const e=t.parent;if(!e.is("containerElement"))throw new hi.b("view-writer-break-non-container-element: Trying to break an element which is not a container element.",this.document);if(!e.parent)throw new hi.b("view-writer-break-root: Trying to break root element.",this.document);if(t.isAtStart)return Xn._createBefore(e);if(!t.isAtEnd){const i=e._clone(!1);this.insert(Xn._createAfter(e),i);const n=new to(t,Xn._createAt(e,"end")),o=new Xn(i,0);this.move(n,o)}return Xn._createAfter(e)}mergeAttributes(t){const e=t.offset,i=t.parent;if(i.is("text"))return t;if(i.is("attributeElement")&&0===i.childCount){const t=i.parent,e=i.index;return i._remove(),this._removeFromClonedElementsGroup(i),this.mergeAttributes(new Xn(t,e))}const n=i.getChild(e-1),o=i.getChild(e);if(!n||!o)return t;if(n.is("text")&&o.is("text"))return Mo(n,o);if(n.is("attributeElement")&&o.is("attributeElement")&&n.isSimilar(o)){const t=n.childCount;return n._appendChild(o.getChildren()),o._remove(),this._removeFromClonedElementsGroup(o),this.mergeAttributes(new Xn(n,t))}return t}mergeContainers(t){const e=t.nodeBefore,i=t.nodeAfter;if(!(e&&i&&e.is("containerElement")&&i.is("containerElement")))throw new hi.b("view-writer-merge-containers-invalid-position: Element before and after given position cannot be merged.",this.document);const n=e.getChild(e.childCount-1),o=n instanceof Ni?Xn._createAt(n,"end"):Xn._createAt(e,"end");return this.move(to._createIn(i),Xn._createAt(e,"end")),this.remove(to._createOn(i)),o}insert(t,e){(function t(e,i){for(const n of e){if(!Io.some(t=>n instanceof t))throw new hi.b("view-writer-insert-invalid-node",i);n.is("text")||t(n.getChildren(),i)}})(e=Ri(e)?[...e]:[e],this.document);const i=To(t);if(!i)throw new hi.b("view-writer-invalid-position-container",this.document);const n=this._breakAttributes(t,!0),o=i._insertChild(n.offset,e);for(const t of e)this._addToClonedElementsGroup(t);const s=n.getShiftedBy(o),r=this.mergeAttributes(n);if(0===o)return new to(r,r);{r.isEqual(n)||s.offset--;const t=this.mergeAttributes(s);return new to(r,t)}}remove(t){const e=t instanceof to?t:to._createOn(t);if(Oo(e,this.document),e.isCollapsed)return new Ao;const{start:i,end:n}=this._breakAttributesRange(e,!0),o=i.parent,s=n.offset-i.offset,r=o._removeChildren(i.offset,s);for(const t of r)this._removeFromClonedElementsGroup(t);const a=this.mergeAttributes(i);return e.start=a,e.end=a.clone(),new Ao(r)}clear(t,e){Oo(t,this.document);const i=t.getWalker({direction:"backward",ignoreElementEnd:!0});for(const n of i){const i=n.item;let o;if(i.is("element")&&e.isSimilar(i))o=to._createOn(i);else if(!n.nextPosition.isAfter(t.start)&&i.is("textProxy")){const t=i.getAncestors().find(t=>t.is("element")&&e.isSimilar(t));t&&(o=to._createIn(t))}o&&(o.end.isAfter(t.end)&&(o.end=t.end),o.start.isBefore(t.start)&&(o.start=t.start),this.remove(o))}}move(t,e){let i;if(e.isAfter(t.end)){const n=(e=this._breakAttributes(e,!0)).parent,o=n.childCount;t=this._breakAttributesRange(t,!0),i=this.remove(t),e.offset+=n.childCount-o}else i=this.remove(t);return this.insert(e,i)}wrap(t,e){if(!(e instanceof ro))throw new hi.b("view-writer-wrap-invalid-attribute",this.document);if(Oo(t,this.document),t.isCollapsed){let n=t.start;n.parent.is("element")&&(i=n.parent,!Array.from(i.getChildren()).some(t=>!t.is("uiElement")))&&(n=n.getLastMatchingPosition(t=>t.item.is("uiElement"))),n=this._wrapPosition(n,e);const o=this.document.selection;return o.isCollapsed&&o.getFirstPosition().isEqual(t.start)&&this.setSelection(n),new to(n)}return this._wrapRange(t,e);var i}unwrap(t,e){if(!(e instanceof ro))throw new hi.b("view-writer-unwrap-invalid-attribute",this.document);if(Oo(t,this.document),t.isCollapsed)return t;const{start:i,end:n}=this._breakAttributesRange(t,!0),o=i.parent,s=this._unwrapChildren(o,i.offset,n.offset,e),r=this.mergeAttributes(s.start);r.isEqual(s.start)||s.end.offset--;const a=this.mergeAttributes(s.end);return new to(r,a)}rename(t,e){const i=new Ln(t,e.getAttributes());return this.insert(Xn._createAfter(e),i),this.move(to._createIn(e),Xn._createAt(i,0)),this.remove(to._createOn(e)),i}clearClonedElementsGroup(t){this._cloneGroups.delete(t)}createPositionAt(t,e){return Xn._createAt(t,e)}createPositionAfter(t){return Xn._createAfter(t)}createPositionBefore(t){return Xn._createBefore(t)}createRange(t,e){return new to(t,e)}createRangeOn(t){return to._createOn(t)}createRangeIn(t){return to._createIn(t)}createSelection(t,e,i){return new no(t,e,i)}_wrapChildren(t,e,i,n){let o=e;const s=[];for(;o<i;){const e=t.getChild(o),i=e.is("text"),r=e.is("attributeElement"),a=e.is("emptyElement"),c=e.is("uiElement");if(r&&this._wrapAttributeElement(n,e))s.push(new Xn(t,o));else if(i||a||c||r&&Po(n,e)){const i=n._clone();e._remove(),i._appendChild(e),t._insertChild(o,i),this._addToClonedElementsGroup(i),s.push(new Xn(t,o))}else r&&this._wrapChildren(e,0,e.childCount,n);o++}let r=0;for(const t of s){if(t.offset-=r,t.offset==e)continue;this.mergeAttributes(t).isEqual(t)||(r++,i--)}return to._createFromParentsAndOffsets(t,e,t,i)}_unwrapChildren(t,e,i,n){let o=e;const s=[];for(;o<i;){const e=t.getChild(o);if(e.is("attributeElement"))if(e.isSimilar(n)){const n=e.getChildren(),r=e.childCount;e._remove(),t._insertChild(o,n),this._removeFromClonedElementsGroup(e),s.push(new Xn(t,o),new Xn(t,o+r)),o+=r,i+=r-1}else this._unwrapAttributeElement(n,e)?(s.push(new Xn(t,o),new Xn(t,o+1)),o++):(this._unwrapChildren(e,0,e.childCount,n),o++);else o++}let r=0;for(const t of s){if(t.offset-=r,t.offset==e||t.offset==i)continue;this.mergeAttributes(t).isEqual(t)||(r++,i--)}return to._createFromParentsAndOffsets(t,e,t,i)}_wrapRange(t,e){const{start:i,end:n}=this._breakAttributesRange(t,!0),o=i.parent,s=this._wrapChildren(o,i.offset,n.offset,e),r=this.mergeAttributes(s.start);r.isEqual(s.start)||s.end.offset--;const a=this.mergeAttributes(s.end);return new to(r,a)}_wrapPosition(t,e){if(e.isSimilar(t.parent))return So(t.clone());t.parent.is("text")&&(t=Eo(t));const i=this.createAttributeElement();i._priority=Number.POSITIVE_INFINITY,i.isSimilar=()=>!1,t.parent._insertChild(t.offset,i);const n=new to(t,t.getShiftedBy(1));this.wrap(n,e);const o=new Xn(i.parent,i.index);i._remove();const s=o.nodeBefore,r=o.nodeAfter;return s instanceof Ni&&r instanceof Ni?Mo(s,r):So(o)}_wrapAttributeElement(t,e){if(!Ro(t,e))return!1;if(t.name!==e.name||t.priority!==e.priority)return!1;for(const i of t.getAttributeKeys())if("class"!==i&&"style"!==i&&e.hasAttribute(i)&&e.getAttribute(i)!==t.getAttribute(i))return!1;for(const i of t.getStyleNames())if(e.hasStyle(i)&&e.getStyle(i)!==t.getStyle(i))return!1;for(const i of t.getAttributeKeys())"class"!==i&&"style"!==i&&(e.hasAttribute(i)||this.setAttribute(i,t.getAttribute(i),e));for(const i of t.getStyleNames())e.hasStyle(i)||this.setStyle(i,t.getStyle(i),e);for(const i of t.getClassNames())e.hasClass(i)||this.addClass(i,e);return!0}_unwrapAttributeElement(t,e){if(!Ro(t,e))return!1;if(t.name!==e.name||t.priority!==e.priority)return!1;for(const i of t.getAttributeKeys())if("class"!==i&&"style"!==i&&(!e.hasAttribute(i)||e.getAttribute(i)!==t.getAttribute(i)))return!1;if(!e.hasClass(...t.getClassNames()))return!1;for(const i of t.getStyleNames())if(!e.hasStyle(i)||e.getStyle(i)!==t.getStyle(i))return!1;for(const i of t.getAttributeKeys())"class"!==i&&"style"!==i&&this.removeAttribute(i,e);return this.removeClass(Array.from(t.getClassNames()),e),this.removeStyle(Array.from(t.getStyleNames()),e),!0}_breakAttributesRange(t,e=!1){const i=t.start,n=t.end;if(Oo(t,this.document),t.isCollapsed){const i=this._breakAttributes(t.start,e);return new to(i,i)}const o=this._breakAttributes(n,e),s=o.parent.childCount,r=this._breakAttributes(i,e);return o.offset+=o.parent.childCount-s,new to(r,o)}_breakAttributes(t,e=!1){const i=t.offset,n=t.parent;if(t.parent.is("emptyElement"))throw new hi.b("view-writer-cannot-break-empty-element",this.document);if(t.parent.is("uiElement"))throw new hi.b("view-writer-cannot-break-ui-element",this.document);if(!e&&n.is("text")&&No(n.parent))return t.clone();if(No(n))return t.clone();if(n.is("text"))return this._breakAttributes(Eo(t),e);if(i==n.childCount){const t=new Xn(n.parent,n.index+1);return this._breakAttributes(t,e)}if(0===i){const t=new Xn(n.parent,n.index);return this._breakAttributes(t,e)}{const t=n.index+1,o=n._clone();n.parent._insertChild(t,o),this._addToClonedElementsGroup(o);const s=n.childCount-i,r=n._removeChildren(i,s);o._appendChild(r);const a=new Xn(n.parent,t);return this._breakAttributes(a,e)}}_addToClonedElementsGroup(t){if(!t.root.is("rootElement"))return;if(t.is("element"))for(const e of t.getChildren())this._addToClonedElementsGroup(e);const e=t.id;if(!e)return;let i=this._cloneGroups.get(e);i||(i=new Set,this._cloneGroups.set(e,i)),i.add(t),t._clonesGroup=i}_removeFromClonedElementsGroup(t){if(t.is("element"))for(const e of t.getChildren())this._removeFromClonedElementsGroup(e);const e=t.id;if(!e)return;const i=this._cloneGroups.get(e);i&&i.delete(t)}}function To(t){let e=t.parent;for(;!No(e);){if(!e)return;e=e.parent}return e}function Po(t,e){return t.priority<e.priority||!(t.priority>e.priority)&&t.getIdentity()<e.getIdentity()}function So(t){const e=t.nodeBefore;if(e&&e.is("text"))return new Xn(e,e.data.length);const i=t.nodeAfter;return i&&i.is("text")?new Xn(i,0):t}function Eo(t){if(t.offset==t.parent.data.length)return new Xn(t.parent.parent,t.parent.index+1);if(0===t.offset)return new Xn(t.parent.parent,t.parent.index);const e=t.parent.data.slice(t.offset);return t.parent._data=t.parent.data.slice(0,t.offset),t.parent.parent._insertChild(t.parent.index+1,new Ni(e)),new Xn(t.parent.parent,t.parent.index+1)}function Mo(t,e){const i=t.data.length;return t._data+=e.data,e._remove(),new Xn(t,i)}const Io=[Ni,ro,Ln,lo,vo];function No(t){return t&&(t.is("containerElement")||t.is("documentFragment"))}function Oo(t,e){const i=To(t.start),n=To(t.end);if(!i||!n||i!==n)throw new hi.b("view-writer-invalid-range-container",e)}function Ro(t,e){return null===t.id&&null===e.id}function Lo(t){return"[object Text]"==Object.prototype.toString.call(t)}const Do=t=>t.createTextNode(" "),zo=t=>{const e=t.createElement("br");return e.dataset.ckeFiller=!0,e},jo=(()=>{let t="";for(let e=0;e<7;e++)t+="";return t})();function Vo(t){return Lo(t)&&t.data.substr(0,7)===jo}function Bo(t){return 7==t.data.length&&Vo(t)}function Fo(t){return Vo(t)?t.data.slice(7):t.data}function Ho(t,e){if(e.keyCode==po.arrowleft){const t=e.domTarget.ownerDocument.defaultView.getSelection();if(1==t.rangeCount&&t.getRangeAt(0).collapsed){const e=t.getRangeAt(0).startContainer,i=t.getRangeAt(0).startOffset;Vo(e)&&i<=7&&t.collapse(e,0)}}}function Uo(t,e,i,n=!1){i=i||function(t,e){return t===e},Array.isArray(t)||(t=Array.from(t)),Array.isArray(e)||(e=Array.from(e));const o=function(t,e,i){const n=Wo(t,e,i);if(-1===n)return{firstIndex:-1,lastIndexOld:-1,lastIndexNew:-1};const o=qo(t,n),s=qo(e,n),r=Wo(o,s,i),a=t.length-r,c=e.length-r;return{firstIndex:n,lastIndexOld:a,lastIndexNew:c}}(t,e,i);return n?function(t,e){const{firstIndex:i,lastIndexOld:n,lastIndexNew:o}=t;if(-1===i)return Array(e).fill("equal");let s=[];i>0&&(s=s.concat(Array(i).fill("equal")));o-i>0&&(s=s.concat(Array(o-i).fill("insert")));n-i>0&&(s=s.concat(Array(n-i).fill("delete")));o<e&&(s=s.concat(Array(e-o).fill("equal")));return s}(o,e.length):function(t,e){const i=[],{firstIndex:n,lastIndexOld:o,lastIndexNew:s}=e;s-n>0&&i.push({index:n,type:"insert",values:t.slice(n,s)});o-n>0&&i.push({index:n+(s-n),type:"delete",howMany:o-n});return i}(e,o)}function Wo(t,e,i){for(let n=0;n<Math.max(t.length,e.length);n++)if(void 0===t[n]||void 0===e[n]||!i(t[n],e[n]))return n;return-1}function qo(t,e){return t.slice(e).reverse()}function $o(t,e,i){i=i||function(t,e){return t===e};const n=t.length,o=e.length;if(n>200||o>200||n+o>300)return $o.fastDiff(t,e,i,!0);let s,r;if(o<n){const i=t;t=e,e=i,s="delete",r="insert"}else s="insert",r="delete";const a=t.length,c=e.length,l=c-a,d={},h={};function u(n){const o=(void 0!==h[n-1]?h[n-1]:-1)+1,l=void 0!==h[n+1]?h[n+1]:-1,u=o>l?-1:1;d[n+u]&&(d[n]=d[n+u].slice(0)),d[n]||(d[n]=[]),d[n].push(o>l?s:r);let f=Math.max(o,l),m=f-n;for(;m<a&&f<c&&i(t[m],e[f]);)m++,f++,d[n].push("equal");return f}let f,m=0;do{for(f=-m;f<l;f++)h[f]=u(f);for(f=l+m;f>l;f--)h[f]=u(f);h[l]=u(l),m++}while(h[l]!==c);return d[l].slice(1)}function Yo(t,e,i){t.insertBefore(i,t.childNodes[e]||null)}function Go(t){const e=t.parentNode;e&&e.removeChild(t)}function Qo(t){if(t){if(t.defaultView)return t instanceof t.defaultView.Document;if(t.ownerDocument&&t.ownerDocument.defaultView)return t instanceof t.ownerDocument.defaultView.Node}return!1}$o.fastDiff=Uo;class Ko{constructor(t,e){this.domDocuments=new Set,this.domConverter=t,this.markedAttributes=new Set,this.markedChildren=new Set,this.markedTexts=new Set,this.selection=e,this.isFocused=!1,this._inlineFiller=null,this._fakeSelectionContainer=null}markToSync(t,e){if("text"===t)this.domConverter.mapViewToDom(e.parent)&&this.markedTexts.add(e);else{if(!this.domConverter.mapViewToDom(e))return;if("attributes"===t)this.markedAttributes.add(e);else{if("children"!==t)throw new hi.b("view-engine-unknown-type: Unknown type passed to Renderer.markToSync.",this);this.markedChildren.add(e)}}}render(){let t;for(const t of this.markedChildren)this._updateChildrenMappings(t);this._inlineFiller&&!this._isSelectionInInlineFiller()&&this._removeInlineFiller(),this._inlineFiller?t=this._getInlineFillerPosition():this._needsInlineFillerAtSelection()&&(t=this.selection.getFirstPosition(),this.markedChildren.add(t.parent));for(const t of this.markedAttributes)this._updateAttrs(t);for(const e of this.markedChildren)this._updateChildren(e,{inlineFillerPosition:t});for(const e of this.markedTexts)!this.markedChildren.has(e.parent)&&this.domConverter.mapViewToDom(e.parent)&&this._updateText(e,{inlineFillerPosition:t});if(t){const e=this.domConverter.viewPositionToDom(t),i=e.parent.ownerDocument;Vo(e.parent)?this._inlineFiller=e.parent:this._inlineFiller=Jo(i,e.parent,e.offset)}else this._inlineFiller=null;this._updateSelection(),this._updateFocus(),this.markedTexts.clear(),this.markedAttributes.clear(),this.markedChildren.clear()}_updateChildrenMappings(t){const e=this.domConverter.mapViewToDom(t);if(!e)return;const i=this.domConverter.mapViewToDom(t).childNodes,n=Array.from(this.domConverter.viewChildrenToDom(t,e.ownerDocument,{withChildren:!1})),o=this._diffNodeLists(i,n),s=this._findReplaceActions(o,i,n);if(-1!==s.indexOf("replace")){const e={equal:0,insert:0,delete:0};for(const o of s)if("replace"===o){const o=e.equal+e.insert,s=e.equal+e.delete,r=t.getChild(o);r&&!r.is("uiElement")&&this._updateElementMappings(r,i[s]),Go(n[o]),e.equal++}else e[o]++}}_updateElementMappings(t,e){this.domConverter.unbindDomElement(e),this.domConverter.bindElements(e,t),this.markedChildren.add(t),this.markedAttributes.add(t)}_getInlineFillerPosition(){const t=this.selection.getFirstPosition();return t.parent.is("text")?Xn._createBefore(this.selection.getFirstPosition().parent):t}_isSelectionInInlineFiller(){if(1!=this.selection.rangeCount||!this.selection.isCollapsed)return!1;const t=this.selection.getFirstPosition(),e=this.domConverter.viewPositionToDom(t);return!!(e&&Lo(e.parent)&&Vo(e.parent))}_removeInlineFiller(){const t=this._inlineFiller;if(!Vo(t))throw new hi.b("view-engine-filler-was-lost: The inline filler node was lost.",this);Bo(t)?t.parentNode.removeChild(t):t.data=t.data.substr(7),this._inlineFiller=null}_needsInlineFillerAtSelection(){if(1!=this.selection.rangeCount||!this.selection.isCollapsed)return!1;const t=this.selection.getFirstPosition(),e=t.parent,i=t.offset;if(!this.domConverter.mapViewToDom(e.root))return!1;if(!e.is("element"))return!1;if(!function(t){if("false"==t.getAttribute("contenteditable"))return!1;const e=t.findAncestor(t=>t.hasAttribute("contenteditable"));return!e||"true"==e.getAttribute("contenteditable")}(e))return!1;if(i===e.getFillerOffset())return!1;const n=t.nodeBefore,o=t.nodeAfter;return!(n instanceof Ni||o instanceof Ni)}_updateText(t,e){const i=this.domConverter.findCorrespondingDomText(t),n=this.domConverter.viewToDom(t,i.ownerDocument),o=i.data;let s=n.data;const r=e.inlineFillerPosition;if(r&&r.parent==t.parent&&r.offset==t.index&&(s=jo+s),o!=s){const t=Uo(o,s);for(const e of t)"insert"===e.type?i.insertData(e.index,e.values.join("")):i.deleteData(e.index,e.howMany)}}_updateAttrs(t){const e=this.domConverter.mapViewToDom(t);if(!e)return;const i=Array.from(e.attributes).map(t=>t.name),n=t.getAttributeKeys();for(const i of n)e.setAttribute(i,t.getAttribute(i));for(const n of i)t.hasAttribute(n)||e.removeAttribute(n)}_updateChildren(t,e){const i=this.domConverter.mapViewToDom(t);if(!i)return;const n=e.inlineFillerPosition,o=this.domConverter.mapViewToDom(t).childNodes,s=Array.from(this.domConverter.viewChildrenToDom(t,i.ownerDocument,{bind:!0,inlineFillerPosition:n}));n&&n.parent===t&&Jo(i.ownerDocument,s,n.offset);const r=this._diffNodeLists(o,s);let a=0;const c=new Set;for(const t of r)"insert"===t?(Yo(i,a,s[a]),a++):"delete"===t?(c.add(o[a]),Go(o[a])):(this._markDescendantTextToSync(this.domConverter.domToView(s[a])),a++);for(const t of c)t.parentNode||this.domConverter.unbindDomElement(t)}_diffNodeLists(t,e){return $o(t=function(t,e){const i=Array.from(t);if(0==i.length||!e)return i;i[i.length-1]==e&&i.pop();return i}(t,this._fakeSelectionContainer),e,Xo.bind(null,this.domConverter))}_findReplaceActions(t,e,i){if(-1===t.indexOf("insert")||-1===t.indexOf("delete"))return t;let n=[],o=[],s=[];const r={equal:0,insert:0,delete:0};for(const a of t)"insert"===a?s.push(i[r.equal+r.insert]):"delete"===a?o.push(e[r.equal+r.delete]):(n=n.concat($o(o,s,Zo).map(t=>"equal"===t?"replace":t)),n.push("equal"),o=[],s=[]),r[a]++;return n.concat($o(o,s,Zo).map(t=>"equal"===t?"replace":t))}_markDescendantTextToSync(t){if(t)if(t.is("text"))this.markedTexts.add(t);else if(t.is("element"))for(const e of t.getChildren())this._markDescendantTextToSync(e)}_updateSelection(){if(0===this.selection.rangeCount)return this._removeDomSelection(),void this._removeFakeSelection();const t=this.domConverter.mapViewToDom(this.selection.editableElement);this.isFocused&&t&&(this.selection.isFake?this._updateFakeSelection(t):(this._removeFakeSelection(),this._updateDomSelection(t)))}_updateFakeSelection(t){const e=t.ownerDocument;this._fakeSelectionContainer||(this._fakeSelectionContainer=function(t){const e=t.createElement("div");return Object.assign(e.style,{position:"fixed",top:0,left:"-9999px",width:"42px"}),e.textContent=" ",e}(e));const i=this._fakeSelectionContainer;if(this.domConverter.bindFakeSelection(i,this.selection),!this._fakeSelectionNeedsUpdate(t))return;i.parentElement&&i.parentElement==t||t.appendChild(i),i.textContent=this.selection.fakeSelectionLabel||" ";const n=e.getSelection(),o=e.createRange();n.removeAllRanges(),o.selectNodeContents(i),n.addRange(o)}_updateDomSelection(t){const e=t.ownerDocument.defaultView.getSelection();if(!this._domSelectionNeedsUpdate(e))return;const i=this.domConverter.viewPositionToDom(this.selection.anchor),n=this.domConverter.viewPositionToDom(this.selection.focus);t.focus(),e.collapse(i.parent,i.offset),e.extend(n.parent,n.offset),fo.isGecko&&function(t,e){const i=t.parent;if(i.nodeType!=Node.ELEMENT_NODE||t.offset!=i.childNodes.length-1)return;const n=i.childNodes[t.offset];n&&"BR"==n.tagName&&e.addRange(e.getRangeAt(0))}(n,e)}_domSelectionNeedsUpdate(t){if(!this.domConverter.isDomSelectionCorrect(t))return!0;const e=t&&this.domConverter.domSelectionToView(t);return(!e||!this.selection.isEqual(e))&&!(!this.selection.isCollapsed&&this.selection.isSimilar(e))}_fakeSelectionNeedsUpdate(t){const e=this._fakeSelectionContainer,i=t.ownerDocument.getSelection();return!e||e.parentElement!==t||(i.anchorNode!==e&&!e.contains(i.anchorNode)||e.textContent!==this.selection.fakeSelectionLabel)}_removeDomSelection(){for(const t of this.domDocuments){if(t.getSelection().rangeCount){const e=t.activeElement,i=this.domConverter.mapDomToView(e);e&&i&&t.getSelection().removeAllRanges()}}}_removeFakeSelection(){const t=this._fakeSelectionContainer;t&&t.remove()}_updateFocus(){if(this.isFocused){const t=this.selection.editableElement;t&&this.domConverter.focus(t)}}}function Jo(t,e,i){const n=e instanceof Array?e:e.childNodes,o=n[i];if(Lo(o))return o.data=jo+o.data,o;{const o=t.createTextNode(jo);return Array.isArray(e)?n.splice(i,0,o):Yo(e,i,o),o}}function Zo(t,e){return Qo(t)&&Qo(e)&&!Lo(t)&&!Lo(e)&&t.tagName.toLowerCase()===e.tagName.toLowerCase()}function Xo(t,e,i){return e===i||(Lo(e)&&Lo(i)?e.data===i.data:!(!t.isBlockFiller(e)||!t.isBlockFiller(i)))}vi(Ko,Hn);var ts={window:window,document:document};function es(t){let e=0;for(;t.previousSibling;)t=t.previousSibling,e++;return e}function is(t){const e=[];for(;t&&t.nodeType!=Node.DOCUMENT_NODE;)e.unshift(t),t=t.parentNode;return e}const ns=zo(document);class os{constructor(t={}){this.blockFillerMode=t.blockFillerMode||"br",this.preElements=["pre"],this.blockElements=["p","div","h1","h2","h3","h4","h5","h6","li","dd","dt","figcaption"],this._blockFiller="br"==this.blockFillerMode?zo:Do,this._domToViewMapping=new WeakMap,this._viewToDomMapping=new WeakMap,this._fakeSelectionMapping=new WeakMap}bindFakeSelection(t,e){this._fakeSelectionMapping.set(t,new no(e))}fakeSelectionToView(t){return this._fakeSelectionMapping.get(t)}bindElements(t,e){this._domToViewMapping.set(t,e),this._viewToDomMapping.set(e,t)}unbindDomElement(t){const e=this._domToViewMapping.get(t);if(e){this._domToViewMapping.delete(t),this._viewToDomMapping.delete(e);for(const e of Array.from(t.childNodes))this.unbindDomElement(e)}}bindDocumentFragments(t,e){this._domToViewMapping.set(t,e),this._viewToDomMapping.set(e,t)}viewToDom(t,e,i={}){if(t.is("text")){const i=this._processDataFromViewText(t);return e.createTextNode(i)}{if(this.mapViewToDom(t))return this.mapViewToDom(t);let n;if(t.is("documentFragment"))n=e.createDocumentFragment(),i.bind&&this.bindDocumentFragments(n,t);else{if(t.is("uiElement"))return n=t.render(e),i.bind&&this.bindElements(n,t),n;n=t.hasAttribute("xmlns")?e.createElementNS(t.getAttribute("xmlns"),t.name):e.createElement(t.name),i.bind&&this.bindElements(n,t);for(const e of t.getAttributeKeys())n.setAttribute(e,t.getAttribute(e))}if(i.withChildren||void 0===i.withChildren)for(const o of this.viewChildrenToDom(t,e,i))n.appendChild(o);return n}}*viewChildrenToDom(t,e,i={}){const n=t.getFillerOffset&&t.getFillerOffset();let o=0;for(const s of t.getChildren())n===o&&(yield this._blockFiller(e)),yield this.viewToDom(s,e,i),o++;n===o&&(yield this._blockFiller(e))}viewRangeToDom(t){const e=this.viewPositionToDom(t.start),i=this.viewPositionToDom(t.end),n=document.createRange();return n.setStart(e.parent,e.offset),n.setEnd(i.parent,i.offset),n}viewPositionToDom(t){const e=t.parent;if(e.is("text")){const i=this.findCorrespondingDomText(e);if(!i)return null;let n=t.offset;return Vo(i)&&(n+=7),{parent:i,offset:n}}{let i,n,o;if(0===t.offset){if(i=this.mapViewToDom(e),!i)return null;o=i.childNodes[0]}else{const e=t.nodeBefore;if(n=e.is("text")?this.findCorrespondingDomText(e):this.mapViewToDom(t.nodeBefore),!n)return null;i=n.parentNode,o=n.nextSibling}if(Lo(o)&&Vo(o))return{parent:o,offset:7};return{parent:i,offset:n?es(n)+1:0}}}domToView(t,e={}){if(this.isBlockFiller(t,this.blockFillerMode))return null;const i=this.getParentUIElement(t,this._domToViewMapping);if(i)return i;if(Lo(t)){if(Bo(t))return null;{const e=this._processDataFromDomText(t);return""===e?null:new Ni(e)}}if(this.isComment(t))return null;{if(this.mapDomToView(t))return this.mapDomToView(t);let i;if(this.isDocumentFragment(t))i=new Ao,e.bind&&this.bindDocumentFragments(t,i);else{const n=e.keepOriginalCase?t.tagName:t.tagName.toLowerCase();i=new On(n),e.bind&&this.bindElements(t,i);const o=t.attributes;for(let t=o.length-1;t>=0;t--)i._setAttribute(o[t].name,o[t].value)}if(e.withChildren||void 0===e.withChildren)for(const n of this.domChildrenToView(t,e))i._appendChild(n);return i}}*domChildrenToView(t,e={}){for(let i=0;i<t.childNodes.length;i++){const n=t.childNodes[i],o=this.domToView(n,e);null!==o&&(yield o)}}domSelectionToView(t){if(1===t.rangeCount){let e=t.getRangeAt(0).startContainer;Lo(e)&&(e=e.parentNode);const i=this.fakeSelectionToView(e);if(i)return i}const e=this.isDomSelectionBackward(t),i=[];for(let e=0;e<t.rangeCount;e++){const n=t.getRangeAt(e),o=this.domRangeToView(n);o&&i.push(o)}return new no(i,{backward:e})}domRangeToView(t){const e=this.domPositionToView(t.startContainer,t.startOffset),i=this.domPositionToView(t.endContainer,t.endOffset);return e&&i?new to(e,i):null}domPositionToView(t,e){if(this.isBlockFiller(t,this.blockFillerMode))return this.domPositionToView(t.parentNode,es(t));const i=this.mapDomToView(t);if(i&&i.is("uiElement"))return Xn._createBefore(i);if(Lo(t)){if(Bo(t))return this.domPositionToView(t.parentNode,es(t));const i=this.findCorrespondingViewText(t);let n=e;return i?(Vo(t)&&(n-=7,n=n<0?0:n),new Xn(i,n)):null}if(0===e){const e=this.mapDomToView(t);if(e)return new Xn(e,0)}else{const i=t.childNodes[e-1],n=Lo(i)?this.findCorrespondingViewText(i):this.mapDomToView(i);if(n&&n.parent)return new Xn(n.parent,n.index+1)}return null}mapDomToView(t){return this.getParentUIElement(t)||this._domToViewMapping.get(t)}findCorrespondingViewText(t){if(Bo(t))return null;const e=this.getParentUIElement(t);if(e)return e;const i=t.previousSibling;if(i){if(!this.isElement(i))return null;const t=this.mapDomToView(i);if(t){return t.nextSibling instanceof Ni?t.nextSibling:null}}else{const e=this.mapDomToView(t.parentNode);if(e){const t=e.getChild(0);return t instanceof Ni?t:null}}return null}mapViewToDom(t){return this._viewToDomMapping.get(t)}findCorrespondingDomText(t){const e=t.previousSibling;return e&&this.mapViewToDom(e)?this.mapViewToDom(e).nextSibling:!e&&t.parent&&this.mapViewToDom(t.parent)?this.mapViewToDom(t.parent).childNodes[0]:null}focus(t){const e=this.mapViewToDom(t);if(e&&e.ownerDocument.activeElement!==e){const{scrollX:t,scrollY:i}=ts.window,n=[];rs(e,t=>{const{scrollLeft:e,scrollTop:i}=t;n.push([e,i])}),e.focus(),rs(e,t=>{const[e,i]=n.shift();t.scrollLeft=e,t.scrollTop=i}),ts.window.scrollTo(t,i)}}isElement(t){return t&&t.nodeType==Node.ELEMENT_NODE}isDocumentFragment(t){return t&&t.nodeType==Node.DOCUMENT_FRAGMENT_NODE}isComment(t){return t&&t.nodeType==Node.COMMENT_NODE}isBlockFiller(t){return"br"==this.blockFillerMode?t.isEqualNode(ns):!("BR"!==t.tagName||!as(t,this.blockElements)||1!==t.parentNode.childNodes.length)||function(t,e){return Lo(t)&&" "==t.data&&as(t,e)&&1===t.parentNode.childNodes.length}(t,this.blockElements)}isDomSelectionBackward(t){if(t.isCollapsed)return!1;const e=document.createRange();e.setStart(t.anchorNode,t.anchorOffset),e.setEnd(t.focusNode,t.focusOffset);const i=e.collapsed;return e.detach(),i}getParentUIElement(t){const e=is(t);for(e.pop();e.length;){const t=e.pop(),i=this._domToViewMapping.get(t);if(i&&i.is("uiElement"))return i}return null}isDomSelectionCorrect(t){return this._isDomSelectionPositionCorrect(t.anchorNode,t.anchorOffset)&&this._isDomSelectionPositionCorrect(t.focusNode,t.focusOffset)}_isDomSelectionPositionCorrect(t,e){if(Lo(t)&&Vo(t)&&e<7)return!1;if(this.isElement(t)&&Vo(t.childNodes[e]))return!1;const i=this.mapDomToView(t);return!i||!i.is("uiElement")}_processDataFromViewText(t){let e=t.data;if(t.getAncestors().some(t=>this.preElements.includes(t.name)))return e;if(" "==e.charAt(0)){const i=this._getTouchingViewTextNode(t,!1);!(i&&this._nodeEndsWithSpace(i))&&i||(e=" "+e.substr(1))}if(" "==e.charAt(e.length-1)){const i=this._getTouchingViewTextNode(t,!0);" "!=e.charAt(e.length-2)&&i&&" "!=i.data.charAt(0)||(e=e.substr(0,e.length-1)+" ")}return e.replace(/ {2}/g," ")}_nodeEndsWithSpace(t){if(t.getAncestors().some(t=>this.preElements.includes(t.name)))return!1;const e=this._processDataFromViewText(t);return" "==e.charAt(e.length-1)}_processDataFromDomText(t){let e=t.data;if(ss(t,this.preElements))return Fo(t);e=e.replace(/[ \n\t\r]{1,}/g," ");const i=this._getTouchingInlineDomNode(t,!1),n=this._getTouchingInlineDomNode(t,!0),o=this._checkShouldLeftTrimDomText(i),s=this._checkShouldRightTrimDomText(t,n);return o&&(e=e.replace(/^ /,"")),s&&(e=e.replace(/ $/,"")),e=Fo(new Text(e)),e=e.replace(/ \u00A0/g," "),(/( |\u00A0)\u00A0$/.test(e)||!n||n.data&&" "==n.data.charAt(0))&&(e=e.replace(/\u00A0$/," ")),o&&(e=e.replace(/^\u00A0/," ")),e}_checkShouldLeftTrimDomText(t){return!t||(!!ii(t)||/[^\S\u00A0]/.test(t.data.charAt(t.data.length-1)))}_checkShouldRightTrimDomText(t,e){return!e&&!Vo(t)}_getTouchingViewTextNode(t,e){const i=new Zn({startPosition:e?Xn._createAfter(t):Xn._createBefore(t),direction:e?"forward":"backward"});for(const t of i){if(t.item.is("containerElement"))return null;if(t.item.is("br"))return null;if(t.item.is("textProxy"))return t.item}return null}_getTouchingInlineDomNode(t,e){if(!t.parentNode)return null;const i=e?"nextNode":"previousNode",n=t.ownerDocument,o=is(t)[0],s=n.createTreeWalker(o,NodeFilter.SHOW_TEXT|NodeFilter.SHOW_ELEMENT,{acceptNode:t=>Lo(t)||"BR"==t.tagName?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP});s.currentNode=t;const r=s[i]();if(null!==r){const e=function(t,e){const i=is(t),n=is(e);let o=0;for(;i[o]==n[o]&&i[o];)o++;return 0===o?null:i[o-1]}(t,r);if(e&&!ss(t,this.blockElements,e)&&!ss(r,this.blockElements,e))return r}return null}}function ss(t,e,i){let n=is(t);return i&&(n=n.slice(n.indexOf(i)+1)),n.some(t=>t.tagName&&e.includes(t.tagName.toLowerCase()))}function rs(t,e){for(;t&&t!=ts.document;)e(t),t=t.parentNode}function as(t,e){const i=t.parentNode;return i&&i.tagName&&e.includes(i.tagName.toLowerCase())}function cs(t){const e=Object.prototype.toString.apply(t);return"[object Window]"==e||"[object global]"==e}var ls=zn({},mi,{listenTo(t,...e){if(Qo(t)||cs(t)){const i=this._getProxyEmitter(t)||new ds(t);i.attach(...e),t=i}mi.listenTo.call(this,t,...e)},stopListening(t,e,i){if(Qo(t)||cs(t)){const e=this._getProxyEmitter(t);if(!e)return;t=e}mi.stopListening.call(this,t,e,i),t instanceof ds&&t.detach(e)},_getProxyEmitter(t){return e=this,i=hs(t),e[ui]&&e[ui][i]?e[ui][i].emitter:null;var e,i}});class ds{constructor(t){gi(this,hs(t)),this._domNode=t}}function hs(t){return t["data-ck-expando"]||(t["data-ck-expando"]=li())}zn(ds.prototype,mi,{attach(t,e,i={}){if(this._domListeners&&this._domListeners[t])return;const n=this._createDomListener(t,!!i.useCapture);this._domNode.addEventListener(t,n,!!i.useCapture),this._domListeners||(this._domListeners={}),this._domListeners[t]=n},detach(t){let e;!this._domListeners[t]||(e=this._events[t])&&e.callbacks.length||this._domListeners[t].removeListener()},_createDomListener(t,e){const i=e=>{this.fire(t,e)};return i.removeListener=()=>{this._domNode.removeEventListener(t,i,e),delete this._domListeners[t]},i}});class us{constructor(t){this.view=t,this.document=t.document,this.isEnabled=!1}enable(){this.isEnabled=!0}disable(){this.isEnabled=!1}destroy(){this.disable(),this.stopListening()}}vi(us,ls);var fs=function(t){return this.__data__.set(t,"__lodash_hash_undefined__"),this};var ms=function(t){return this.__data__.has(t)};function gs(t){var e=-1,i=null==t?0:t.length;for(this.__data__=new kt;++e<i;)this.add(t[e])}gs.prototype.add=gs.prototype.push=fs,gs.prototype.has=ms;var ps=gs;var bs=function(t,e){for(var i=-1,n=null==t?0:t.length;++i<n;)if(e(t[i],i,t))return!0;return!1};var ws=function(t,e){return t.has(e)};var ks=function(t,e,i,n,o,s){var r=1&i,a=t.length,c=e.length;if(a!=c&&!(r&&c>a))return!1;var l=s.get(t);if(l&&s.get(e))return l==e;var d=-1,h=!0,u=2&i?new ps:void 0;for(s.set(t,e),s.set(e,t);++d<a;){var f=t[d],m=e[d];if(n)var g=r?n(m,f,d,e,t,s):n(f,m,d,t,e,s);if(void 0!==g){if(g)continue;h=!1;break}if(u){if(!bs(e,(function(t,e){if(!ws(u,e)&&(f===t||o(f,t,i,n,s)))return u.push(e)}))){h=!1;break}}else if(f!==m&&!o(f,m,i,n,s)){h=!1;break}}return s.delete(t),s.delete(e),h};var _s=function(t){var e=-1,i=Array(t.size);return t.forEach((function(t,n){i[++e]=[n,t]})),i};var vs=function(t){var e=-1,i=Array(t.size);return t.forEach((function(t){i[++e]=t})),i},ys=o?o.prototype:void 0,xs=ys?ys.valueOf:void 0;var As=function(t,e,i,n,o,s,r){switch(i){case"[object DataView]":if(t.byteLength!=e.byteLength||t.byteOffset!=e.byteOffset)return!1;t=t.buffer,e=e.buffer;case"[object ArrayBuffer]":return!(t.byteLength!=e.byteLength||!s(new Re(t),new Re(e)));case"[object Boolean]":case"[object Date]":case"[object Number]":return A(+t,+e);case"[object Error]":return t.name==e.name&&t.message==e.message;case"[object RegExp]":case"[object String]":return t==e+"";case"[object Map]":var a=_s;case"[object Set]":var c=1&n;if(a||(a=vs),t.size!=e.size&&!c)return!1;var l=r.get(t);if(l)return l==e;n|=2,r.set(t,e);var d=ks(a(t),a(e),n,o,s,r);return r.delete(t),d;case"[object Symbol]":if(xs)return xs.call(t)==xs.call(e)}return!1},Cs=Object.prototype.hasOwnProperty;var Ts=function(t,e,i,n,o,s){var r=1&i,a=ke(t),c=a.length;if(c!=ke(e).length&&!r)return!1;for(var l=c;l--;){var d=a[l];if(!(r?d in e:Cs.call(e,d)))return!1}var h=s.get(t);if(h&&s.get(e))return h==e;var u=!0;s.set(t,e),s.set(e,t);for(var f=r;++l<c;){var m=t[d=a[l]],g=e[d];if(n)var p=r?n(g,m,d,e,t,s):n(m,g,d,t,e,s);if(!(void 0===p?m===g||o(m,g,i,n,s):p)){u=!1;break}f||(f="constructor"==d)}if(u&&!f){var b=t.constructor,w=e.constructor;b!=w&&"constructor"in t&&"constructor"in e&&!("function"==typeof b&&b instanceof b&&"function"==typeof w&&w instanceof w)&&(u=!1)}return s.delete(t),s.delete(e),u},Ps=Object.prototype.hasOwnProperty;var Ss=function(t,e,i,n,o,s){var r=Lt(t),a=Lt(e),c=r?"[object Array]":Ie(t),l=a?"[object Array]":Ie(e),d="[object Object]"==(c="[object Arguments]"==c?"[object Object]":c),h="[object Object]"==(l="[object Arguments]"==l?"[object Object]":l),u=c==l;if(u&&Object(Dt.a)(t)){if(!Object(Dt.a)(e))return!1;r=!0,d=!1}if(u&&!d)return s||(s=new yt),r||qt(t)?ks(t,e,i,n,o,s):As(t,e,c,i,n,o,s);if(!(1&i)){var f=d&&Ps.call(t,"__wrapped__"),m=h&&Ps.call(e,"__wrapped__");if(f||m){var g=f?t.value():t,p=m?e.value():e;return s||(s=new yt),o(g,p,i,n,s)}}return!!u&&(s||(s=new yt),Ts(t,e,i,n,o,s))};var Es=function t(e,i,n,o,s){return e===i||(null==e||null==i||!p(e)&&!p(i)?e!=e&&i!=i:Ss(e,i,n,o,t,s))};var Ms=function(t,e,i){var n=(i="function"==typeof i?i:void 0)?i(t,e):void 0;return void 0===n?Es(t,e,void 0,i):!!n};class Is extends us{constructor(t){super(t),this._config={childList:!0,characterData:!0,characterDataOldValue:!0,subtree:!0},this.domConverter=t.domConverter,this.renderer=t._renderer,this._domElements=[],this._mutationObserver=new window.MutationObserver(this._onMutations.bind(this))}flush(){this._onMutations(this._mutationObserver.takeRecords())}observe(t){this._domElements.push(t),this.isEnabled&&this._mutationObserver.observe(t,this._config)}enable(){super.enable();for(const t of this._domElements)this._mutationObserver.observe(t,this._config)}disable(){super.disable(),this._mutationObserver.disconnect()}destroy(){super.destroy(),this._mutationObserver.disconnect()}_onMutations(t){if(0===t.length)return;const e=this.domConverter,i=new Map,n=new Set;for(const i of t)if("childList"===i.type){const t=e.mapDomToView(i.target);if(t&&t.is("uiElement"))continue;t&&!this._isBogusBrMutation(i)&&n.add(t)}for(const o of t){const t=e.mapDomToView(o.target);if((!t||!t.is("uiElement"))&&"characterData"===o.type){const t=e.findCorrespondingViewText(o.target);t&&!n.has(t.parent)?i.set(t,{type:"text",oldText:t.data,newText:Fo(o.target),node:t}):!t&&Vo(o.target)&&n.add(e.mapDomToView(o.target.parentNode))}}const o=[];for(const t of i.values())this.renderer.markToSync("text",t.node),o.push(t);for(const t of n){const i=e.mapViewToDom(t),n=Array.from(t.getChildren()),s=Array.from(e.domChildrenToView(i,{withChildren:!1}));Ms(n,s,a)||(this.renderer.markToSync("children",t),o.push({type:"children",oldChildren:n,newChildren:s,node:t}))}const s=t[0].target.ownerDocument.getSelection();let r=null;if(s&&s.anchorNode){const t=e.domPositionToView(s.anchorNode,s.anchorOffset),i=e.domPositionToView(s.focusNode,s.focusOffset);t&&i&&(r=new no(t),r.setFocus(i))}function a(t,e){if(!Array.isArray(t))return t===e||!(!t.is("text")||!e.is("text"))&&t.data===e.data}o.length&&(this.document.fire("mutations",o,r),this.view.forceRender())}_isBogusBrMutation(t){let e=null;return null===t.nextSibling&&0===t.removedNodes.length&&1==t.addedNodes.length&&(e=this.domConverter.domToView(t.addedNodes[0],{withChildren:!1})),e&&e.is("element","br")}}class Ns{constructor(t,e,i){this.view=t,this.document=t.document,this.domEvent=e,this.domTarget=e.target,zn(this,i)}get target(){return this.view.domConverter.mapDomToView(this.domTarget)}preventDefault(){this.domEvent.preventDefault()}stopPropagation(){this.domEvent.stopPropagation()}}class Os extends us{constructor(t){super(t),this.useCapture=!1}observe(t){("string"==typeof this.domEventType?[this.domEventType]:this.domEventType).forEach(e=>{this.listenTo(t,e,(t,e)=>{this.isEnabled&&this.onDomEvent(e)},{useCapture:this.useCapture})})}fire(t,e,i){this.isEnabled&&this.document.fire(t,new Ns(this.view,e,i))}}class Rs extends Os{constructor(t){super(t),this.domEventType=["keydown","keyup"]}onDomEvent(t){this.fire(t.type,t,{keyCode:t.keyCode,altKey:t.altKey,ctrlKey:t.ctrlKey||t.metaKey,shiftKey:t.shiftKey,get keystroke(){return bo(this)}})}}var Ls=function(){return n.a.Date.now()},Ds=/^\s+|\s+$/g,zs=/^[-+]0x[0-9a-f]+$/i,js=/^0b[01]+$/i,Vs=/^0o[0-7]+$/i,Bs=parseInt;var Fs=function(t){if("number"==typeof t)return t;if(ji(t))return NaN;if(z(t)){var e="function"==typeof t.valueOf?t.valueOf():t;t=z(e)?e+"":e}if("string"!=typeof t)return 0===t?t:+t;t=t.replace(Ds,"");var i=js.test(t);return i||Vs.test(t)?Bs(t.slice(2),i?2:8):zs.test(t)?NaN:+t},Hs=Math.max,Us=Math.min;var Ws=function(t,e,i){var n,o,s,r,a,c,l=0,d=!1,h=!1,u=!0;if("function"!=typeof t)throw new TypeError("Expected a function");function f(e){var i=n,s=o;return n=o=void 0,l=e,r=t.apply(s,i)}function m(t){return l=t,a=setTimeout(p,e),d?f(t):r}function g(t){var i=t-c;return void 0===c||i>=e||i<0||h&&t-l>=s}function p(){var t=Ls();if(g(t))return b(t);a=setTimeout(p,function(t){var i=e-(t-c);return h?Us(i,s-(t-l)):i}(t))}function b(t){return a=void 0,u&&n?f(t):(n=o=void 0,r)}function w(){var t=Ls(),i=g(t);if(n=arguments,o=this,c=t,i){if(void 0===a)return m(c);if(h)return clearTimeout(a),a=setTimeout(p,e),f(c)}return void 0===a&&(a=setTimeout(p,e)),r}return e=Fs(e)||0,z(i)&&(d=!!i.leading,s=(h="maxWait"in i)?Hs(Fs(i.maxWait)||0,e):s,u="trailing"in i?!!i.trailing:u),w.cancel=function(){void 0!==a&&clearTimeout(a),l=0,n=c=o=a=void 0},w.flush=function(){return void 0===a?r:b(Ls())},w};class qs extends us{constructor(t){super(t),this._fireSelectionChangeDoneDebounced=Ws(t=>this.document.fire("selectionChangeDone",t),200)}observe(){const t=this.document;t.on("keydown",(e,i)=>{var n;t.selection.isFake&&((n=i.keyCode)==po.arrowright||n==po.arrowleft||n==po.arrowup||n==po.arrowdown)&&this.isEnabled&&(i.preventDefault(),this._handleSelectionMove(i.keyCode))},{priority:"lowest"})}destroy(){super.destroy(),this._fireSelectionChangeDoneDebounced.cancel()}_handleSelectionMove(t){const e=this.document.selection,i=new no(e.getRanges(),{backward:e.isBackward,fake:!1});t!=po.arrowleft&&t!=po.arrowup||i.setTo(i.getFirstPosition()),t!=po.arrowright&&t!=po.arrowdown||i.setTo(i.getLastPosition());const n={oldSelection:e,newSelection:i,domSelection:null};this.document.fire("selectionChange",n),this._fireSelectionChangeDoneDebounced(n)}}class $s extends us{constructor(t){super(t),this.mutationObserver=t.getObserver(Is),this.selection=this.document.selection,this.domConverter=t.domConverter,this._documents=new WeakSet,this._fireSelectionChangeDoneDebounced=Ws(t=>this.document.fire("selectionChangeDone",t),200),this._clearInfiniteLoopInterval=setInterval(()=>this._clearInfiniteLoop(),1e3),this._loopbackCounter=0}observe(t){const e=t.ownerDocument;this._documents.has(e)||(this.listenTo(e,"selectionchange",()=>{this._handleSelectionChange(e)}),this._documents.add(e))}destroy(){super.destroy(),clearInterval(this._clearInfiniteLoopInterval),this._fireSelectionChangeDoneDebounced.cancel()}_handleSelectionChange(t){if(!this.isEnabled)return;this.mutationObserver.flush();const e=t.defaultView.getSelection(),i=this.domConverter.domSelectionToView(e);if(0!=i.rangeCount&&!(this.selection.isEqual(i)&&this.domConverter.isDomSelectionCorrect(e)||++this._loopbackCounter>60))if(this.selection.isSimilar(i))this.view.forceRender();else{const t={oldSelection:this.selection,newSelection:i,domSelection:e};this.document.fire("selectionChange",t),this._fireSelectionChangeDoneDebounced(t)}}_clearInfiniteLoop(){this._loopbackCounter=0}}class Ys extends Os{constructor(t){super(t),this.domEventType=["focus","blur"],this.useCapture=!0;const e=this.document;e.on("focus",()=>{e.isFocused=!0,this._renderTimeoutId=setTimeout(()=>t.forceRender(),50)}),e.on("blur",(i,n)=>{const o=e.selection.editableElement;null!==o&&o!==n.target||(e.isFocused=!1,t.forceRender())})}onDomEvent(t){this.fire(t.type,t)}destroy(){this._renderTimeoutId&&clearTimeout(this._renderTimeoutId),super.destroy()}}class Gs extends Os{constructor(t){super(t),this.domEventType=["compositionstart","compositionupdate","compositionend"];const e=this.document;e.on("compositionstart",()=>{e.isComposing=!0}),e.on("compositionend",()=>{e.isComposing=!1})}onDomEvent(t){this.fire(t.type,t)}}class Qs extends Os{constructor(t){super(t),this.domEventType=["beforeinput"]}onDomEvent(t){this.fire(t.type,t)}}function Ks(t){return"[object Range]"==Object.prototype.toString.apply(t)}function Js(t){const e=t.ownerDocument.defaultView.getComputedStyle(t);return{top:parseInt(e.borderTopWidth,10),right:parseInt(e.borderRightWidth,10),bottom:parseInt(e.borderBottomWidth,10),left:parseInt(e.borderLeftWidth,10)}}const Zs=["top","right","bottom","left","width","height"];class Xs{constructor(t){const e=Ks(t);if(Object.defineProperty(this,"_source",{value:t._source||t,writable:!0,enumerable:!1}),ii(t)||e)tr(this,e?Xs.getDomRangeRects(t)[0]:t.getBoundingClientRect());else if(cs(t)){const{innerWidth:e,innerHeight:i}=t;tr(this,{top:0,right:e,bottom:i,left:0,width:e,height:i})}else tr(this,t)}clone(){return new Xs(this)}moveTo(t,e){return this.top=e,this.right=t+this.width,this.bottom=e+this.height,this.left=t,this}moveBy(t,e){return this.top+=e,this.right+=t,this.left+=t,this.bottom+=e,this}getIntersection(t){const e={top:Math.max(this.top,t.top),right:Math.min(this.right,t.right),bottom:Math.min(this.bottom,t.bottom),left:Math.max(this.left,t.left)};return e.width=e.right-e.left,e.height=e.bottom-e.top,e.width<0||e.height<0?null:new Xs(e)}getIntersectionArea(t){const e=this.getIntersection(t);return e?e.getArea():0}getArea(){return this.width*this.height}getVisible(){const t=this._source;let e=this.clone();if(!er(t)){let i=t.parentNode||t.commonAncestorContainer;for(;i&&!er(i);){const t=new Xs(i),n=e.getIntersection(t);if(!n)return null;n.getArea()<e.getArea()&&(e=n),i=i.parentNode}}return e}isEqual(t){for(const e of Zs)if(this[e]!==t[e])return!1;return!0}contains(t){const e=this.getIntersection(t);return!(!e||!e.isEqual(t))}excludeScrollbarsAndBorders(){const t=this._source;let e,i,n;if(cs(t))e=t.innerWidth-t.document.documentElement.clientWidth,i=t.innerHeight-t.document.documentElement.clientHeight,n=t.getComputedStyle(t.document.documentElement).direction;else{const o=Js(this._source);e=t.offsetWidth-t.clientWidth-o.left-o.right,i=t.offsetHeight-t.clientHeight-o.top-o.bottom,n=t.ownerDocument.defaultView.getComputedStyle(t).direction,this.left+=o.left,this.top+=o.top,this.right-=o.right,this.bottom-=o.bottom,this.width=this.right-this.left,this.height=this.bottom-this.top}return this.width-=e,"ltr"===n?this.right-=e:this.left+=e,this.height-=i,this.bottom-=i,this}static getDomRangeRects(t){const e=[],i=Array.from(t.getClientRects());if(i.length)for(const t of i)e.push(new Xs(t));else{let i=t.startContainer;Lo(i)&&(i=i.parentNode);const n=new Xs(i.getBoundingClientRect());n.right=n.left,n.width=0,e.push(n)}return e}}function tr(t,e){for(const i of Zs)t[i]=e[i]}function er(t){return!!ii(t)&&t===t.ownerDocument.body}function ir({target:t,viewportOffset:e=0}){const i=lr(t);let n=i,o=null;for(;n;){let s;s=dr(n==i?t:o),or(s,()=>hr(t,n));const r=hr(t,n);if(nr(n,r,e),n.parent!=n){if(o=n.frameElement,n=n.parent,!o)return}else n=null}}function nr(t,e,i){const n=e.clone().moveBy(0,i),o=e.clone().moveBy(0,-i),s=new Xs(t).excludeScrollbarsAndBorders();if(![o,n].every(t=>s.contains(t))){let{scrollX:r,scrollY:a}=t;rr(o,s)?a-=s.top-e.top+i:sr(n,s)&&(a+=e.bottom-s.bottom+i),ar(e,s)?r-=s.left-e.left+i:cr(e,s)&&(r+=e.right-s.right+i),t.scrollTo(r,a)}}function or(t,e){const i=lr(t);let n,o;for(;t!=i.document.body;)o=e(),n=new Xs(t).excludeScrollbarsAndBorders(),n.contains(o)||(rr(o,n)?t.scrollTop-=n.top-o.top:sr(o,n)&&(t.scrollTop+=o.bottom-n.bottom),ar(o,n)?t.scrollLeft-=n.left-o.left:cr(o,n)&&(t.scrollLeft+=o.right-n.right)),t=t.parentNode}function sr(t,e){return t.bottom>e.bottom}function rr(t,e){return t.top<e.top}function ar(t,e){return t.left<e.left}function cr(t,e){return t.right>e.right}function lr(t){return Ks(t)?t.startContainer.ownerDocument.defaultView:t.ownerDocument.defaultView}function dr(t){if(Ks(t)){let e=t.commonAncestorContainer;return Lo(e)&&(e=e.parentNode),e}return t.parentNode}function hr(t,e){const i=lr(t),n=new Xs(t);if(i===e)return n;{let t=i;for(;t!=e;){const e=t.frameElement,i=new Xs(e).excludeScrollbarsAndBorders();n.moveBy(i.left,i.top),t=t.parent}}return n}Object.assign({},{scrollViewportToShowTarget:ir,scrollAncestorsToShowTarget:function(t){or(dr(t),()=>new Xs(t))}});class ur{constructor(){this.document=new so,this.domConverter=new os,this.domRoots=new Map,this.set("isRenderingInProgress",!1),this._renderer=new Ko(this.domConverter,this.document.selection),this._renderer.bind("isFocused").to(this.document),this._initialDomRootAttributes=new WeakMap,this._observers=new Map,this._ongoingChange=!1,this._postFixersInProgress=!1,this._renderingDisabled=!1,this._hasChangedSinceTheLastRendering=!1,this._writer=new Co(this.document),this.addObserver(Is),this.addObserver($s),this.addObserver(Ys),this.addObserver(Rs),this.addObserver(qs),this.addObserver(Gs),fo.isAndroid&&this.addObserver(Qs),this.document.on("keydown",Ho),yo(this),this.on("render",()=>{this._render(),this.document.fire("layoutChanged"),this._hasChangedSinceTheLastRendering=!1}),this.listenTo(this.document.selection,"change",()=>{this._hasChangedSinceTheLastRendering=!0})}attachDomRoot(t,e="main"){const i=this.document.getRoot(e);i._name=t.tagName.toLowerCase();const n={};for(const{name:e,value:o}of Array.from(t.attributes))n[e]=o,"class"===e?this._writer.addClass(o.split(" "),i):this._writer.setAttribute(e,o,i);this._initialDomRootAttributes.set(t,n);const o=()=>{this._writer.setAttribute("contenteditable",!i.isReadOnly,i),i.isReadOnly?this._writer.addClass("ck-read-only",i):this._writer.removeClass("ck-read-only",i)};o(),this.domRoots.set(e,t),this.domConverter.bindElements(t,i),this._renderer.markToSync("children",i),this._renderer.markToSync("attributes",i),this._renderer.domDocuments.add(t.ownerDocument),i.on("change:children",(t,e)=>this._renderer.markToSync("children",e)),i.on("change:attributes",(t,e)=>this._renderer.markToSync("attributes",e)),i.on("change:text",(t,e)=>this._renderer.markToSync("text",e)),i.on("change:isReadOnly",()=>this.change(o)),i.on("change",()=>{this._hasChangedSinceTheLastRendering=!0});for(const i of this._observers.values())i.observe(t,e)}detachDomRoot(t){const e=this.domRoots.get(t);Array.from(e.attributes).forEach(({name:t})=>e.removeAttribute(t));const i=this._initialDomRootAttributes.get(e);for(const t in i)e.setAttribute(t,i[t]);this.domRoots.delete(t),this.domConverter.unbindDomElement(e)}getDomRoot(t="main"){return this.domRoots.get(t)}addObserver(t){let e=this._observers.get(t);if(e)return e;e=new t(this),this._observers.set(t,e);for(const[t,i]of this.domRoots)e.observe(i,t);return e.enable(),e}getObserver(t){return this._observers.get(t)}disableObservers(){for(const t of this._observers.values())t.disable()}enableObservers(){for(const t of this._observers.values())t.enable()}scrollToTheSelection(){const t=this.document.selection.getFirstRange();t&&ir({target:this.domConverter.viewRangeToDom(t),viewportOffset:20})}focus(){if(!this.document.isFocused){const t=this.document.selection.editableElement;t&&(this.domConverter.focus(t),this.forceRender())}}change(t){if(this.isRenderingInProgress||this._postFixersInProgress)throw new hi.b("cannot-change-view-tree: Attempting to make changes to the view when it is in an incorrect state: rendering or post-fixers are in progress. This may cause some unexpected behavior and inconsistency between the DOM and the view.",this);try{if(this._ongoingChange)return t(this._writer);this._ongoingChange=!0;const e=t(this._writer);return this._ongoingChange=!1,!this._renderingDisabled&&this._hasChangedSinceTheLastRendering&&(this._postFixersInProgress=!0,this.document._callPostFixers(this._writer),this._postFixersInProgress=!1,this.fire("render")),e}catch(t){hi.b.rethrowUnexpectedError(t,this)}}forceRender(){this._hasChangedSinceTheLastRendering=!0,this.change(()=>{})}destroy(){for(const t of this._observers.values())t.destroy();this.document.destroy(),this.stopListening()}createPositionAt(t,e){return Xn._createAt(t,e)}createPositionAfter(t){return Xn._createAfter(t)}createPositionBefore(t){return Xn._createBefore(t)}createRange(t,e){return new to(t,e)}createRangeOn(t){return to._createOn(t)}createRangeIn(t){return to._createIn(t)}createSelection(t,e,i){return new no(t,e,i)}_disableRendering(t){this._renderingDisabled=t,0==t&&this.change(()=>{})}_render(){this.isRenderingInProgress=!0,this.disableObservers(),this._renderer.render(),this.enableObservers(),this.isRenderingInProgress=!1}}vi(ur,Hn);class fr{constructor(t){this.parent=null,this._attrs=Li(t)}get index(){let t;if(!this.parent)return null;if(null===(t=this.parent.getChildIndex(this)))throw new hi.b("model-node-not-found-in-parent: The node's parent does not contain this node.",this);return t}get startOffset(){let t;if(!this.parent)return null;if(null===(t=this.parent.getChildStartOffset(this)))throw new hi.b("model-node-not-found-in-parent: The node's parent does not contain this node.",this);return t}get offsetSize(){return 1}get endOffset(){return this.parent?this.startOffset+this.offsetSize:null}get nextSibling(){const t=this.index;return null!==t&&this.parent.getChild(t+1)||null}get previousSibling(){const t=this.index;return null!==t&&this.parent.getChild(t-1)||null}get root(){let t=this;for(;t.parent;)t=t.parent;return t}get document(){return this.root==this?null:this.root.document||null}getPath(){const t=[];let e=this;for(;e.parent;)t.unshift(e.startOffset),e=e.parent;return t}getAncestors(t={includeSelf:!1,parentFirst:!1}){const e=[];let i=t.includeSelf?this:this.parent;for(;i;)e[t.parentFirst?"push":"unshift"](i),i=i.parent;return e}getCommonAncestor(t,e={}){const i=this.getAncestors(e),n=t.getAncestors(e);let o=0;for(;i[o]==n[o]&&i[o];)o++;return 0===o?null:i[o-1]}isBefore(t){if(this==t)return!1;if(this.root!==t.root)return!1;const e=this.getPath(),i=t.getPath(),n=Ei(e,i);switch(n){case"prefix":return!0;case"extension":return!1;default:return e[n]<i[n]}}isAfter(t){return this!=t&&(this.root===t.root&&!this.isBefore(t))}hasAttribute(t){return this._attrs.has(t)}getAttribute(t){return this._attrs.get(t)}getAttributes(){return this._attrs.entries()}getAttributeKeys(){return this._attrs.keys()}toJSON(){const t={};return this._attrs.size&&(t.attributes=Array.from(this._attrs).reduce((t,e)=>(t[e[0]]=e[1],t),{})),t}is(t){return"node"==t||"model:node"==t}_clone(){return new fr(this._attrs)}_remove(){this.parent._removeChildren(this.index)}_setAttribute(t,e){this._attrs.set(t,e)}_setAttributesTo(t){this._attrs=Li(t)}_removeAttribute(t){return this._attrs.delete(t)}_clearAttributes(){this._attrs.clear()}}class mr extends fr{constructor(t,e){super(e),this._data=t||""}get offsetSize(){return this.data.length}get data(){return this._data}is(t){return"text"==t||"model:text"==t||super.is(t)}toJSON(){const t=super.toJSON();return t.data=this.data,t}_clone(){return new mr(this.data,this.getAttributes())}static fromJSON(t){return new mr(t.data,t.attributes)}}class gr{constructor(t,e,i){if(this.textNode=t,e<0||e>t.offsetSize)throw new hi.b("model-textproxy-wrong-offsetintext: Given offsetInText value is incorrect.",this);if(i<0||e+i>t.offsetSize)throw new hi.b("model-textproxy-wrong-length: Given length value is incorrect.",this);this.data=t.data.substring(e,e+i),this.offsetInText=e}get startOffset(){return null!==this.textNode.startOffset?this.textNode.startOffset+this.offsetInText:null}get offsetSize(){return this.data.length}get endOffset(){return null!==this.startOffset?this.startOffset+this.offsetSize:null}get isPartial(){return this.offsetSize!==this.textNode.offsetSize}get parent(){return this.textNode.parent}get root(){return this.textNode.root}get document(){return this.textNode.document}is(t){return"textProxy"==t||"model:textProxy"==t}getPath(){const t=this.textNode.getPath();return t.length>0&&(t[t.length-1]+=this.offsetInText),t}getAncestors(t={includeSelf:!1,parentFirst:!1}){const e=[];let i=t.includeSelf?this:this.parent;for(;i;)e[t.parentFirst?"push":"unshift"](i),i=i.parent;return e}hasAttribute(t){return this.textNode.hasAttribute(t)}getAttribute(t){return this.textNode.getAttribute(t)}getAttributes(){return this.textNode.getAttributes()}getAttributeKeys(){return this.textNode.getAttributeKeys()}}class pr{constructor(t){this._nodes=[],t&&this._insertNodes(0,t)}[Symbol.iterator](){return this._nodes[Symbol.iterator]()}get length(){return this._nodes.length}get maxOffset(){return this._nodes.reduce((t,e)=>t+e.offsetSize,0)}getNode(t){return this._nodes[t]||null}getNodeIndex(t){const e=this._nodes.indexOf(t);return-1==e?null:e}getNodeStartOffset(t){const e=this.getNodeIndex(t);return null===e?null:this._nodes.slice(0,e).reduce((t,e)=>t+e.offsetSize,0)}indexToOffset(t){if(t==this._nodes.length)return this.maxOffset;const e=this._nodes[t];if(!e)throw new hi.b("model-nodelist-index-out-of-bounds: Given index cannot be found in the node list.",this);return this.getNodeStartOffset(e)}offsetToIndex(t){let e=0;for(const i of this._nodes){if(t>=e&&t<e+i.offsetSize)return this.getNodeIndex(i);e+=i.offsetSize}if(e!=t)throw new hi.b("model-nodelist-offset-out-of-bounds: Given offset cannot be found in the node list.",this,{offset:t,nodeList:this});return this.length}_insertNodes(t,e){for(const t of e)if(!(t instanceof fr))throw new hi.b("model-nodelist-insertNodes-not-node: Trying to insert an object which is not a Node instance.",this);this._nodes.splice(t,0,...e)}_removeNodes(t,e=1){return this._nodes.splice(t,e)}toJSON(){return this._nodes.map(t=>t.toJSON())}}class br extends fr{constructor(t,e,i){super(e),this.name=t,this._children=new pr,i&&this._insertChild(0,i)}get childCount(){return this._children.length}get maxOffset(){return this._children.maxOffset}get isEmpty(){return 0===this.childCount}is(t,e=null){const i=t.replace(/^model:/,"");return e?"element"==i&&e==this.name:"element"==i||i==this.name||super.is(t)}getChild(t){return this._children.getNode(t)}getChildren(){return this._children[Symbol.iterator]()}getChildIndex(t){return this._children.getNodeIndex(t)}getChildStartOffset(t){return this._children.getNodeStartOffset(t)}offsetToIndex(t){return this._children.offsetToIndex(t)}getNodeByPath(t){let e=this;for(const i of t)e=e.getChild(e.offsetToIndex(i));return e}toJSON(){const t=super.toJSON();if(t.name=this.name,this._children.length>0){t.children=[];for(const e of this._children)t.children.push(e.toJSON())}return t}_clone(t=!1){const e=t?Array.from(this._children).map(t=>t._clone(!0)):null;return new br(this.name,this.getAttributes(),e)}_appendChild(t){this._insertChild(this.childCount,t)}_insertChild(t,e){const i=function(t){if("string"==typeof t)return[new mr(t)];Ri(t)||(t=[t]);return Array.from(t).map(t=>"string"==typeof t?new mr(t):t instanceof gr?new mr(t.data,t.getAttributes()):t)}(e);for(const t of i)null!==t.parent&&t._remove(),t.parent=this;this._children._insertNodes(t,i)}_removeChildren(t,e=1){const i=this._children._removeNodes(t,e);for(const t of i)t.parent=null;return i}static fromJSON(t){let e=null;if(t.children){e=[];for(const i of t.children)i.name?e.push(br.fromJSON(i)):e.push(mr.fromJSON(i))}return new br(t.name,t.attributes,e)}}class wr{constructor(t={}){if(!t.boundaries&&!t.startPosition)throw new hi.b("model-tree-walker-no-start-position: Neither boundaries nor starting position have been defined.",null);const e=t.direction||"forward";if("forward"!=e&&"backward"!=e)throw new hi.b("model-tree-walker-unknown-direction: Only `backward` and `forward` direction allowed.",t,{direction:e});this.direction=e,this.boundaries=t.boundaries||null,t.startPosition?this.position=t.startPosition.clone():this.position=_r._createAt(this.boundaries["backward"==this.direction?"end":"start"]),this.position.stickiness="toNone",this.singleCharacters=!!t.singleCharacters,this.shallow=!!t.shallow,this.ignoreElementEnd=!!t.ignoreElementEnd,this._boundaryStartParent=this.boundaries?this.boundaries.start.parent:null,this._boundaryEndParent=this.boundaries?this.boundaries.end.parent:null,this._visitedParent=this.position.parent}[Symbol.iterator](){return this}skip(t){let e,i,n,o;do{n=this.position,o=this._visitedParent,({done:e,value:i}=this.next())}while(!e&&t(i));e||(this.position=n,this._visitedParent=o)}next(){return"forward"==this.direction?this._next():this._previous()}_next(){const t=this.position,e=this.position.clone(),i=this._visitedParent;if(null===i.parent&&e.offset===i.maxOffset)return{done:!0};if(i===this._boundaryEndParent&&e.offset==this.boundaries.end.offset)return{done:!0};const n=e.textNode?e.textNode:e.nodeAfter;if(n instanceof br)return this.shallow?e.offset++:(e.path.push(0),this._visitedParent=n),this.position=e,kr("elementStart",n,t,e,1);if(n instanceof mr){let o;if(this.singleCharacters)o=1;else{let t=n.endOffset;this._boundaryEndParent==i&&this.boundaries.end.offset<t&&(t=this.boundaries.end.offset),o=t-e.offset}const s=e.offset-n.startOffset,r=new gr(n,s,o);return e.offset+=o,this.position=e,kr("text",r,t,e,o)}return e.path.pop(),e.offset++,this.position=e,this._visitedParent=i.parent,this.ignoreElementEnd?this._next():kr("elementEnd",i,t,e)}_previous(){const t=this.position,e=this.position.clone(),i=this._visitedParent;if(null===i.parent&&0===e.offset)return{done:!0};if(i==this._boundaryStartParent&&e.offset==this.boundaries.start.offset)return{done:!0};const n=e.textNode?e.textNode:e.nodeBefore;if(n instanceof br)return e.offset--,this.shallow?(this.position=e,kr("elementStart",n,t,e,1)):(e.path.push(n.maxOffset),this.position=e,this._visitedParent=n,this.ignoreElementEnd?this._previous():kr("elementEnd",n,t,e));if(n instanceof mr){let o;if(this.singleCharacters)o=1;else{let t=n.startOffset;this._boundaryStartParent==i&&this.boundaries.start.offset>t&&(t=this.boundaries.start.offset),o=e.offset-t}const s=e.offset-n.startOffset,r=new gr(n,s-o,o);return e.offset-=o,this.position=e,kr("text",r,t,e,o)}return e.path.pop(),this.position=e,this._visitedParent=i.parent,kr("elementStart",i,t,e,1)}}function kr(t,e,i,n,o){return{done:!1,value:{type:t,item:e,previousPosition:i,nextPosition:n,length:o}}}class _r{constructor(t,e,i="toNone"){if(!t.is("element")&&!t.is("documentFragment"))throw new hi.b("model-position-root-invalid: Position root invalid.",t);if(!(e instanceof Array)||0===e.length)throw new hi.b("model-position-path-incorrect-format: Position path must be an array with at least one item.",t,{path:e});e=t.getPath().concat(e),t=t.root,this.root=t,this.path=e,this.stickiness=i}get offset(){return Xi(this.path)}set offset(t){this.path[this.path.length-1]=t}get parent(){let t=this.root;for(let e=0;e<this.path.length-1;e++)if(t=t.getChild(t.offsetToIndex(this.path[e])),!t)throw new hi.b("model-position-path-incorrect: The position's path is incorrect.",this,{position:this});if(t.is("text"))throw new hi.b("model-position-path-incorrect: The position's path is incorrect.",this,{position:this});return t}get index(){return this.parent.offsetToIndex(this.offset)}get textNode(){const t=this.parent.getChild(this.index);return t instanceof mr&&t.startOffset<this.offset?t:null}get nodeAfter(){return null===this.textNode?this.parent.getChild(this.index):null}get nodeBefore(){return null===this.textNode?this.parent.getChild(this.index-1):null}get isAtStart(){return 0===this.offset}get isAtEnd(){return this.offset==this.parent.maxOffset}compareWith(t){if(this.root!=t.root)return"different";const e=Ei(this.path,t.path);switch(e){case"same":return"same";case"prefix":return"before";case"extension":return"after";default:return this.path[e]<t.path[e]?"before":"after"}}getLastMatchingPosition(t,e={}){e.startPosition=this;const i=new wr(e);return i.skip(t),i.position}getParentPath(){return this.path.slice(0,-1)}getAncestors(){return this.parent.is("documentFragment")?[this.parent]:this.parent.getAncestors({includeSelf:!0})}getCommonPath(t){if(this.root!=t.root)return[];const e=Ei(this.path,t.path),i="string"==typeof e?Math.min(this.path.length,t.path.length):e;return this.path.slice(0,i)}getCommonAncestor(t){const e=this.getAncestors(),i=t.getAncestors();let n=0;for(;e[n]==i[n]&&e[n];)n++;return 0===n?null:e[n-1]}getShiftedBy(t){const e=this.clone(),i=e.offset+t;return e.offset=i<0?0:i,e}isAfter(t){return"after"==this.compareWith(t)}isBefore(t){return"before"==this.compareWith(t)}isEqual(t){return"same"==this.compareWith(t)}isTouching(t){let e=null,i=null;switch(this.compareWith(t)){case"same":return!0;case"before":e=_r._createAt(this),i=_r._createAt(t);break;case"after":e=_r._createAt(t),i=_r._createAt(this);break;default:return!1}let n=e.parent;for(;e.path.length+i.path.length;){if(e.isEqual(i))return!0;if(e.path.length>i.path.length){if(e.offset!==n.maxOffset)return!1;e.path=e.path.slice(0,-1),n=n.parent,e.offset++}else{if(0!==i.offset)return!1;i.path=i.path.slice(0,-1)}}}is(t){return"position"==t||"model:position"==t}hasSameParentAs(t){if(this.root!==t.root)return!1;return"same"==Ei(this.getParentPath(),t.getParentPath())}getTransformedByOperation(t){let e;switch(t.type){case"insert":e=this._getTransformedByInsertOperation(t);break;case"move":case"remove":case"reinsert":e=this._getTransformedByMoveOperation(t);break;case"split":e=this._getTransformedBySplitOperation(t);break;case"merge":e=this._getTransformedByMergeOperation(t);break;default:e=_r._createAt(this)}return e}_getTransformedByInsertOperation(t){return this._getTransformedByInsertion(t.position,t.howMany)}_getTransformedByMoveOperation(t){return this._getTransformedByMove(t.sourcePosition,t.targetPosition,t.howMany)}_getTransformedBySplitOperation(t){const e=t.movedRange;return e.containsPosition(this)||e.start.isEqual(this)&&"toNext"==this.stickiness?this._getCombined(t.splitPosition,t.moveTargetPosition):t.graveyardPosition?this._getTransformedByMove(t.graveyardPosition,t.insertionPosition,1):this._getTransformedByInsertion(t.insertionPosition,1)}_getTransformedByMergeOperation(t){const e=t.movedRange;let i;return e.containsPosition(this)||e.start.isEqual(this)?(i=this._getCombined(t.sourcePosition,t.targetPosition),t.sourcePosition.isBefore(t.targetPosition)&&(i=i._getTransformedByDeletion(t.deletionPosition,1))):i=this.isEqual(t.deletionPosition)?_r._createAt(t.deletionPosition):this._getTransformedByMove(t.deletionPosition,t.graveyardPosition,1),i}_getTransformedByDeletion(t,e){const i=_r._createAt(this);if(this.root!=t.root)return i;if("same"==Ei(t.getParentPath(),this.getParentPath())){if(t.offset<this.offset){if(t.offset+e>this.offset)return null;i.offset-=e}}else if("prefix"==Ei(t.getParentPath(),this.getParentPath())){const n=t.path.length-1;if(t.offset<=this.path[n]){if(t.offset+e>this.path[n])return null;i.path[n]-=e}}return i}_getTransformedByInsertion(t,e){const i=_r._createAt(this);if(this.root!=t.root)return i;if("same"==Ei(t.getParentPath(),this.getParentPath()))(t.offset<this.offset||t.offset==this.offset&&"toPrevious"!=this.stickiness)&&(i.offset+=e);else if("prefix"==Ei(t.getParentPath(),this.getParentPath())){const n=t.path.length-1;t.offset<=this.path[n]&&(i.path[n]+=e)}return i}_getTransformedByMove(t,e,i){if(e=e._getTransformedByDeletion(t,i),t.isEqual(e))return _r._createAt(this);const n=this._getTransformedByDeletion(t,i);return null===n||t.isEqual(this)&&"toNext"==this.stickiness||t.getShiftedBy(i).isEqual(this)&&"toPrevious"==this.stickiness?this._getCombined(t,e):n._getTransformedByInsertion(e,i)}_getCombined(t,e){const i=t.path.length-1,n=_r._createAt(e);return n.stickiness=this.stickiness,n.offset=n.offset+this.path[i]-t.offset,n.path=n.path.concat(this.path.slice(i+1)),n}toJSON(){return{root:this.root.toJSON(),path:Array.from(this.path),stickiness:this.stickiness}}clone(){return new this.constructor(this.root,this.path,this.stickiness)}static _createAt(t,e,i="toNone"){if(t instanceof _r)return new _r(t.root,t.path,t.stickiness);{const n=t;if("end"==e)e=n.maxOffset;else{if("before"==e)return this._createBefore(n,i);if("after"==e)return this._createAfter(n,i);if(0!==e&&!e)throw new hi.b("model-createPositionAt-offset-required: Model#createPositionAt() requires the offset when the first parameter is a model item.",[this,t])}if(!n.is("element")&&!n.is("documentFragment"))throw new hi.b("model-position-parent-incorrect: Position parent have to be a element or document fragment.",[this,t]);const o=n.getPath();return o.push(e),new this(n.root,o,i)}}static _createAfter(t,e){if(!t.parent)throw new hi.b("model-position-after-root: You cannot make a position after root.",[this,t],{root:t});return this._createAt(t.parent,t.endOffset,e)}static _createBefore(t,e){if(!t.parent)throw new hi.b("model-position-before-root: You cannot make a position before root.",t,{root:t});return this._createAt(t.parent,t.startOffset,e)}static fromJSON(t,e){if("$graveyard"===t.root){const i=new _r(e.graveyard,t.path);return i.stickiness=t.stickiness,i}if(!e.getRoot(t.root))throw new hi.b("model-position-fromjson-no-root: Cannot create position for document. Root with specified name does not exist.",e,{rootName:t.root});return new _r(e.getRoot(t.root),t.path,t.stickiness)}}class vr{constructor(t,e=null){this.start=_r._createAt(t),this.end=e?_r._createAt(e):_r._createAt(t),this.start.stickiness=this.isCollapsed?"toNone":"toNext",this.end.stickiness=this.isCollapsed?"toNone":"toPrevious"}*[Symbol.iterator](){yield*new wr({boundaries:this,ignoreElementEnd:!0})}get isCollapsed(){return this.start.isEqual(this.end)}get isFlat(){return"same"==Ei(this.start.getParentPath(),this.end.getParentPath())}get root(){return this.start.root}containsPosition(t){return t.isAfter(this.start)&&t.isBefore(this.end)}containsRange(t,e=!1){t.isCollapsed&&(e=!1);const i=this.containsPosition(t.start)||e&&this.start.isEqual(t.start),n=this.containsPosition(t.end)||e&&this.end.isEqual(t.end);return i&&n}containsItem(t){const e=_r._createBefore(t);return this.containsPosition(e)||this.start.isEqual(e)}is(t){return"range"==t||"model:range"==t}isEqual(t){return this.start.isEqual(t.start)&&this.end.isEqual(t.end)}isIntersecting(t){return this.start.isBefore(t.end)&&this.end.isAfter(t.start)}getDifference(t){const e=[];return this.isIntersecting(t)?(this.containsPosition(t.start)&&e.push(new vr(this.start,t.start)),this.containsPosition(t.end)&&e.push(new vr(t.end,this.end))):e.push(new vr(this.start,this.end)),e}getIntersection(t){if(this.isIntersecting(t)){let e=this.start,i=this.end;return this.containsPosition(t.start)&&(e=t.start),this.containsPosition(t.end)&&(i=t.end),new vr(e,i)}return null}getMinimalFlatRanges(){const t=[],e=this.start.getCommonPath(this.end).length,i=_r._createAt(this.start);let n=i.parent;for(;i.path.length>e+1;){const e=n.maxOffset-i.offset;0!==e&&t.push(new vr(i,i.getShiftedBy(e))),i.path=i.path.slice(0,-1),i.offset++,n=n.parent}for(;i.path.length<=this.end.path.length;){const e=this.end.path[i.path.length-1],n=e-i.offset;0!==n&&t.push(new vr(i,i.getShiftedBy(n))),i.offset=e,i.path.push(0)}return t}getWalker(t={}){return t.boundaries=this,new wr(t)}*getItems(t={}){t.boundaries=this,t.ignoreElementEnd=!0;const e=new wr(t);for(const t of e)yield t.item}*getPositions(t={}){t.boundaries=this;const e=new wr(t);yield e.position;for(const t of e)yield t.nextPosition}getTransformedByOperation(t){switch(t.type){case"insert":return this._getTransformedByInsertOperation(t);case"move":case"remove":case"reinsert":return this._getTransformedByMoveOperation(t);case"split":return[this._getTransformedBySplitOperation(t)];case"merge":return[this._getTransformedByMergeOperation(t)]}return[new vr(this.start,this.end)]}getTransformedByOperations(t){const e=[new vr(this.start,this.end)];for(const i of t)for(let t=0;t<e.length;t++){const n=e[t].getTransformedByOperation(i);e.splice(t,1,...n),t+=n.length-1}for(let t=0;t<e.length;t++){const i=e[t];for(let n=t+1;n<e.length;n++){const t=e[n];(i.containsRange(t)||t.containsRange(i)||i.isEqual(t))&&e.splice(n,1)}}return e}getCommonAncestor(){return this.start.getCommonAncestor(this.end)}toJSON(){return{start:this.start.toJSON(),end:this.end.toJSON()}}clone(){return new this.constructor(this.start,this.end)}_getTransformedByInsertOperation(t,e=!1){return this._getTransformedByInsertion(t.position,t.howMany,e)}_getTransformedByMoveOperation(t,e=!1){const i=t.sourcePosition,n=t.howMany,o=t.targetPosition;return this._getTransformedByMove(i,o,n,e)}_getTransformedBySplitOperation(t){const e=this.start._getTransformedBySplitOperation(t);let i=this.end._getTransformedBySplitOperation(t);return this.end.isEqual(t.insertionPosition)&&(i=this.end.getShiftedBy(1)),e.root!=i.root&&(i=this.end.getShiftedBy(-1)),new vr(e,i)}_getTransformedByMergeOperation(t){if(this.start.isEqual(t.targetPosition)&&this.end.isEqual(t.deletionPosition))return new vr(this.start);let e=this.start._getTransformedByMergeOperation(t),i=this.end._getTransformedByMergeOperation(t);return e.root!=i.root&&(i=this.end.getShiftedBy(-1)),e.isAfter(i)?(t.sourcePosition.isBefore(t.targetPosition)?(e=_r._createAt(i),e.offset=0):(t.deletionPosition.isEqual(e)||(i=t.deletionPosition),e=t.targetPosition),new vr(e,i)):new vr(e,i)}_getTransformedByInsertion(t,e,i=!1){if(i&&this.containsPosition(t))return[new vr(this.start,t),new vr(t.getShiftedBy(e),this.end._getTransformedByInsertion(t,e))];{const i=new vr(this.start,this.end);return i.start=i.start._getTransformedByInsertion(t,e),i.end=i.end._getTransformedByInsertion(t,e),[i]}}_getTransformedByMove(t,e,i,n=!1){if(this.isCollapsed){const n=this.start._getTransformedByMove(t,e,i);return[new vr(n)]}const o=vr._createFromPositionAndShift(t,i),s=e._getTransformedByDeletion(t,i);if(this.containsPosition(e)&&!n&&(o.containsPosition(this.start)||o.containsPosition(this.end))){const n=this.start._getTransformedByMove(t,e,i),o=this.end._getTransformedByMove(t,e,i);return[new vr(n,o)]}let r;const a=this.getDifference(o);let c=null;const l=this.getIntersection(o);if(1==a.length?c=new vr(a[0].start._getTransformedByDeletion(t,i),a[0].end._getTransformedByDeletion(t,i)):2==a.length&&(c=new vr(this.start,this.end._getTransformedByDeletion(t,i))),r=c?c._getTransformedByInsertion(s,i,null!==l||n):[],l){const t=new vr(l.start._getCombined(o.start,s),l.end._getCombined(o.start,s));2==r.length?r.splice(1,0,t):r.push(t)}return r}_getTransformedByDeletion(t,e){let i=this.start._getTransformedByDeletion(t,e),n=this.end._getTransformedByDeletion(t,e);return null==i&&null==n?null:(null==i&&(i=t),null==n&&(n=t),new vr(i,n))}static _createFromPositionAndShift(t,e){const i=t,n=t.getShiftedBy(e);return e>0?new this(i,n):new this(n,i)}static _createIn(t){return new this(_r._createAt(t,0),_r._createAt(t,t.maxOffset))}static _createOn(t){return this._createFromPositionAndShift(_r._createBefore(t),t.offsetSize)}static _createFromRanges(t){if(0===t.length)throw new hi.b("range-create-from-ranges-empty-array: At least one range has to be passed.",null);if(1==t.length)return t[0].clone();const e=t[0];t.sort((t,e)=>t.start.isAfter(e.start)?1:-1);const i=t.indexOf(e),n=new this(e.start,e.end);if(i>0)for(let e=i-1;t[e].end.isEqual(n.start);e++)n.start=_r._createAt(t[e].start);for(let e=i+1;e<t.length&&t[e].start.isEqual(n.end);e++)n.end=_r._createAt(t[e].end);return n}static fromJSON(t,e){return new this(_r.fromJSON(t.start,e),_r.fromJSON(t.end,e))}}class yr{constructor(){this._modelToViewMapping=new WeakMap,this._viewToModelMapping=new WeakMap,this._viewToModelLengthCallbacks=new Map,this._markerNameToElements=new Map,this._elementToMarkerNames=new Map,this._unboundMarkerNames=new Set,this.on("modelToViewPosition",(t,e)=>{if(e.viewPosition)return;const i=this._modelToViewMapping.get(e.modelPosition.parent);e.viewPosition=this._findPositionIn(i,e.modelPosition.offset)},{priority:"low"}),this.on("viewToModelPosition",(t,e)=>{if(e.modelPosition)return;const i=this.findMappedViewAncestor(e.viewPosition),n=this._viewToModelMapping.get(i),o=this._toModelOffset(e.viewPosition.parent,e.viewPosition.offset,i);e.modelPosition=_r._createAt(n,o)},{priority:"low"})}bindElements(t,e){this._modelToViewMapping.set(t,e),this._viewToModelMapping.set(e,t)}unbindViewElement(t){const e=this.toModelElement(t);if(this._viewToModelMapping.delete(t),this._elementToMarkerNames.has(t))for(const e of this._elementToMarkerNames.get(t))this._unboundMarkerNames.add(e);this._modelToViewMapping.get(e)==t&&this._modelToViewMapping.delete(e)}unbindModelElement(t){const e=this.toViewElement(t);this._modelToViewMapping.delete(t),this._viewToModelMapping.get(e)==t&&this._viewToModelMapping.delete(e)}bindElementToMarker(t,e){const i=this._markerNameToElements.get(e)||new Set;i.add(t);const n=this._elementToMarkerNames.get(t)||new Set;n.add(e),this._markerNameToElements.set(e,i),this._elementToMarkerNames.set(t,n)}unbindElementFromMarkerName(t,e){const i=this._markerNameToElements.get(e);i&&(i.delete(t),0==i.size&&this._markerNameToElements.delete(e));const n=this._elementToMarkerNames.get(t);n&&(n.delete(e),0==n.size&&this._elementToMarkerNames.delete(t))}flushUnboundMarkerNames(){const t=Array.from(this._unboundMarkerNames);return this._unboundMarkerNames.clear(),t}clearBindings(){this._modelToViewMapping=new WeakMap,this._viewToModelMapping=new WeakMap,this._markerNameToElements=new Map,this._elementToMarkerNames=new Map,this._unboundMarkerNames=new Set}toModelElement(t){return this._viewToModelMapping.get(t)}toViewElement(t){return this._modelToViewMapping.get(t)}toModelRange(t){return new vr(this.toModelPosition(t.start),this.toModelPosition(t.end))}toViewRange(t){return new to(this.toViewPosition(t.start),this.toViewPosition(t.end))}toModelPosition(t){const e={viewPosition:t,mapper:this};return this.fire("viewToModelPosition",e),e.modelPosition}toViewPosition(t,e={isPhantom:!1}){const i={modelPosition:t,mapper:this,isPhantom:e.isPhantom};return this.fire("modelToViewPosition",i),i.viewPosition}markerNameToElements(t){const e=this._markerNameToElements.get(t);if(!e)return null;const i=new Set;for(const t of e)if(t.is("attributeElement"))for(const e of t.getElementsWithSameId())i.add(e);else i.add(t);return i}registerViewToModelLength(t,e){this._viewToModelLengthCallbacks.set(t,e)}findMappedViewAncestor(t){let e=t.parent;for(;!this._viewToModelMapping.has(e);)e=e.parent;return e}_toModelOffset(t,e,i){if(i!=t){return this._toModelOffset(t.parent,t.index,i)+this._toModelOffset(t,e,t)}if(t.is("text"))return e;let n=0;for(let i=0;i<e;i++)n+=this.getModelLength(t.getChild(i));return n}getModelLength(t){if(this._viewToModelLengthCallbacks.get(t.name)){return this._viewToModelLengthCallbacks.get(t.name)(t)}if(this._viewToModelMapping.has(t))return 1;if(t.is("text"))return t.data.length;if(t.is("uiElement"))return 0;{let e=0;for(const i of t.getChildren())e+=this.getModelLength(i);return e}}_findPositionIn(t,e){let i,n=0,o=0,s=0;if(t.is("text"))return new Xn(t,e);for(;o<e;)i=t.getChild(s),n=this.getModelLength(i),o+=n,s++;return o==e?this._moveViewPositionToTextNode(new Xn(t,s)):this._findPositionIn(i,e-(o-n))}_moveViewPositionToTextNode(t){const e=t.nodeBefore,i=t.nodeAfter;return e instanceof Ni?new Xn(e,e.data.length):i instanceof Ni?new Xn(i,0):t}}vi(yr,mi);class xr{constructor(){this._consumable=new Map,this._textProxyRegistry=new Map}add(t,e){e=Ar(e),t instanceof gr&&(t=this._getSymbolForTextProxy(t)),this._consumable.has(t)||this._consumable.set(t,new Map),this._consumable.get(t).set(e,!0)}consume(t,e){return e=Ar(e),t instanceof gr&&(t=this._getSymbolForTextProxy(t)),!!this.test(t,e)&&(this._consumable.get(t).set(e,!1),!0)}test(t,e){e=Ar(e),t instanceof gr&&(t=this._getSymbolForTextProxy(t));const i=this._consumable.get(t);if(void 0===i)return null;const n=i.get(e);return void 0===n?null:n}revert(t,e){e=Ar(e),t instanceof gr&&(t=this._getSymbolForTextProxy(t));const i=this.test(t,e);return!1===i?(this._consumable.get(t).set(e,!0),!0):!0!==i&&null}_getSymbolForTextProxy(t){let e=null;const i=this._textProxyRegistry.get(t.startOffset);if(i){const n=i.get(t.endOffset);n&&(e=n.get(t.parent))}return e||(e=this._addSymbolForTextProxy(t.startOffset,t.endOffset,t.parent)),e}_addSymbolForTextProxy(t,e,i){const n=Symbol("textProxySymbol");let o,s;return o=this._textProxyRegistry.get(t),o||(o=new Map,this._textProxyRegistry.set(t,o)),s=o.get(e),s||(s=new Map,o.set(e,s)),s.set(i,n),n}}function Ar(t){const e=t.split(":");return e.length>1?e[0]+":"+e[1]:e[0]}class Cr{constructor(t){this.conversionApi=zn({dispatcher:this},t)}convertChanges(t,e,i){for(const e of t.getMarkersToRemove())this.convertMarkerRemove(e.name,e.range,i);for(const e of t.getChanges())"insert"==e.type?this.convertInsert(vr._createFromPositionAndShift(e.position,e.length),i):"remove"==e.type?this.convertRemove(e.position,e.length,e.name,i):this.convertAttribute(e.range,e.attributeKey,e.attributeOldValue,e.attributeNewValue,i);for(const t of this.conversionApi.mapper.flushUnboundMarkerNames()){const n=e.get(t).getRange();this.convertMarkerRemove(t,n,i),this.convertMarkerAdd(t,n,i)}for(const e of t.getMarkersToAdd())this.convertMarkerAdd(e.name,e.range,i)}convertInsert(t,e){this.conversionApi.writer=e,this.conversionApi.consumable=this._createInsertConsumable(t);for(const e of t){const t=e.item,i={item:t,range:vr._createFromPositionAndShift(e.previousPosition,e.length)};this._testAndFire("insert",i);for(const e of t.getAttributeKeys())i.attributeKey=e,i.attributeOldValue=null,i.attributeNewValue=t.getAttribute(e),this._testAndFire(`attribute:${e}`,i)}this._clearConversionApi()}convertRemove(t,e,i,n){this.conversionApi.writer=n,this.fire("remove:"+i,{position:t,length:e},this.conversionApi),this._clearConversionApi()}convertAttribute(t,e,i,n,o){this.conversionApi.writer=o,this.conversionApi.consumable=this._createConsumableForRange(t,`attribute:${e}`);for(const o of t){const t={item:o.item,range:vr._createFromPositionAndShift(o.previousPosition,o.length),attributeKey:e,attributeOldValue:i,attributeNewValue:n};this._testAndFire(`attribute:${e}`,t)}this._clearConversionApi()}convertSelection(t,e,i){const n=Array.from(e.getMarkersAtPosition(t.getFirstPosition()));if(this.conversionApi.writer=i,this.conversionApi.consumable=this._createSelectionConsumable(t,n),this.fire("selection",{selection:t},this.conversionApi),t.isCollapsed){for(const e of n){const i=e.getRange();if(!Tr(t.getFirstPosition(),e,this.conversionApi.mapper))continue;const n={item:t,markerName:e.name,markerRange:i};this.conversionApi.consumable.test(t,"addMarker:"+e.name)&&this.fire("addMarker:"+e.name,n,this.conversionApi)}for(const e of t.getAttributeKeys()){const i={item:t,range:t.getFirstRange(),attributeKey:e,attributeOldValue:null,attributeNewValue:t.getAttribute(e)};this.conversionApi.consumable.test(t,"attribute:"+i.attributeKey)&&this.fire("attribute:"+i.attributeKey+":$text",i,this.conversionApi)}this._clearConversionApi()}}convertMarkerAdd(t,e,i){if(!e.root.document||"$graveyard"==e.root.rootName)return;this.conversionApi.writer=i;const n="addMarker:"+t,o=new xr;if(o.add(e,n),this.conversionApi.consumable=o,this.fire(n,{markerName:t,markerRange:e},this.conversionApi),o.test(e,n)){this.conversionApi.consumable=this._createConsumableForRange(e,n);for(const i of e.getItems()){if(!this.conversionApi.consumable.test(i,n))continue;const o={item:i,range:vr._createOn(i),markerName:t,markerRange:e};this.fire(n,o,this.conversionApi)}this._clearConversionApi()}}convertMarkerRemove(t,e,i){e.root.document&&"$graveyard"!=e.root.rootName&&(this.conversionApi.writer=i,this.fire("removeMarker:"+t,{markerName:t,markerRange:e},this.conversionApi),this._clearConversionApi())}_createInsertConsumable(t){const e=new xr;for(const i of t){const t=i.item;e.add(t,"insert");for(const i of t.getAttributeKeys())e.add(t,"attribute:"+i)}return e}_createConsumableForRange(t,e){const i=new xr;for(const n of t.getItems())i.add(n,e);return i}_createSelectionConsumable(t,e){const i=new xr;i.add(t,"selection");for(const n of e)i.add(t,"addMarker:"+n.name);for(const e of t.getAttributeKeys())i.add(t,"attribute:"+e);return i}_testAndFire(t,e){if(!this.conversionApi.consumable.test(e.item,t))return;const i=e.item.name||"$text";this.fire(t+":"+i,e,this.conversionApi)}_clearConversionApi(){delete this.conversionApi.writer,delete this.conversionApi.consumable}}function Tr(t,e,i){const n=e.getRange(),o=Array.from(t.getAncestors());return o.shift(),o.reverse(),!o.some(t=>{if(n.containsItem(t)){return!!i.toViewElement(t).getCustomProperty("addHighlight")}})}vi(Cr,mi);class Pr{constructor(t,e,i){this._lastRangeBackward=!1,this._ranges=[],this._attrs=new Map,t&&this.setTo(t,e,i)}get anchor(){if(this._ranges.length>0){const t=this._ranges[this._ranges.length-1];return this._lastRangeBackward?t.end:t.start}return null}get focus(){if(this._ranges.length>0){const t=this._ranges[this._ranges.length-1];return this._lastRangeBackward?t.start:t.end}return null}get isCollapsed(){return 1===this._ranges.length&&this._ranges[0].isCollapsed}get rangeCount(){return this._ranges.length}get isBackward(){return!this.isCollapsed&&this._lastRangeBackward}isEqual(t){if(this.rangeCount!=t.rangeCount)return!1;if(0===this.rangeCount)return!0;if(!this.anchor.isEqual(t.anchor)||!this.focus.isEqual(t.focus))return!1;for(const e of this._ranges){let i=!1;for(const n of t._ranges)if(e.isEqual(n)){i=!0;break}if(!i)return!1}return!0}*getRanges(){for(const t of this._ranges)yield new vr(t.start,t.end)}getFirstRange(){let t=null;for(const e of this._ranges)t&&!e.start.isBefore(t.start)||(t=e);return t?new vr(t.start,t.end):null}getLastRange(){let t=null;for(const e of this._ranges)t&&!e.end.isAfter(t.end)||(t=e);return t?new vr(t.start,t.end):null}getFirstPosition(){const t=this.getFirstRange();return t?t.start.clone():null}getLastPosition(){const t=this.getLastRange();return t?t.end.clone():null}setTo(t,e,i){if(null===t)this._setRanges([]);else if(t instanceof Pr)this._setRanges(t.getRanges(),t.isBackward);else if(t&&"function"==typeof t.getRanges)this._setRanges(t.getRanges(),t.isBackward);else if(t instanceof vr)this._setRanges([t],!!e&&!!e.backward);else if(t instanceof _r)this._setRanges([new vr(t)]);else if(t instanceof fr){const n=!!i&&!!i.backward;let o;if("in"==e)o=vr._createIn(t);else if("on"==e)o=vr._createOn(t);else{if(void 0===e)throw new hi.b("model-selection-setTo-required-second-parameter: selection.setTo requires the second parameter when the first parameter is a node.",[this,t]);o=new vr(_r._createAt(t,e))}this._setRanges([o],n)}else{if(!Ri(t))throw new hi.b("model-selection-setTo-not-selectable: Cannot set the selection to the given place.",[this,t]);this._setRanges(t,e&&!!e.backward)}}_setRanges(t,e=!1){const i=(t=Array.from(t)).some(e=>{if(!(e instanceof vr))throw new hi.b("model-selection-set-ranges-not-range: Selection range set to an object that is not an instance of model.Range.",[this,t]);return this._ranges.every(t=>!t.isEqual(e))});if(t.length!==this._ranges.length||i){this._removeAllRanges();for(const e of t)this._pushRange(e);this._lastRangeBackward=!!e,this.fire("change:range",{directChange:!0})}}setFocus(t,e){if(null===this.anchor)throw new hi.b("model-selection-setFocus-no-ranges: Cannot set selection focus if there are no ranges in selection.",[this,t]);const i=_r._createAt(t,e);if("same"==i.compareWith(this.focus))return;const n=this.anchor;this._ranges.length&&this._popRange(),"before"==i.compareWith(n)?(this._pushRange(new vr(i,n)),this._lastRangeBackward=!0):(this._pushRange(new vr(n,i)),this._lastRangeBackward=!1),this.fire("change:range",{directChange:!0})}getAttribute(t){return this._attrs.get(t)}getAttributes(){return this._attrs.entries()}getAttributeKeys(){return this._attrs.keys()}hasAttribute(t){return this._attrs.has(t)}removeAttribute(t){this.hasAttribute(t)&&(this._attrs.delete(t),this.fire("change:attribute",{attributeKeys:[t],directChange:!0}))}setAttribute(t,e){this.getAttribute(t)!==e&&(this._attrs.set(t,e),this.fire("change:attribute",{attributeKeys:[t],directChange:!0}))}getSelectedElement(){if(1!==this.rangeCount)return null;const t=this.getFirstRange(),e=t.start.nodeAfter,i=t.end.nodeBefore;return e instanceof br&&e==i?e:null}is(t){return"selection"==t||"model:selection"==t}*getSelectedBlocks(){const t=new WeakSet;for(const e of this.getRanges()){const i=Mr(e.start,t);i&&Ir(i,e)&&(yield i);for(const i of e.getWalker()){const n=i.item;"elementEnd"==i.type&&Er(n,t,e)&&(yield n)}const n=Mr(e.end,t);n&&!e.end.isTouching(_r._createAt(n,0))&&Ir(n,e)&&(yield n)}}containsEntireContent(t=this.anchor.root){const e=_r._createAt(t,0),i=_r._createAt(t,"end");return e.isTouching(this.getFirstPosition())&&i.isTouching(this.getLastPosition())}_pushRange(t){this._checkRange(t),this._ranges.push(new vr(t.start,t.end))}_checkRange(t){for(let e=0;e<this._ranges.length;e++)if(t.isIntersecting(this._ranges[e]))throw new hi.b("model-selection-range-intersects: Trying to add a range that intersects with another range in the selection.",[this,t],{addedRange:t,intersectingRange:this._ranges[e]})}_removeAllRanges(){for(;this._ranges.length>0;)this._popRange()}_popRange(){this._ranges.pop()}}function Sr(t,e){return!e.has(t)&&(e.add(t),t.document.model.schema.isBlock(t)&&t.parent)}function Er(t,e,i){return Sr(t,e)&&Ir(t,i)}function Mr(t,e){const i=t.parent.document.model.schema,n=t.parent.getAncestors({parentFirst:!0,includeSelf:!0});let o=!1;const s=n.find(t=>!o&&(o=i.isLimit(t),!o&&Sr(t,e)));return n.forEach(t=>e.add(t)),s}function Ir(t,e){const i=function(t){const e=t.document.model.schema;let i=t.parent;for(;i;){if(e.isBlock(i))return i;i=i.parent}}(t);return!i||!e.containsRange(vr._createOn(i),!0)}vi(Pr,mi);class Nr extends vr{constructor(t,e){super(t,e),Or.call(this)}detach(){this.stopListening()}is(t){return"liveRange"==t||"model:liveRange"==t||super.is(t)}toRange(){return new vr(this.start,this.end)}static fromRange(t){return new Nr(t.start,t.end)}}function Or(){this.listenTo(this.root.document.model,"applyOperation",(t,e)=>{const i=e[0];i.isDocumentOperation&&Rr.call(this,i)},{priority:"low"})}function Rr(t){const e=this.getTransformedByOperation(t),i=vr._createFromRanges(e),n=!i.isEqual(this),o=function(t,e){switch(e.type){case"insert":return t.containsPosition(e.position);case"move":case"remove":case"reinsert":case"merge":return t.containsPosition(e.sourcePosition)||t.start.isEqual(e.sourcePosition)||t.containsPosition(e.targetPosition);case"split":return t.containsPosition(e.splitPosition)||t.containsPosition(e.insertionPosition)}return!1}(this,t);let s=null;if(n){"$graveyard"==i.root.rootName&&(s="remove"==t.type?t.sourcePosition:t.deletionPosition);const e=this.toRange();this.start=i.start,this.end=i.end,this.fire("change:range",e,{deletionPosition:s})}else o&&this.fire("change:content",this.toRange(),{deletionPosition:s})}vi(Nr,mi);class Lr{constructor(t){this._selection=new Dr(t),this._selection.delegate("change:range").to(this),this._selection.delegate("change:attribute").to(this),this._selection.delegate("change:marker").to(this)}get isCollapsed(){return this._selection.isCollapsed}get anchor(){return this._selection.anchor}get focus(){return this._selection.focus}get rangeCount(){return this._selection.rangeCount}get hasOwnRange(){return this._selection.hasOwnRange}get isBackward(){return this._selection.isBackward}get isGravityOverridden(){return this._selection.isGravityOverridden}get markers(){return this._selection.markers}get _ranges(){return this._selection._ranges}getRanges(){return this._selection.getRanges()}getFirstPosition(){return this._selection.getFirstPosition()}getLastPosition(){return this._selection.getLastPosition()}getFirstRange(){return this._selection.getFirstRange()}getLastRange(){return this._selection.getLastRange()}getSelectedBlocks(){return this._selection.getSelectedBlocks()}getSelectedElement(){return this._selection.getSelectedElement()}containsEntireContent(t){return this._selection.containsEntireContent(t)}destroy(){this._selection.destroy()}getAttributeKeys(){return this._selection.getAttributeKeys()}getAttributes(){return this._selection.getAttributes()}getAttribute(t){return this._selection.getAttribute(t)}hasAttribute(t){return this._selection.hasAttribute(t)}refresh(){this._selection._updateMarkers(),this._selection._updateAttributes(!1)}is(t){return"selection"==t||"model:selection"==t||"documentSelection"==t||"model:documentSelection"==t}_setFocus(t,e){this._selection.setFocus(t,e)}_setTo(t,e,i){this._selection.setTo(t,e,i)}_setAttribute(t,e){this._selection.setAttribute(t,e)}_removeAttribute(t){this._selection.removeAttribute(t)}_getStoredAttributes(){return this._selection._getStoredAttributes()}_overrideGravity(){return this._selection.overrideGravity()}_restoreGravity(t){this._selection.restoreGravity(t)}static _getStoreAttributeKey(t){return"selection:"+t}static _isStoreAttributeKey(t){return t.startsWith("selection:")}}vi(Lr,mi);class Dr extends Pr{constructor(t){super(),this.markers=new yi({idProperty:"name"}),this._model=t.model,this._document=t,this._attributePriority=new Map,this._fixGraveyardRangesData=[],this._hasChangedRange=!1,this._overriddenGravityRegister=new Set,this.listenTo(this._model,"applyOperation",(t,e)=>{const i=e[0];if(i.isDocumentOperation&&"marker"!=i.type&&"rename"!=i.type&&"noop"!=i.type){for(;this._fixGraveyardRangesData.length;){const{liveRange:t,sourcePosition:e}=this._fixGraveyardRangesData.shift();this._fixGraveyardSelection(t,e)}this._hasChangedRange&&(this._hasChangedRange=!1,this.fire("change:range",{directChange:!1}))}},{priority:"lowest"}),this.on("change:range",()=>{for(const t of this.getRanges())if(!this._document._validateSelectionRange(t))throw new hi.b("document-selection-wrong-position: Range from document selection starts or ends at incorrect position.",this,{range:t})}),this.listenTo(this._model.markers,"update",()=>this._updateMarkers()),this.listenTo(this._document,"change",(t,e)=>{!function(t,e){const i=t.document.differ;for(const n of i.getChanges()){if("insert"!=n.type)continue;const i=n.position.parent;n.length===i.maxOffset&&t.enqueueChange(e,t=>{const e=Array.from(i.getAttributeKeys()).filter(t=>t.startsWith("selection:"));for(const n of e)t.removeAttribute(n,i)})}}(this._model,e)})}get isCollapsed(){return 0===this._ranges.length?this._document._getDefaultRange().isCollapsed:super.isCollapsed}get anchor(){return super.anchor||this._document._getDefaultRange().start}get focus(){return super.focus||this._document._getDefaultRange().end}get rangeCount(){return this._ranges.length?this._ranges.length:1}get hasOwnRange(){return this._ranges.length>0}get isGravityOverridden(){return!!this._overriddenGravityRegister.size}destroy(){for(let t=0;t<this._ranges.length;t++)this._ranges[t].detach();this.stopListening()}*getRanges(){this._ranges.length?yield*super.getRanges():yield this._document._getDefaultRange()}getFirstRange(){return super.getFirstRange()||this._document._getDefaultRange()}getLastRange(){return super.getLastRange()||this._document._getDefaultRange()}setTo(t,e,i){super.setTo(t,e,i),this._updateAttributes(!0),this._updateMarkers()}setFocus(t,e){super.setFocus(t,e),this._updateAttributes(!0),this._updateMarkers()}setAttribute(t,e){if(this._setAttribute(t,e)){const e=[t];this.fire("change:attribute",{attributeKeys:e,directChange:!0})}}removeAttribute(t){if(this._removeAttribute(t)){const e=[t];this.fire("change:attribute",{attributeKeys:e,directChange:!0})}}overrideGravity(){const t=li();return this._overriddenGravityRegister.add(t),1===this._overriddenGravityRegister.size&&this._updateAttributes(!0),t}restoreGravity(t){if(!this._overriddenGravityRegister.has(t))throw new hi.b("document-selection-gravity-wrong-restore: Attempting to restore the selection gravity for an unknown UID.",this,{uid:t});this._overriddenGravityRegister.delete(t),this.isGravityOverridden||this._updateAttributes(!0)}_popRange(){this._ranges.pop().detach()}_pushRange(t){const e=this._prepareRange(t);e&&this._ranges.push(e)}_prepareRange(t){if(this._checkRange(t),t.root==this._document.graveyard)return;const e=Nr.fromRange(t);return e.on("change:range",(t,i,n)=>{this._hasChangedRange=!0,e.root==this._document.graveyard&&this._fixGraveyardRangesData.push({liveRange:e,sourcePosition:n.deletionPosition})}),e}_updateMarkers(){const t=[];let e=!1;for(const e of this._model.markers){const i=e.getRange();for(const n of this.getRanges())i.containsRange(n,!n.isCollapsed)&&t.push(e)}const i=Array.from(this.markers);for(const i of t)this.markers.has(i)||(this.markers.add(i),e=!0);for(const i of Array.from(this.markers))t.includes(i)||(this.markers.remove(i),e=!0);e&&this.fire("change:marker",{oldMarkers:i,directChange:!1})}_updateAttributes(t){const e=Li(this._getSurroundingAttributes()),i=Li(this.getAttributes());if(t)this._attributePriority=new Map,this._attrs=new Map;else for(const[t,e]of this._attributePriority)"low"==e&&(this._attrs.delete(t),this._attributePriority.delete(t));this._setAttributesTo(e);const n=[];for(const[t,e]of this.getAttributes())i.has(t)&&i.get(t)===e||n.push(t);for(const[t]of i)this.hasAttribute(t)||n.push(t);n.length>0&&this.fire("change:attribute",{attributeKeys:n,directChange:!1})}_setAttribute(t,e,i=!0){const n=i?"normal":"low";return("low"!=n||"normal"!=this._attributePriority.get(t))&&(super.getAttribute(t)!==e&&(this._attrs.set(t,e),this._attributePriority.set(t,n),!0))}_removeAttribute(t,e=!0){const i=e?"normal":"low";return("low"!=i||"normal"!=this._attributePriority.get(t))&&(this._attributePriority.set(t,i),!!super.hasAttribute(t)&&(this._attrs.delete(t),!0))}_setAttributesTo(t){const e=new Set;for(const[e,i]of this.getAttributes())t.get(e)!==i&&this._removeAttribute(e,!1);for(const[i,n]of t){this._setAttribute(i,n,!1)&&e.add(i)}return e}*_getStoredAttributes(){const t=this.getFirstPosition().parent;if(this.isCollapsed&&t.isEmpty)for(const e of t.getAttributeKeys())if(e.startsWith("selection:")){const i=e.substr("selection:".length);yield[i,t.getAttribute(e)]}}_getSurroundingAttributes(){const t=this.getFirstPosition(),e=this._model.schema;let i=null;if(this.isCollapsed){const e=t.textNode?t.textNode:t.nodeBefore,n=t.textNode?t.textNode:t.nodeAfter;if(this.isGravityOverridden||(i=zr(e)),i||(i=zr(n)),!this.isGravityOverridden&&!i){let t=e;for(;t&&!i;)t=t.previousSibling,i=zr(t)}if(!i){let t=n;for(;t&&!i;)t=t.nextSibling,i=zr(t)}i||(i=this._getStoredAttributes())}else{const t=this.getFirstRange();for(const n of t){if(n.item.is("element")&&e.isObject(n.item))break;if("text"==n.type){i=n.item.getAttributes();break}}}return i}_fixGraveyardSelection(t,e){const i=e.clone(),n=this._model.schema.getNearestSelectionRange(i),o=this._ranges.indexOf(t);if(this._ranges.splice(o,1),t.detach(),n){const t=this._prepareRange(n);this._ranges.splice(o,0,t)}}}function zr(t){return t instanceof gr||t instanceof mr?t.getAttributes():null}class jr{constructor(t){this._dispatchers=t}add(t){for(const e of this._dispatchers)t(e);return this}}var Vr=function(t){return ti(t,5)};class Br extends jr{elementToElement(t){return this.add(function(t){return(t=Vr(t)).view=Hr(t.view,"container"),e=>{var i;e.on("insert:"+t.model,(i=t.view,(t,e,n)=>{const o=i(e.item,n.writer);if(!o)return;if(!n.consumable.consume(e.item,"insert"))return;const s=n.mapper.toViewPosition(e.range.start);n.mapper.bindElements(e.item,o),n.writer.insert(s,o)}),{priority:t.converterPriority||"normal"})}}(t))}attributeToElement(t){return this.add(function(t){let e="attribute:"+((t=Vr(t)).model.key?t.model.key:t.model);t.model.name&&(e+=":"+t.model.name);if(t.model.values)for(const e of t.model.values)t.view[e]=Hr(t.view[e],"attribute");else t.view=Hr(t.view,"attribute");const i=Ur(t);return n=>{n.on(e,function(t){return(e,i,n)=>{const o=t(i.attributeOldValue,n.writer),s=t(i.attributeNewValue,n.writer);if(!o&&!s)return;if(!n.consumable.consume(i.item,e.name))return;const r=n.writer,a=r.document.selection;if(i.item instanceof Pr||i.item instanceof Lr)r.wrap(a.getFirstRange(),s);else{let t=n.mapper.toViewRange(i.range);null!==i.attributeOldValue&&o&&(t=r.unwrap(t,o)),null!==i.attributeNewValue&&s&&r.wrap(t,s)}}}(i),{priority:t.converterPriority||"normal"})}}(t))}attributeToAttribute(t){return this.add(function(t){let e="attribute:"+((t=Vr(t)).model.key?t.model.key:t.model);t.model.name&&(e+=":"+t.model.name);if(t.model.values)for(const e of t.model.values)t.view[e]=Wr(t.view[e]);else t.view=Wr(t.view);const i=Ur(t);return n=>{var o;n.on(e,(o=i,(t,e,i)=>{const n=o(e.attributeOldValue,e),s=o(e.attributeNewValue,e);if(!n&&!s)return;if(!i.consumable.consume(e.item,t.name))return;const r=i.mapper.toViewElement(e.item),a=i.writer;if(!r)throw new hi.b("conversion-attribute-to-attribute-on-text: Trying to convert text node's attribute with attribute-to-attribute converter.",[e,i]);if(null!==e.attributeOldValue&&n)if("class"==n.key){const t=Array.isArray(n.value)?n.value:[n.value];for(const e of t)a.removeClass(e,r)}else if("style"==n.key){const t=Object.keys(n.value);for(const e of t)a.removeStyle(e,r)}else a.removeAttribute(n.key,r);if(null!==e.attributeNewValue&&s)if("class"==s.key){const t=Array.isArray(s.value)?s.value:[s.value];for(const e of t)a.addClass(e,r)}else if("style"==s.key){const t=Object.keys(s.value);for(const e of t)a.setStyle(e,s.value[e],r)}else a.setAttribute(s.key,s.value,r)}),{priority:t.converterPriority||"normal"})}}(t))}markerToElement(t){return this.add(function(t){return(t=Vr(t)).view=Hr(t.view,"ui"),e=>{var i;e.on("addMarker:"+t.model,(i=t.view,(t,e,n)=>{e.isOpening=!0;const o=i(e,n.writer);e.isOpening=!1;const s=i(e,n.writer);if(!o||!s)return;const r=e.markerRange;if(r.isCollapsed&&!n.consumable.consume(r,t.name))return;for(const e of r)if(!n.consumable.consume(e.item,t.name))return;const a=n.mapper,c=n.writer;c.insert(a.toViewPosition(r.start),o),n.mapper.bindElementToMarker(o,e.markerName),r.isCollapsed||(c.insert(a.toViewPosition(r.end),s),n.mapper.bindElementToMarker(s,e.markerName)),t.stop()}),{priority:t.converterPriority||"normal"}),e.on("removeMarker:"+t.model,(t.view,(t,e,i)=>{const n=i.mapper.markerNameToElements(e.markerName);if(n){for(const t of n)i.mapper.unbindElementFromMarkerName(t,e.markerName),i.writer.clear(i.writer.createRangeOn(t),t);i.writer.clearClonedElementsGroup(e.markerName),t.stop()}}),{priority:t.converterPriority||"normal"})}}(t))}markerToHighlight(t){return this.add(function(t){return e=>{var i;e.on("addMarker:"+t.model,(i=t.view,(t,e,n)=>{if(!e.item)return;if(!(e.item instanceof Pr||e.item instanceof Lr||e.item.is("textProxy")))return;const o=qr(i,e,n);if(!o)return;if(!n.consumable.consume(e.item,t.name))return;const s=Fr(o),r=n.writer,a=r.document.selection;if(e.item instanceof Pr||e.item instanceof Lr)r.wrap(a.getFirstRange(),s,a);else{const t=n.mapper.toViewRange(e.range),i=r.wrap(t,s);for(const t of i.getItems())if(t.is("attributeElement")&&t.isSimilar(s)){n.mapper.bindElementToMarker(t,e.markerName);break}}}),{priority:t.converterPriority||"normal"}),e.on("addMarker:"+t.model,function(t){return(e,i,n)=>{if(!i.item)return;if(!(i.item instanceof br))return;const o=qr(t,i,n);if(!o)return;if(!n.consumable.test(i.item,e.name))return;const s=n.mapper.toViewElement(i.item);if(s&&s.getCustomProperty("addHighlight")){n.consumable.consume(i.item,e.name);for(const t of vr._createIn(i.item))n.consumable.consume(t.item,e.name);s.getCustomProperty("addHighlight")(s,o,n.writer),n.mapper.bindElementToMarker(s,i.markerName)}}}(t.view),{priority:t.converterPriority||"normal"}),e.on("removeMarker:"+t.model,function(t){return(e,i,n)=>{if(i.markerRange.isCollapsed)return;const o=qr(t,i,n);if(!o)return;const s=Fr(o),r=n.mapper.markerNameToElements(i.markerName);if(r){for(const t of r)n.mapper.unbindElementFromMarkerName(t,i.markerName),t.is("attributeElement")?n.writer.unwrap(n.writer.createRangeOn(t),s):t.getCustomProperty("removeHighlight")(t,o.id,n.writer);n.writer.clearClonedElementsGroup(i.markerName),e.stop()}}}(t.view),{priority:t.converterPriority||"normal"})}}(t))}}function Fr(t){const e=new ro("span",t.attributes);return t.classes&&e._addClass(t.classes),t.priority&&(e._priority=t.priority),e._id=t.id,e}function Hr(t,e){return"function"==typeof t?t:(i,n)=>function(t,e,i){"string"==typeof t&&(t={name:t});let n;const o=Object.assign({},t.attributes);if("container"==i)n=e.createContainerElement(t.name,o);else if("attribute"==i){const i={priority:t.priority||ro.DEFAULT_PRIORITY};n=e.createAttributeElement(t.name,o,i)}else n=e.createUIElement(t.name,o);if(t.styles){const i=Object.keys(t.styles);for(const o of i)e.setStyle(o,t.styles[o],n)}if(t.classes){const i=t.classes;if("string"==typeof i)e.addClass(i,n);else for(const t of i)e.addClass(t,n)}return n}(t,n,e)}function Ur(t){return t.model.values?(e,i)=>{const n=t.view[e];return n?n(e,i):null}:t.view}function Wr(t){return"string"==typeof t?e=>({key:t,value:e}):"object"==typeof t?t.value?()=>t:e=>({key:t.key,value:e}):t}function qr(t,e,i){const n="function"==typeof t?t(e,i):t;return n?(n.priority||(n.priority=10),n.id||(n.id=e.markerName),n):null}class $r extends jr{elementToElement(t){return this.add(Yr(t))}elementToAttribute(t){return this.add(function(t){Qr(t=Vr(t));const e=Kr(t,!1),i=Gr(t.view),n=i?"element:"+i:"element";return i=>{i.on(n,e,{priority:t.converterPriority||"low"})}}(t))}attributeToAttribute(t){return this.add(function(t){t=Vr(t);let e=null;("string"==typeof t.view||t.view.key)&&(e=function(t){"string"==typeof t.view&&(t.view={key:t.view});const e=t.view.key;let i;if("class"==e||"style"==e){i={["class"==e?"classes":"styles"]:t.view.value}}else{const n=void 0===t.view.value?/[\s\S]*/:t.view.value;i={attributes:{[e]:n}}}t.view.name&&(i.name=t.view.name);return t.view=i,e}(t));Qr(t,e);const i=Kr(t,!0);return e=>{e.on("element",i,{priority:t.converterPriority||"low"})}}(t))}elementToMarker(t){return this.add(function(t){return function(t){const e=t.model;t.model=(t,i)=>{const n="string"==typeof e?e:e(t);return i.createElement("$marker",{"data-name":n})}}(t=Vr(t)),Yr(t)}(t))}}function Yr(t){const e=function(t){const e=t.view?new Di(t.view):null;return(i,n,o)=>{let s={};if(e){const t=e.match(n.viewItem);if(!t)return;s=t.match}s.name=!0;const r=(a=t.model,c=n.viewItem,l=o.writer,a instanceof Function?a(c,l):l.createElement(a));var a,c,l;if(!r)return;if(!o.consumable.test(n.viewItem,s))return;const d=o.splitToAllowedParent(r,n.modelCursor);if(!d)return;o.writer.insert(r,d.position),o.convertChildren(n.viewItem,o.writer.createPositionAt(r,0)),o.consumable.consume(n.viewItem,s);const h=o.getSplitParts(r);n.modelRange=new vr(o.writer.createPositionBefore(r),o.writer.createPositionAfter(h[h.length-1])),d.cursorParent?n.modelCursor=o.writer.createPositionAt(d.cursorParent,0):n.modelCursor=n.modelRange.end}}(t=Vr(t)),i=Gr(t.view),n=i?"element:"+i:"element";return i=>{i.on(n,e,{priority:t.converterPriority||"normal"})}}function Gr(t){return"string"==typeof t?t:"object"==typeof t&&"string"==typeof t.name?t.name:null}function Qr(t,e=null){const i=null===e||(t=>t.getAttribute(e)),n="object"!=typeof t.model?t.model:t.model.key,o="object"!=typeof t.model||void 0===t.model.value?i:t.model.value;t.model={key:n,value:o}}function Kr(t,e){const i=new Di(t.view);return(n,o,s)=>{const r=i.match(o.viewItem);if(!r)return;const a=t.model.key,c="function"==typeof t.model.value?t.model.value(o.viewItem):t.model.value;null!==c&&(!function(t,e){const i="function"==typeof t?t(e):t;if("object"==typeof i&&!Gr(i))return!1;return!i.classes&&!i.attributes&&!i.styles}(t.view,o.viewItem)?delete r.match.name:r.match.name=!0,s.consumable.test(o.viewItem,r.match)&&(o.modelRange||(o=Object.assign(o,s.convertChildren(o.viewItem,o.modelCursor))),function(t,e,i,n){let o=!1;for(const s of Array.from(t.getItems({shallow:i})))n.schema.checkAttribute(s,e.key)&&(n.writer.setAttribute(e.key,e.value,s),o=!0);return o}(o.modelRange,{key:a,value:c},e,s)&&s.consumable.consume(o.viewItem,r.match)))}}class Jr{constructor(t){this.model=t,this.view=new ur,this.mapper=new yr,this.downcastDispatcher=new Cr({mapper:this.mapper});const e=this.model.document,i=e.selection,n=this.model.markers;this.listenTo(this.model,"_beforeChanges",()=>{this.view._disableRendering(!0)},{priority:"highest"}),this.listenTo(this.model,"_afterChanges",()=>{this.view._disableRendering(!1)},{priority:"lowest"}),this.listenTo(e,"change",()=>{this.view.change(t=>{this.downcastDispatcher.convertChanges(e.differ,n,t),this.downcastDispatcher.convertSelection(i,n,t)})},{priority:"low"}),this.listenTo(this.view.document,"selectionChange",function(t,e){return(i,n)=>{const o=n.newSelection,s=new Pr,r=[];for(const t of o.getRanges())r.push(e.toModelRange(t));s.setTo(r,{backward:o.isBackward}),s.isEqual(t.document.selection)||t.change(t=>{t.setSelection(s)})}}(this.model,this.mapper)),this.downcastDispatcher.on("insert:$text",(t,e,i)=>{if(!i.consumable.consume(e.item,"insert"))return;const n=i.writer,o=i.mapper.toViewPosition(e.range.start),s=n.createText(e.item.data);n.insert(o,s)},{priority:"lowest"}),this.downcastDispatcher.on("remove",(t,e,i)=>{const n=i.mapper.toViewPosition(e.position),o=e.position.getShiftedBy(e.length),s=i.mapper.toViewPosition(o,{isPhantom:!0}),r=i.writer.createRange(n,s),a=i.writer.remove(r.getTrimmed());for(const t of i.writer.createRangeIn(a).getItems())i.mapper.unbindViewElement(t)},{priority:"low"}),this.downcastDispatcher.on("selection",(t,e,i)=>{const n=i.writer,o=n.document.selection;for(const t of o.getRanges())t.isCollapsed&&t.end.parent.document&&i.writer.mergeAttributes(t.start);n.setSelection(null)},{priority:"low"}),this.downcastDispatcher.on("selection",(t,e,i)=>{const n=e.selection;if(n.isCollapsed)return;if(!i.consumable.consume(n,"selection"))return;const o=[];for(const t of n.getRanges()){const e=i.mapper.toViewRange(t);o.push(e)}i.writer.setSelection(o,{backward:n.isBackward})},{priority:"low"}),this.downcastDispatcher.on("selection",(t,e,i)=>{const n=e.selection;if(!n.isCollapsed)return;if(!i.consumable.consume(n,"selection"))return;const o=i.writer,s=n.getFirstPosition(),r=i.mapper.toViewPosition(s),a=o.breakAttributes(r);o.setSelection(a)},{priority:"low"}),this.view.document.roots.bindTo(this.model.document.roots).using(t=>{if("$graveyard"==t.rootName)return null;const e=new Jn(t.name);return e.rootName=t.rootName,e._document=this.view.document,this.mapper.bindElements(t,e),e})}destroy(){this.view.destroy(),this.stopListening()}}vi(Jr,Hn);class Zr{constructor(){this._commands=new Map}add(t,e){this._commands.set(t,e)}get(t){return this._commands.get(t)}execute(t,...e){const i=this.get(t);if(!i)throw new hi.b("commandcollection-command-not-found: Command does not exist.",this,{commandName:t});i.execute(...e)}*names(){yield*this._commands.keys()}*commands(){yield*this._commands.values()}[Symbol.iterator](){return this._commands[Symbol.iterator]()}destroy(){for(const t of this.commands())t.destroy()}}class Xr{constructor(){this._consumables=new Map}add(t,e){let i;t.is("text")||t.is("documentFragment")?this._consumables.set(t,!0):(this._consumables.has(t)?i=this._consumables.get(t):(i=new ta,this._consumables.set(t,i)),i.add(e))}test(t,e){const i=this._consumables.get(t);return void 0===i?null:t.is("text")||t.is("documentFragment")?i:i.test(e)}consume(t,e){return!!this.test(t,e)&&(t.is("text")||t.is("documentFragment")?this._consumables.set(t,!1):this._consumables.get(t).consume(e),!0)}revert(t,e){const i=this._consumables.get(t);void 0!==i&&(t.is("text")||t.is("documentFragment")?this._consumables.set(t,!0):i.revert(e))}static consumablesFromElement(t){const e={name:!0,attributes:[],classes:[],styles:[]},i=t.getAttributeKeys();for(const t of i)"style"!=t&&"class"!=t&&e.attributes.push(t);const n=t.getClassNames();for(const t of n)e.classes.push(t);const o=t.getStyleNames();for(const t of o)e.styles.push(t);return e}static createFrom(t,e){if(e||(e=new Xr),t.is("text"))return e.add(t),e;t.is("element")&&e.add(t,Xr.consumablesFromElement(t)),t.is("documentFragment")&&e.add(t);for(const i of t.getChildren())e=Xr.createFrom(i,e);return e}}class ta{constructor(){this._canConsumeName=null,this._consumables={attributes:new Map,styles:new Map,classes:new Map}}add(t){t.name&&(this._canConsumeName=!0);for(const e in this._consumables)e in t&&this._add(e,t[e])}test(t){if(t.name&&!this._canConsumeName)return this._canConsumeName;for(const e in this._consumables)if(e in t){const i=this._test(e,t[e]);if(!0!==i)return i}return!0}consume(t){t.name&&(this._canConsumeName=!1);for(const e in this._consumables)e in t&&this._consume(e,t[e])}revert(t){t.name&&(this._canConsumeName=!0);for(const e in this._consumables)e in t&&this._revert(e,t[e])}_add(t,e){const i=Lt(e)?e:[e],n=this._consumables[t];for(const e of i){if("attributes"===t&&("class"===e||"style"===e))throw new hi.b("viewconsumable-invalid-attribute: Classes and styles should be handled separately.",this);if(n.set(e,!0),"styles"===t)for(const t of En.getRelatedStyles(e))n.set(t,!0)}}_test(t,e){const i=Lt(e)?e:[e],n=this._consumables[t];for(const e of i)if("attributes"!==t||"class"!==e&&"style"!==e){const t=n.get(e);if(void 0===t)return null;if(!t)return!1}else{const t="class"==e?"classes":"styles",i=this._test(t,[...this._consumables[t].keys()]);if(!0!==i)return i}return!0}_consume(t,e){const i=Lt(e)?e:[e],n=this._consumables[t];for(const e of i)if("attributes"!==t||"class"!==e&&"style"!==e){if(n.set(e,!1),"styles"==t)for(const t of En.getRelatedStyles(e))n.set(t,!1)}else{const t="class"==e?"classes":"styles";this._consume(t,[...this._consumables[t].keys()])}}_revert(t,e){const i=Lt(e)?e:[e],n=this._consumables[t];for(const e of i)if("attributes"!==t||"class"!==e&&"style"!==e){!1===n.get(e)&&n.set(e,!0)}else{const t="class"==e?"classes":"styles";this._revert(t,[...this._consumables[t].keys()])}}}class ea{constructor(){this._sourceDefinitions={},this._attributeProperties={},this.decorate("checkChild"),this.decorate("checkAttribute"),this.on("checkAttribute",(t,e)=>{e[0]=new ia(e[0])},{priority:"highest"}),this.on("checkChild",(t,e)=>{e[0]=new ia(e[0]),e[1]=this.getDefinition(e[1])},{priority:"highest"})}register(t,e){if(this._sourceDefinitions[t])throw new hi.b("schema-cannot-register-item-twice: A single item cannot be registered twice in the schema.",this,{itemName:t});this._sourceDefinitions[t]=[Object.assign({},e)],this._clearCache()}extend(t,e){if(!this._sourceDefinitions[t])throw new hi.b("schema-cannot-extend-missing-item: Cannot extend an item which was not registered yet.",this,{itemName:t});this._sourceDefinitions[t].push(Object.assign({},e)),this._clearCache()}getDefinitions(){return this._compiledDefinitions||this._compile(),this._compiledDefinitions}getDefinition(t){let e;return e="string"==typeof t?t:t.is&&(t.is("text")||t.is("textProxy"))?"$text":t.name,this.getDefinitions()[e]}isRegistered(t){return!!this.getDefinition(t)}isBlock(t){const e=this.getDefinition(t);return!(!e||!e.isBlock)}isLimit(t){const e=this.getDefinition(t);return!!e&&!(!e.isLimit&&!e.isObject)}isObject(t){const e=this.getDefinition(t);return!(!e||!e.isObject)}isInline(t){const e=this.getDefinition(t);return!(!e||!e.isInline)}checkChild(t,e){return!!e&&this._checkContextMatch(e,t)}checkAttribute(t,e){const i=this.getDefinition(t.last);return!!i&&i.allowAttributes.includes(e)}checkMerge(t,e=null){if(t instanceof _r){const e=t.nodeBefore,i=t.nodeAfter;if(!(e instanceof br))throw new hi.b("schema-check-merge-no-element-before: The node before the merge position must be an element.",this);if(!(i instanceof br))throw new hi.b("schema-check-merge-no-element-after: The node after the merge position must be an element.",this);return this.checkMerge(e,i)}for(const i of e.getChildren())if(!this.checkChild(t,i))return!1;return!0}addChildCheck(t){this.on("checkChild",(e,[i,n])=>{if(!n)return;const o=t(i,n);"boolean"==typeof o&&(e.stop(),e.return=o)},{priority:"high"})}addAttributeCheck(t){this.on("checkAttribute",(e,[i,n])=>{const o=t(i,n);"boolean"==typeof o&&(e.stop(),e.return=o)},{priority:"high"})}setAttributeProperties(t,e){this._attributeProperties[t]=Object.assign(this.getAttributeProperties(t),e)}getAttributeProperties(t){return this._attributeProperties[t]||{}}getLimitElement(t){let e;if(t instanceof _r)e=t.parent;else{e=(t instanceof vr?[t]:Array.from(t.getRanges())).reduce((t,e)=>{const i=e.getCommonAncestor();return t?t.getCommonAncestor(i,{includeSelf:!0}):i},null)}for(;!this.isLimit(e)&&e.parent;)e=e.parent;return e}checkAttributeInSelection(t,e){if(t.isCollapsed){const i=[...t.getFirstPosition().getAncestors(),new mr("",t.getAttributes())];return this.checkAttribute(i,e)}{const i=t.getRanges();for(const t of i)for(const i of t)if(this.checkAttribute(i.item,e))return!0}return!1}*getValidRanges(t,e){t=function*(t){for(const e of t)yield*e.getMinimalFlatRanges()}(t);for(const i of t)yield*this._getValidRangesForRange(i,e)}getNearestSelectionRange(t,e="both"){if(this.checkChild(t,"$text"))return new vr(t);let i,n;"both"!=e&&"backward"!=e||(i=new wr({startPosition:t,direction:"backward"})),"both"!=e&&"forward"!=e||(n=new wr({startPosition:t}));for(const t of function*(t,e){let i=!1;for(;!i;){if(i=!0,t){const e=t.next();e.done||(i=!1,yield{walker:t,value:e.value})}if(e){const t=e.next();t.done||(i=!1,yield{walker:e,value:t.value})}}}(i,n)){const e=t.walker==i?"elementEnd":"elementStart",n=t.value;if(n.type==e&&this.isObject(n.item))return vr._createOn(n.item);if(this.checkChild(n.nextPosition,"$text"))return new vr(n.nextPosition)}return null}findAllowedParent(t,e){let i=t.parent;for(;i;){if(this.checkChild(i,e))return i;if(this.isLimit(i))return null;i=i.parent}return null}removeDisallowedAttributes(t,e){for(const i of t)if(i.is("text"))fa(this,i,e);else{const t=vr._createIn(i).getPositions();for(const i of t){fa(this,i.nodeBefore||i.parent,e)}}}createContext(t){return new ia(t)}_clearCache(){this._compiledDefinitions=null}_compile(){const t={},e=this._sourceDefinitions,i=Object.keys(e);for(const n of i)t[n]=na(e[n],n);for(const e of i)oa(t,e);for(const e of i)sa(t,e);for(const e of i)ra(t,e),aa(t,e);for(const e of i)ca(t,e),la(t,e);this._compiledDefinitions=t}_checkContextMatch(t,e,i=e.length-1){const n=e.getItem(i);if(t.allowIn.includes(n.name)){if(0==i)return!0;{const t=this.getDefinition(n);return this._checkContextMatch(t,e,i-1)}}return!1}*_getValidRangesForRange(t,e){let i=t.start,n=t.start;for(const o of t.getItems({shallow:!0}))o.is("element")&&(yield*this._getValidRangesForRange(vr._createIn(o),e)),this.checkAttribute(o,e)||(i.isEqual(n)||(yield new vr(i,n)),i=_r._createAfter(o)),n=_r._createAfter(o);i.isEqual(n)||(yield new vr(i,n))}}vi(ea,Hn);class ia{constructor(t){if(t instanceof ia)return t;"string"==typeof t?t=[t]:Array.isArray(t)||(t=t.getAncestors({includeSelf:!0})),t[0]&&"string"!=typeof t[0]&&t[0].is("documentFragment")&&t.shift(),this._items=t.map(ua)}get length(){return this._items.length}get last(){return this._items[this._items.length-1]}[Symbol.iterator](){return this._items[Symbol.iterator]()}push(t){const e=new ia([t]);return e._items=[...this._items,...e._items],e}getItem(t){return this._items[t]}*getNames(){yield*this._items.map(t=>t.name)}endsWith(t){return Array.from(this.getNames()).join(" ").endsWith(t)}startsWith(t){return Array.from(this.getNames()).join(" ").startsWith(t)}}function na(t,e){const i={name:e,allowIn:[],allowContentOf:[],allowWhere:[],allowAttributes:[],allowAttributesOf:[],inheritTypesFrom:[]};return function(t,e){for(const i of t){const t=Object.keys(i).filter(t=>t.startsWith("is"));for(const n of t)e[n]=i[n]}}(t,i),da(t,i,"allowIn"),da(t,i,"allowContentOf"),da(t,i,"allowWhere"),da(t,i,"allowAttributes"),da(t,i,"allowAttributesOf"),da(t,i,"inheritTypesFrom"),function(t,e){for(const i of t){const t=i.inheritAllFrom;t&&(e.allowContentOf.push(t),e.allowWhere.push(t),e.allowAttributesOf.push(t),e.inheritTypesFrom.push(t))}}(t,i),i}function oa(t,e){for(const i of t[e].allowContentOf)if(t[i]){ha(t,i).forEach(t=>{t.allowIn.push(e)})}delete t[e].allowContentOf}function sa(t,e){for(const i of t[e].allowWhere){const n=t[i];if(n){const i=n.allowIn;t[e].allowIn.push(...i)}}delete t[e].allowWhere}function ra(t,e){for(const i of t[e].allowAttributesOf){const n=t[i];if(n){const i=n.allowAttributes;t[e].allowAttributes.push(...i)}}delete t[e].allowAttributesOf}function aa(t,e){const i=t[e];for(const e of i.inheritTypesFrom){const n=t[e];if(n){const t=Object.keys(n).filter(t=>t.startsWith("is"));for(const e of t)e in i||(i[e]=n[e])}}delete i.inheritTypesFrom}function ca(t,e){const i=t[e],n=i.allowIn.filter(e=>t[e]);i.allowIn=Array.from(new Set(n))}function la(t,e){const i=t[e];i.allowAttributes=Array.from(new Set(i.allowAttributes))}function da(t,e,i){for(const n of t)"string"==typeof n[i]?e[i].push(n[i]):Array.isArray(n[i])&&e[i].push(...n[i])}function ha(t,e){const i=t[e];return(n=t,Object.keys(n).map(t=>n[t])).filter(t=>t.allowIn.includes(i.name));var n}function ua(t){return"string"==typeof t?{name:t,*getAttributeKeys(){},getAttribute(){}}:{name:t.is("element")?t.name:"$text",*getAttributeKeys(){yield*t.getAttributeKeys()},getAttribute:e=>t.getAttribute(e)}}function fa(t,e,i){for(const n of e.getAttributeKeys())t.checkAttribute(e,n)||i.removeAttribute(n,e)}class ma{constructor(t={}){this._splitParts=new Map,this._modelCursor=null,this.conversionApi=Object.assign({},t),this.conversionApi.convertItem=this._convertItem.bind(this),this.conversionApi.convertChildren=this._convertChildren.bind(this),this.conversionApi.splitToAllowedParent=this._splitToAllowedParent.bind(this),this.conversionApi.getSplitParts=this._getSplitParts.bind(this)}convert(t,e,i=["$root"]){this.fire("viewCleanup",t),this._modelCursor=function(t,e){let i;for(const n of new ia(t)){const t={};for(const e of n.getAttributeKeys())t[e]=n.getAttribute(e);const o=e.createElement(n.name,t);i&&e.append(o,i),i=_r._createAt(o,0)}return i}(i,e),this.conversionApi.writer=e,this.conversionApi.consumable=Xr.createFrom(t),this.conversionApi.store={};const{modelRange:n}=this._convertItem(t,this._modelCursor),o=e.createDocumentFragment();if(n){this._removeEmptyElements();for(const t of Array.from(this._modelCursor.parent.getChildren()))e.append(t,o);o.markers=function(t,e){const i=new Set,n=new Map,o=vr._createIn(t).getItems();for(const t of o)"$marker"==t.name&&i.add(t);for(const t of i){const i=t.getAttribute("data-name"),o=e.createPositionBefore(t);n.has(i)?n.get(i).end=o.clone():n.set(i,new vr(o.clone())),e.remove(t)}return n}(o,e)}return this._modelCursor=null,this._splitParts.clear(),this.conversionApi.writer=null,this.conversionApi.store=null,o}_convertItem(t,e){const i=Object.assign({viewItem:t,modelCursor:e,modelRange:null});if(t.is("element")?this.fire("element:"+t.name,i,this.conversionApi):t.is("text")?this.fire("text",i,this.conversionApi):this.fire("documentFragment",i,this.conversionApi),i.modelRange&&!(i.modelRange instanceof vr))throw new hi.b("view-conversion-dispatcher-incorrect-result: Incorrect conversion result was dropped.",this);return{modelRange:i.modelRange,modelCursor:i.modelCursor}}_convertChildren(t,e){const i=new vr(e);let n=e;for(const e of Array.from(t.getChildren())){const t=this._convertItem(e,n);t.modelRange instanceof vr&&(i.end=t.modelRange.end,n=t.modelCursor)}return{modelRange:i,modelCursor:n}}_splitToAllowedParent(t,e){const i=this.conversionApi.schema.findAllowedParent(e,t);if(!i)return null;if(i===e.parent)return{position:e};if(this._modelCursor.parent.getAncestors().includes(i))return null;const n=this.conversionApi.writer.split(e,i),o=[];for(const t of n.range.getWalker())if("elementEnd"==t.type)o.push(t.item);else{const e=o.pop(),i=t.item;this._registerSplitPair(e,i)}return{position:n.position,cursorParent:n.range.end.parent}}_registerSplitPair(t,e){this._splitParts.has(t)||this._splitParts.set(t,[t]);const i=this._splitParts.get(t);this._splitParts.set(e,i),i.push(e)}_getSplitParts(t){let e;return e=this._splitParts.has(t)?this._splitParts.get(t):[t],e}_removeEmptyElements(){let t=!1;for(const e of this._splitParts.keys())e.isEmpty&&(this.conversionApi.writer.remove(e),this._splitParts.delete(e),t=!0);t&&this._removeEmptyElements()}}vi(ma,mi);class ga{constructor(t,e){this.model=t,this.processor=e,this.mapper=new yr,this.downcastDispatcher=new Cr({mapper:this.mapper}),this.downcastDispatcher.on("insert:$text",(t,e,i)=>{if(!i.consumable.consume(e.item,"insert"))return;const n=i.writer,o=i.mapper.toViewPosition(e.range.start),s=n.createText(e.item.data);n.insert(o,s)},{priority:"lowest"}),this.upcastDispatcher=new ma({schema:t.schema}),this.upcastDispatcher.on("text",(t,e,i)=>{if(i.schema.checkChild(e.modelCursor,"$text")&&i.consumable.consume(e.viewItem)){const t=i.writer.createText(e.viewItem.data);i.writer.insert(t,e.modelCursor),e.modelRange=vr._createFromPositionAndShift(e.modelCursor,t.offsetSize),e.modelCursor=e.modelRange.end}},{priority:"lowest"}),this.upcastDispatcher.on("element",(t,e,i)=>{if(!e.modelRange&&i.consumable.consume(e.viewItem,{name:!0})){const{modelRange:t,modelCursor:n}=i.convertChildren(e.viewItem,e.modelCursor);e.modelRange=t,e.modelCursor=n}},{priority:"lowest"}),this.upcastDispatcher.on("documentFragment",(t,e,i)=>{if(!e.modelRange&&i.consumable.consume(e.viewItem,{name:!0})){const{modelRange:t,modelCursor:n}=i.convertChildren(e.viewItem,e.modelCursor);e.modelRange=t,e.modelCursor=n}},{priority:"lowest"}),this.decorate("init"),this.on("init",()=>{this.fire("ready")},{priority:"lowest"})}get(t){const{rootName:e="main",trim:i="empty"}=t||{};if(!this._checkIfRootsExists([e]))throw new hi.b("datacontroller-get-non-existent-root: Attempting to get data from a non-existing root.",this);const n=this.model.document.getRoot(e);return"empty"!==i||this.model.hasContent(n,{ignoreWhitespaces:!0})?this.stringify(n):""}stringify(t){const e=this.toView(t);return this.processor.toData(e)}toView(t){this.mapper.clearBindings();const e=vr._createIn(t),i=new Ao,n=new Co(new so);if(this.mapper.bindElements(t,i),this.downcastDispatcher.convertInsert(e,n),!t.is("documentFragment")){const e=function(t){const e=[],i=t.root.document;if(!i)return[];const n=vr._createIn(t);for(const t of i.model.markers){const i=n.getIntersection(t.getRange());i&&e.push([t.name,i])}return e}(t);for(const[t,i]of e)this.downcastDispatcher.convertMarkerAdd(t,i,n)}return i}init(t){if(this.model.document.version)throw new hi.b("datacontroller-init-document-not-empty: Trying to set initial data to not empty document.",this);let e={};if("string"==typeof t?e.main=t:e=t,!this._checkIfRootsExists(Object.keys(e)))throw new hi.b("datacontroller-init-non-existent-root: Attempting to init data on a non-existing root.",this);return this.model.enqueueChange("transparent",t=>{for(const i of Object.keys(e)){const n=this.model.document.getRoot(i);t.insert(this.parse(e[i],n),n,0)}}),Promise.resolve()}set(t){let e={};if("string"==typeof t?e.main=t:e=t,!this._checkIfRootsExists(Object.keys(e)))throw new hi.b("datacontroller-set-non-existent-root: Attempting to set data on a non-existing root.",this);this.model.enqueueChange("transparent",t=>{t.setSelection(null),t.removeSelectionAttribute(this.model.document.selection.getAttributeKeys());for(const i of Object.keys(e)){const n=this.model.document.getRoot(i);t.remove(t.createRangeIn(n)),t.insert(this.parse(e[i],n),n,0)}})}parse(t,e="$root"){const i=this.processor.toView(t);return this.toModel(i,e)}toModel(t,e="$root"){return this.model.change(i=>this.upcastDispatcher.convert(t,i,e))}destroy(){this.stopListening()}_checkIfRootsExists(t){for(const e of t)if(!this.model.document.getRootNames().includes(e))return!1;return!0}}vi(ga,Hn);class pa{constructor(t,e){this._helpers=new Map,this._downcast=Array.isArray(t)?t:[t],this._createConversionHelpers({name:"downcast",dispatchers:this._downcast,isDowncast:!0}),this._upcast=Array.isArray(e)?e:[e],this._createConversionHelpers({name:"upcast",dispatchers:this._upcast,isDowncast:!1})}addAlias(t,e){const i=this._downcast.includes(e);if(!this._upcast.includes(e)&&!i)throw new hi.b("conversion-add-alias-dispatcher-not-registered: Trying to register and alias for a dispatcher that nas not been registered.",this);this._createConversionHelpers({name:t,dispatchers:[e],isDowncast:i})}for(t){if(!this._helpers.has(t))throw new hi.b("conversion-for-unknown-group: Trying to add a converter to an unknown dispatchers group.",this);return this._helpers.get(t)}elementToElement(t){this.for("downcast").elementToElement(t);for(const{model:e,view:i}of ba(t))this.for("upcast").elementToElement({model:e,view:i,converterPriority:t.converterPriority})}attributeToElement(t){this.for("downcast").attributeToElement(t);for(const{model:e,view:i}of ba(t))this.for("upcast").elementToAttribute({view:i,model:e,converterPriority:t.converterPriority})}attributeToAttribute(t){this.for("downcast").attributeToAttribute(t);for(const{model:e,view:i}of ba(t))this.for("upcast").attributeToAttribute({view:i,model:e})}_createConversionHelpers({name:t,dispatchers:e,isDowncast:i}){if(this._helpers.has(t))throw new hi.b("conversion-group-exists: Trying to register a group name that has already been registered.",this);const n=i?new Br(e):new $r(e);this._helpers.set(t,n)}}function*ba(t){if(t.model.values)for(const e of t.model.values){const i={key:t.model.key,value:e},n=t.view[e],o=t.upcastAlso?t.upcastAlso[e]:void 0;yield*wa(i,n,o)}else yield*wa(t.model,t.view,t.upcastAlso)}function*wa(t,e,i){if(yield{model:t,view:e},i){i=Array.isArray(i)?i:[i];for(const e of i)yield{model:t,view:e}}}class ka{constructor(t="default"){this.operations=[],this.type=t}get baseVersion(){for(const t of this.operations)if(null!==t.baseVersion)return t.baseVersion;return null}addOperation(t){return t.batch=this,this.operations.push(t),t}}class _a{constructor(t){this.baseVersion=t,this.isDocumentOperation=null!==this.baseVersion,this.batch=null}_validate(){}toJSON(){const t=Object.assign({},this);return t.__className=this.constructor.className,delete t.batch,delete t.isDocumentOperation,t}static get className(){return"Operation"}static fromJSON(t){return new this(t.baseVersion)}}class va{constructor(t){this.markers=new Map,this._children=new pr,t&&this._insertChild(0,t)}[Symbol.iterator](){return this.getChildren()}get childCount(){return this._children.length}get maxOffset(){return this._children.maxOffset}get isEmpty(){return 0===this.childCount}get root(){return this}get parent(){return null}is(t){return"documentFragment"==t||"model:documentFragment"==t}getChild(t){return this._children.getNode(t)}getChildren(){return this._children[Symbol.iterator]()}getChildIndex(t){return this._children.getNodeIndex(t)}getChildStartOffset(t){return this._children.getNodeStartOffset(t)}getPath(){return[]}getNodeByPath(t){let e=this;for(const i of t)e=e.getChild(e.offsetToIndex(i));return e}offsetToIndex(t){return this._children.offsetToIndex(t)}toJSON(){const t=[];for(const e of this._children)t.push(e.toJSON());return t}static fromJSON(t){const e=[];for(const i of t)i.name?e.push(br.fromJSON(i)):e.push(mr.fromJSON(i));return new va(e)}_appendChild(t){this._insertChild(this.childCount,t)}_insertChild(t,e){const i=function(t){if("string"==typeof t)return[new mr(t)];Ri(t)||(t=[t]);return Array.from(t).map(t=>"string"==typeof t?new mr(t):t instanceof gr?new mr(t.data,t.getAttributes()):t)}(e);for(const t of i)null!==t.parent&&t._remove(),t.parent=this;this._children._insertNodes(t,i)}_removeChildren(t,e=1){const i=this._children._removeNodes(t,e);for(const t of i)t.parent=null;return i}}function ya(t,e){const i=(e=Ca(e)).reduce((t,e)=>t+e.offsetSize,0),n=t.parent;Pa(t);const o=t.index;return n._insertChild(o,e),Ta(n,o+e.length),Ta(n,o),new vr(t,t.getShiftedBy(i))}function xa(t){if(!t.isFlat)throw new hi.b("operation-utils-remove-range-not-flat: Trying to remove a range which starts and ends in different element.",this);const e=t.start.parent;Pa(t.start),Pa(t.end);const i=e._removeChildren(t.start.index,t.end.index-t.start.index);return Ta(e,t.start.index),i}function Aa(t,e){if(!t.isFlat)throw new hi.b("operation-utils-move-range-not-flat: Trying to move a range which starts and ends in different element.",this);const i=xa(t);return ya(e=e._getTransformedByDeletion(t.start,t.end.offset-t.start.offset),i)}function Ca(t){const e=[];t instanceof Array||(t=[t]);for(let i=0;i<t.length;i++)if("string"==typeof t[i])e.push(new mr(t[i]));else if(t[i]instanceof gr)e.push(new mr(t[i].data,t[i].getAttributes()));else if(t[i]instanceof va||t[i]instanceof pr)for(const n of t[i])e.push(n);else t[i]instanceof fr&&e.push(t[i]);for(let t=1;t<e.length;t++){const i=e[t],n=e[t-1];i instanceof mr&&n instanceof mr&&Sa(i,n)&&(e.splice(t-1,2,new mr(n.data+i.data,n.getAttributes())),t--)}return e}function Ta(t,e){const i=t.getChild(e-1),n=t.getChild(e);if(i&&n&&i.is("text")&&n.is("text")&&Sa(i,n)){const o=new mr(i.data+n.data,i.getAttributes());t._removeChildren(e-1,2),t._insertChild(e-1,o)}}function Pa(t){const e=t.textNode,i=t.parent;if(e){const n=t.offset-e.startOffset,o=e.index;i._removeChildren(o,1);const s=new mr(e.data.substr(0,n),e.getAttributes()),r=new mr(e.data.substr(n),e.getAttributes());i._insertChild(o,[s,r])}}function Sa(t,e){const i=t.getAttributes(),n=e.getAttributes();for(const t of i){if(t[1]!==e.getAttribute(t[0]))return!1;n.next()}return n.next().done}var Ea=function(t,e){return Es(t,e)};class Ma extends _a{constructor(t,e,i,n,o){super(o),this.range=t.clone(),this.key=e,this.oldValue=void 0===i?null:i,this.newValue=void 0===n?null:n}get type(){return null===this.oldValue?"addAttribute":null===this.newValue?"removeAttribute":"changeAttribute"}clone(){return new Ma(this.range,this.key,this.oldValue,this.newValue,this.baseVersion)}getReversed(){return new Ma(this.range,this.key,this.newValue,this.oldValue,this.baseVersion+1)}toJSON(){const t=super.toJSON();return t.range=this.range.toJSON(),t}_validate(){if(!this.range.isFlat)throw new hi.b("attribute-operation-range-not-flat: The range to change is not flat.",this);for(const t of this.range.getItems({shallow:!0})){if(null!==this.oldValue&&!Ea(t.getAttribute(this.key),this.oldValue))throw new hi.b("attribute-operation-wrong-old-value: Changed node has different attribute value than operation's old attribute value.",this,{item:t,key:this.key,value:this.oldValue});if(null===this.oldValue&&null!==this.newValue&&t.hasAttribute(this.key))throw new hi.b("attribute-operation-attribute-exists: The attribute with given key already exists.",this,{node:t,key:this.key})}}_execute(){Ea(this.oldValue,this.newValue)||function(t,e,i){Pa(t.start),Pa(t.end);for(const n of t.getItems({shallow:!0})){const t=n.is("textProxy")?n.textNode:n;null!==i?t._setAttribute(e,i):t._removeAttribute(e),Ta(t.parent,t.index)}Ta(t.end.parent,t.end.index)}(this.range,this.key,this.newValue)}static get className(){return"AttributeOperation"}static fromJSON(t,e){return new Ma(vr.fromJSON(t.range,e),t.key,t.oldValue,t.newValue,t.baseVersion)}}class Ia extends _a{constructor(t,e){super(null),this.sourcePosition=t.clone(),this.howMany=e}get type(){return"detach"}toJSON(){const t=super.toJSON();return t.sourcePosition=this.sourcePosition.toJSON(),t}_validate(){if(this.sourcePosition.root.document)throw new hi.b("detach-operation-on-document-node: Cannot detach document node.",this)}_execute(){xa(vr._createFromPositionAndShift(this.sourcePosition,this.howMany))}static get className(){return"DetachOperation"}}class Na extends _a{constructor(t,e,i,n){super(n),this.sourcePosition=t.clone(),this.sourcePosition.stickiness="toNext",this.howMany=e,this.targetPosition=i.clone(),this.targetPosition.stickiness="toNone"}get type(){return"$graveyard"==this.targetPosition.root.rootName?"remove":"$graveyard"==this.sourcePosition.root.rootName?"reinsert":"move"}clone(){return new this.constructor(this.sourcePosition,this.howMany,this.targetPosition,this.baseVersion)}getMovedRangeStart(){return this.targetPosition._getTransformedByDeletion(this.sourcePosition,this.howMany)}getReversed(){const t=this.sourcePosition._getTransformedByInsertion(this.targetPosition,this.howMany);return new this.constructor(this.getMovedRangeStart(),this.howMany,t,this.baseVersion+1)}_validate(){const t=this.sourcePosition.parent,e=this.targetPosition.parent,i=this.sourcePosition.offset,n=this.targetPosition.offset;if(i+this.howMany>t.maxOffset)throw new hi.b("move-operation-nodes-do-not-exist: The nodes which should be moved do not exist.",this);if(t===e&&i<n&&n<i+this.howMany)throw new hi.b("move-operation-range-into-itself: Trying to move a range of nodes to the inside of that range.",this);if(this.sourcePosition.root==this.targetPosition.root&&"prefix"==Ei(this.sourcePosition.getParentPath(),this.targetPosition.getParentPath())){const t=this.sourcePosition.path.length-1;if(this.targetPosition.path[t]>=i&&this.targetPosition.path[t]<i+this.howMany)throw new hi.b("move-operation-node-into-itself: Trying to move a range of nodes into one of nodes from that range.",this)}}_execute(){Aa(vr._createFromPositionAndShift(this.sourcePosition,this.howMany),this.targetPosition)}toJSON(){const t=super.toJSON();return t.sourcePosition=this.sourcePosition.toJSON(),t.targetPosition=this.targetPosition.toJSON(),t}static get className(){return"MoveOperation"}static fromJSON(t,e){const i=_r.fromJSON(t.sourcePosition,e),n=_r.fromJSON(t.targetPosition,e);return new this(i,t.howMany,n,t.baseVersion)}}class Oa extends _a{constructor(t,e,i){super(i),this.position=t.clone(),this.position.stickiness="toNone",this.nodes=new pr(Ca(e)),this.shouldReceiveAttributes=!1}get type(){return"insert"}get howMany(){return this.nodes.maxOffset}clone(){const t=new pr([...this.nodes].map(t=>t._clone(!0))),e=new Oa(this.position,t,this.baseVersion);return e.shouldReceiveAttributes=this.shouldReceiveAttributes,e}getReversed(){const t=this.position.root.document.graveyard,e=new _r(t,[0]);return new Na(this.position,this.nodes.maxOffset,e,this.baseVersion+1)}_validate(){const t=this.position.parent;if(!t||t.maxOffset<this.position.offset)throw new hi.b("insert-operation-position-invalid: Insertion position is invalid.",this)}_execute(){const t=this.nodes;this.nodes=new pr([...t].map(t=>t._clone(!0))),ya(this.position,t)}toJSON(){const t=super.toJSON();return t.position=this.position.toJSON(),t.nodes=this.nodes.toJSON(),t}static get className(){return"InsertOperation"}static fromJSON(t,e){const i=[];for(const e of t.nodes)e.name?i.push(br.fromJSON(e)):i.push(mr.fromJSON(e));const n=new Oa(_r.fromJSON(t.position,e),i,t.baseVersion);return n.shouldReceiveAttributes=t.shouldReceiveAttributes,n}}class Ra extends _a{constructor(t,e,i,n,o,s){super(s),this.name=t,this.oldRange=e?e.clone():null,this.newRange=i?i.clone():null,this.affectsData=o,this._markers=n}get type(){return"marker"}clone(){return new Ra(this.name,this.oldRange,this.newRange,this._markers,this.affectsData,this.baseVersion)}getReversed(){return new Ra(this.name,this.newRange,this.oldRange,this._markers,this.affectsData,this.baseVersion+1)}_execute(){const t=this.newRange?"_set":"_remove";this._markers[t](this.name,this.newRange,!0,this.affectsData)}toJSON(){const t=super.toJSON();return this.oldRange&&(t.oldRange=this.oldRange.toJSON()),this.newRange&&(t.newRange=this.newRange.toJSON()),delete t._markers,t}static get className(){return"MarkerOperation"}static fromJSON(t,e){return new Ra(t.name,t.oldRange?vr.fromJSON(t.oldRange,e):null,t.newRange?vr.fromJSON(t.newRange,e):null,e.model.markers,t.affectsData,t.baseVersion)}}class La extends _a{constructor(t,e,i,n){super(n),this.position=t,this.position.stickiness="toNext",this.oldName=e,this.newName=i}get type(){return"rename"}clone(){return new La(this.position.clone(),this.oldName,this.newName,this.baseVersion)}getReversed(){return new La(this.position.clone(),this.newName,this.oldName,this.baseVersion+1)}_validate(){const t=this.position.nodeAfter;if(!(t instanceof br))throw new hi.b("rename-operation-wrong-position: Given position is invalid or node after it is not an instance of Element.",this);if(t.name!==this.oldName)throw new hi.b("rename-operation-wrong-name: Element to change has different name than operation's old name.",this)}_execute(){this.position.nodeAfter.name=this.newName}toJSON(){const t=super.toJSON();return t.position=this.position.toJSON(),t}static get className(){return"RenameOperation"}static fromJSON(t,e){return new La(_r.fromJSON(t.position,e),t.oldName,t.newName,t.baseVersion)}}class Da extends _a{constructor(t,e,i,n,o){super(o),this.root=t,this.key=e,this.oldValue=i,this.newValue=n}get type(){return null===this.oldValue?"addRootAttribute":null===this.newValue?"removeRootAttribute":"changeRootAttribute"}clone(){return new Da(this.root,this.key,this.oldValue,this.newValue,this.baseVersion)}getReversed(){return new Da(this.root,this.key,this.newValue,this.oldValue,this.baseVersion+1)}_validate(){if(this.root!=this.root.root||this.root.is("documentFragment"))throw new hi.b("rootattribute-operation-not-a-root: The element to change is not a root element.",this,{root:this.root,key:this.key});if(null!==this.oldValue&&this.root.getAttribute(this.key)!==this.oldValue)throw new hi.b("rootattribute-operation-wrong-old-value: Changed node has different attribute value than operation's old attribute value.",this,{root:this.root,key:this.key});if(null===this.oldValue&&null!==this.newValue&&this.root.hasAttribute(this.key))throw new hi.b("rootattribute-operation-attribute-exists: The attribute with given key already exists.",this,{root:this.root,key:this.key})}_execute(){null!==this.newValue?this.root._setAttribute(this.key,this.newValue):this.root._removeAttribute(this.key)}toJSON(){const t=super.toJSON();return t.root=this.root.toJSON(),t}static get className(){return"RootAttributeOperation"}static fromJSON(t,e){if(!e.getRoot(t.root))throw new hi.b("rootattribute-operation-fromjson-no-root: Cannot create RootAttributeOperation. Root with specified name does not exist.",this,{rootName:t.root});return new Da(e.getRoot(t.root),t.key,t.oldValue,t.newValue,t.baseVersion)}}class za extends _a{constructor(t,e,i,n,o){super(o),this.sourcePosition=t.clone(),this.sourcePosition.stickiness="toPrevious",this.howMany=e,this.targetPosition=i.clone(),this.targetPosition.stickiness="toNext",this.graveyardPosition=n.clone()}get type(){return"merge"}get deletionPosition(){return new _r(this.sourcePosition.root,this.sourcePosition.path.slice(0,-1))}get movedRange(){const t=this.sourcePosition.getShiftedBy(Number.POSITIVE_INFINITY);return new vr(this.sourcePosition,t)}clone(){return new this.constructor(this.sourcePosition,this.howMany,this.targetPosition,this.graveyardPosition,this.baseVersion)}getReversed(){const t=this.targetPosition._getTransformedByMergeOperation(this),e=this.sourcePosition.path.slice(0,-1),i=new _r(this.sourcePosition.root,e)._getTransformedByMergeOperation(this),n=new ja(t,this.howMany,this.graveyardPosition,this.baseVersion+1);return n.insertionPosition=i,n}_validate(){const t=this.sourcePosition.parent,e=this.targetPosition.parent;if(!t.parent)throw new hi.b("merge-operation-source-position-invalid: Merge source position is invalid.",this);if(!e.parent)throw new hi.b("merge-operation-target-position-invalid: Merge target position is invalid.",this);if(this.howMany!=t.maxOffset)throw new hi.b("merge-operation-how-many-invalid: Merge operation specifies wrong number of nodes to move.",this)}_execute(){const t=this.sourcePosition.parent;Aa(vr._createIn(t),this.targetPosition),Aa(vr._createOn(t),this.graveyardPosition)}toJSON(){const t=super.toJSON();return t.sourcePosition=t.sourcePosition.toJSON(),t.targetPosition=t.targetPosition.toJSON(),t.graveyardPosition=t.graveyardPosition.toJSON(),t}static get className(){return"MergeOperation"}static fromJSON(t,e){const i=_r.fromJSON(t.sourcePosition,e),n=_r.fromJSON(t.targetPosition,e),o=_r.fromJSON(t.graveyardPosition,e);return new this(i,t.howMany,n,o,t.baseVersion)}}class ja extends _a{constructor(t,e,i,n){super(n),this.splitPosition=t.clone(),this.splitPosition.stickiness="toNext",this.howMany=e,this.insertionPosition=ja.getInsertionPosition(t),this.insertionPosition.stickiness="toNone",this.graveyardPosition=i?i.clone():null,this.graveyardPosition&&(this.graveyardPosition.stickiness="toNext")}get type(){return"split"}get moveTargetPosition(){const t=this.insertionPosition.path.slice();return t.push(0),new _r(this.insertionPosition.root,t)}get movedRange(){const t=this.splitPosition.getShiftedBy(Number.POSITIVE_INFINITY);return new vr(this.splitPosition,t)}clone(){const t=new this.constructor(this.splitPosition,this.howMany,this.graveyardPosition,this.baseVersion);return t.insertionPosition=this.insertionPosition,t}getReversed(){const t=this.splitPosition.root.document.graveyard,e=new _r(t,[0]);return new za(this.moveTargetPosition,this.howMany,this.splitPosition,e,this.baseVersion+1)}_validate(){const t=this.splitPosition.parent,e=this.splitPosition.offset;if(!t||t.maxOffset<e)throw new hi.b("split-operation-position-invalid: Split position is invalid.",this);if(!t.parent)throw new hi.b("split-operation-split-in-root: Cannot split root element.",this);if(this.howMany!=t.maxOffset-this.splitPosition.offset)throw new hi.b("split-operation-how-many-invalid: Split operation specifies wrong number of nodes to move.",this);if(this.graveyardPosition&&!this.graveyardPosition.nodeAfter)throw new hi.b("split-operation-graveyard-position-invalid: Graveyard position invalid.",this)}_execute(){const t=this.splitPosition.parent;if(this.graveyardPosition)Aa(vr._createFromPositionAndShift(this.graveyardPosition,1),this.insertionPosition);else{const e=t._clone();ya(this.insertionPosition,e)}Aa(new vr(_r._createAt(t,this.splitPosition.offset),_r._createAt(t,t.maxOffset)),this.moveTargetPosition)}toJSON(){const t=super.toJSON();return t.splitPosition=this.splitPosition.toJSON(),t.insertionPosition=this.insertionPosition.toJSON(),this.graveyardPosition&&(t.graveyardPosition=this.graveyardPosition.toJSON()),t}static get className(){return"SplitOperation"}static getInsertionPosition(t){const e=t.path.slice(0,-1);return e[e.length-1]++,new _r(t.root,e)}static fromJSON(t,e){const i=_r.fromJSON(t.splitPosition,e),n=_r.fromJSON(t.insertionPosition,e),o=t.graveyardPosition?_r.fromJSON(t.graveyardPosition,e):null,s=new this(i,t.howMany,o,t.baseVersion);return s.insertionPosition=n,s}}class Va extends br{constructor(t,e,i="main"){super(e),this._doc=t,this.rootName=i}get document(){return this._doc}is(t,e){const i=t.replace("model:","");return e?"rootElement"==i&&e==this.name||super.is(t,e):"rootElement"==i||super.is(t)}toJSON(){return this.rootName}}class Ba{constructor(t,e){this.model=t,this.batch=e}createText(t,e){return new mr(t,e)}createElement(t,e){return new br(t,e)}createDocumentFragment(){return new va}insert(t,e,i=0){if(this._assertWriterUsedCorrectly(),t instanceof mr&&""==t.data)return;const n=_r._createAt(e,i);if(t.parent){if(qa(t.root,n.root))return void this.move(vr._createOn(t),n);if(t.root.document)throw new hi.b("model-writer-insert-forbidden-move: Cannot move a node from a document to a different tree. It is forbidden to move a node that was already in a document outside of it.",this);this.remove(t)}const o=n.root.document?n.root.document.version:null,s=new Oa(n,t,o);if(t instanceof mr&&(s.shouldReceiveAttributes=!0),this.batch.addOperation(s),this.model.applyOperation(s),t instanceof va)for(const[e,i]of t.markers){const t=_r._createAt(i.root,0),o={range:new vr(i.start._getCombined(t,n),i.end._getCombined(t,n)),usingOperation:!0,affectsData:!0};this.model.markers.has(e)?this.updateMarker(e,o):this.addMarker(e,o)}}insertText(t,e,i,n){e instanceof va||e instanceof br||e instanceof _r?this.insert(this.createText(t),e,i):this.insert(this.createText(t,e),i,n)}insertElement(t,e,i,n){e instanceof va||e instanceof br||e instanceof _r?this.insert(this.createElement(t),e,i):this.insert(this.createElement(t,e),i,n)}append(t,e){this.insert(t,e,"end")}appendText(t,e,i){e instanceof va||e instanceof br?this.insert(this.createText(t),e,"end"):this.insert(this.createText(t,e),i,"end")}appendElement(t,e,i){e instanceof va||e instanceof br?this.insert(this.createElement(t),e,"end"):this.insert(this.createElement(t,e),i,"end")}setAttribute(t,e,i){if(this._assertWriterUsedCorrectly(),i instanceof vr){const n=i.getMinimalFlatRanges();for(const i of n)Fa(this,t,e,i)}else Ha(this,t,e,i)}setAttributes(t,e){for(const[i,n]of Li(t))this.setAttribute(i,n,e)}removeAttribute(t,e){if(this._assertWriterUsedCorrectly(),e instanceof vr){const i=e.getMinimalFlatRanges();for(const e of i)Fa(this,t,null,e)}else Ha(this,t,null,e)}clearAttributes(t){this._assertWriterUsedCorrectly();const e=t=>{for(const e of t.getAttributeKeys())this.removeAttribute(e,t)};if(t instanceof vr)for(const i of t.getItems())e(i);else e(t)}move(t,e,i){if(this._assertWriterUsedCorrectly(),!(t instanceof vr))throw new hi.b("writer-move-invalid-range: Invalid range to move.",this);if(!t.isFlat)throw new hi.b("writer-move-range-not-flat: Range to move is not flat.",this);const n=_r._createAt(e,i);if(n.isEqual(t.start))return;if(this._addOperationForAffectedMarkers("move",t),!qa(t.root,n.root))throw new hi.b("writer-move-different-document: Range is going to be moved between different documents.",this);const o=t.root.document?t.root.document.version:null,s=new Na(t.start,t.end.offset-t.start.offset,n,o);this.batch.addOperation(s),this.model.applyOperation(s)}remove(t){this._assertWriterUsedCorrectly();const e=(t instanceof vr?t:vr._createOn(t)).getMinimalFlatRanges().reverse();for(const t of e)this._addOperationForAffectedMarkers("move",t),Wa(t.start,t.end.offset-t.start.offset,this.batch,this.model)}merge(t){this._assertWriterUsedCorrectly();const e=t.nodeBefore,i=t.nodeAfter;if(this._addOperationForAffectedMarkers("merge",t),!(e instanceof br))throw new hi.b("writer-merge-no-element-before: Node before merge position must be an element.",this);if(!(i instanceof br))throw new hi.b("writer-merge-no-element-after: Node after merge position must be an element.",this);t.root.document?this._merge(t):this._mergeDetached(t)}createPositionFromPath(t,e,i){return this.model.createPositionFromPath(t,e,i)}createPositionAt(t,e){return this.model.createPositionAt(t,e)}createPositionAfter(t){return this.model.createPositionAfter(t)}createPositionBefore(t){return this.model.createPositionBefore(t)}createRange(t,e){return this.model.createRange(t,e)}createRangeIn(t){return this.model.createRangeIn(t)}createRangeOn(t){return this.model.createRangeOn(t)}createSelection(t,e,i){return this.model.createSelection(t,e,i)}_mergeDetached(t){const e=t.nodeBefore,i=t.nodeAfter;this.move(vr._createIn(i),_r._createAt(e,"end")),this.remove(i)}_merge(t){const e=_r._createAt(t.nodeBefore,"end"),i=_r._createAt(t.nodeAfter,0),n=t.root.document.graveyard,o=new _r(n,[0]),s=t.root.document.version,r=new za(i,t.nodeAfter.maxOffset,e,o,s);this.batch.addOperation(r),this.model.applyOperation(r)}rename(t,e){if(this._assertWriterUsedCorrectly(),!(t instanceof br))throw new hi.b("writer-rename-not-element-instance: Trying to rename an object which is not an instance of Element.",this);const i=t.root.document?t.root.document.version:null,n=new La(_r._createBefore(t),t.name,e,i);this.batch.addOperation(n),this.model.applyOperation(n)}split(t,e){this._assertWriterUsedCorrectly();let i,n,o=t.parent;if(!o.parent)throw new hi.b("writer-split-element-no-parent: Element with no parent can not be split.",this);if(e||(e=o.parent),!t.parent.getAncestors({includeSelf:!0}).includes(e))throw new hi.b("writer-split-invalid-limit-element: Limit element is not a position ancestor.",this);do{const e=o.root.document?o.root.document.version:null,s=o.maxOffset-t.offset,r=new ja(t,s,null,e);this.batch.addOperation(r),this.model.applyOperation(r),i||n||(i=o,n=t.parent.nextSibling),o=(t=this.createPositionAfter(t.parent)).parent}while(o!==e);return{position:t,range:new vr(_r._createAt(i,"end"),_r._createAt(n,0))}}wrap(t,e){if(this._assertWriterUsedCorrectly(),!t.isFlat)throw new hi.b("writer-wrap-range-not-flat: Range to wrap is not flat.",this);const i=e instanceof br?e:new br(e);if(i.childCount>0)throw new hi.b("writer-wrap-element-not-empty: Element to wrap with is not empty.",this);if(null!==i.parent)throw new hi.b("writer-wrap-element-attached: Element to wrap with is already attached to tree model.",this);this.insert(i,t.start);const n=new vr(t.start.getShiftedBy(1),t.end.getShiftedBy(1));this.move(n,_r._createAt(i,0))}unwrap(t){if(this._assertWriterUsedCorrectly(),null===t.parent)throw new hi.b("writer-unwrap-element-no-parent: Trying to unwrap an element which has no parent.",this);this.move(vr._createIn(t),this.createPositionAfter(t)),this.remove(t)}addMarker(t,e){if(this._assertWriterUsedCorrectly(),!e||"boolean"!=typeof e.usingOperation)throw new hi.b("writer-addMarker-no-usingOperation: The options.usingOperation parameter is required when adding a new marker.",this);const i=e.usingOperation,n=e.range,o=void 0!==e.affectsData&&e.affectsData;if(this.model.markers.has(t))throw new hi.b("writer-addMarker-marker-exists: Marker with provided name already exists.",this);if(!n)throw new hi.b("writer-addMarker-no-range: Range parameter is required when adding a new marker.",this);return i?(Ua(this,t,null,n,o),this.model.markers.get(t)):this.model.markers._set(t,n,i,o)}updateMarker(t,e){this._assertWriterUsedCorrectly();const i="string"==typeof t?t:t.name,n=this.model.markers.get(i);if(!n)throw new hi.b("writer-updateMarker-marker-not-exists: Marker with provided name does not exists.",this);if(!e)return void this.model.markers._refresh(n);const o="boolean"==typeof e.usingOperation,s="boolean"==typeof e.affectsData,r=s?e.affectsData:n.affectsData;if(!o&&!e.range&&!s)throw new hi.b("writer-updateMarker-wrong-options: One of the options is required - provide range, usingOperations or affectsData.",this);const a=n.getRange(),c=e.range?e.range:a;o&&e.usingOperation!==n.managedUsingOperations?e.usingOperation?Ua(this,i,null,c,r):(Ua(this,i,a,null,r),this.model.markers._set(i,c,void 0,r)):n.managedUsingOperations?Ua(this,i,a,c,r):this.model.markers._set(i,c,void 0,r)}removeMarker(t){this._assertWriterUsedCorrectly();const e="string"==typeof t?t:t.name;if(!this.model.markers.has(e))throw new hi.b("writer-removeMarker-no-marker: Trying to remove marker which does not exist.",this);const i=this.model.markers.get(e);i.managedUsingOperations?Ua(this,e,i.getRange(),null,i.affectsData):this.model.markers._remove(e)}setSelection(t,e,i){this._assertWriterUsedCorrectly(),this.model.document.selection._setTo(t,e,i)}setSelectionFocus(t,e){this._assertWriterUsedCorrectly(),this.model.document.selection._setFocus(t,e)}setSelectionAttribute(t,e){if(this._assertWriterUsedCorrectly(),"string"==typeof t)this._setSelectionAttribute(t,e);else for(const[e,i]of Li(t))this._setSelectionAttribute(e,i)}removeSelectionAttribute(t){if(this._assertWriterUsedCorrectly(),"string"==typeof t)this._removeSelectionAttribute(t);else for(const e of t)this._removeSelectionAttribute(e)}overrideSelectionGravity(){return this.model.document.selection._overrideGravity()}restoreSelectionGravity(t){this.model.document.selection._restoreGravity(t)}_setSelectionAttribute(t,e){const i=this.model.document.selection;if(i.isCollapsed&&i.anchor.parent.isEmpty){const n=Lr._getStoreAttributeKey(t);this.setAttribute(n,e,i.anchor.parent)}i._setAttribute(t,e)}_removeSelectionAttribute(t){const e=this.model.document.selection;if(e.isCollapsed&&e.anchor.parent.isEmpty){const i=Lr._getStoreAttributeKey(t);this.removeAttribute(i,e.anchor.parent)}e._removeAttribute(t)}_assertWriterUsedCorrectly(){if(this.model._currentWriter!==this)throw new hi.b("writer-incorrect-use: Trying to use a writer outside the change() block.",this)}_addOperationForAffectedMarkers(t,e){for(const i of this.model.markers){if(!i.managedUsingOperations)continue;const n=i.getRange();let o=!1;if("move"==t)o=e.containsPosition(n.start)||e.start.isEqual(n.start)||e.containsPosition(n.end)||e.end.isEqual(n.end);else{const t=e.nodeBefore,i=e.nodeAfter,s=n.start.parent==t&&n.start.isAtEnd,r=n.end.parent==i&&0==n.end.offset,a=n.end.nodeAfter==i,c=n.start.nodeAfter==i;o=s||r||a||c}o&&this.updateMarker(i.name,{range:n})}}}function Fa(t,e,i,n){const o=t.model,s=o.document;let r,a,c,l=n.start;for(const t of n.getWalker({shallow:!0}))c=t.item.getAttribute(e),r&&a!=c&&(a!=i&&d(),l=r),r=t.nextPosition,a=c;function d(){const n=new vr(l,r),c=n.root.document?s.version:null,d=new Ma(n,e,a,i,c);t.batch.addOperation(d),o.applyOperation(d)}r instanceof _r&&r!=l&&a!=i&&d()}function Ha(t,e,i,n){const o=t.model,s=o.document,r=n.getAttribute(e);let a,c;if(r!=i){if(n.root===n){const t=n.document?s.version:null;c=new Da(n,e,r,i,t)}else{a=new vr(_r._createBefore(n),t.createPositionAfter(n));const o=a.root.document?s.version:null;c=new Ma(a,e,r,i,o)}t.batch.addOperation(c),o.applyOperation(c)}}function Ua(t,e,i,n,o){const s=t.model,r=s.document,a=new Ra(e,i,n,s.markers,o,r.version);t.batch.addOperation(a),s.applyOperation(a)}function Wa(t,e,i,n){let o;if(t.root.document){const i=n.document,s=new _r(i.graveyard,[0]);o=new Na(t,e,s,i.version)}else o=new Ia(t,e);i.addOperation(o),n.applyOperation(o)}function qa(t,e){return t===e||t instanceof Va&&e instanceof Va}class $a{constructor(t){this._markerCollection=t,this._changesInElement=new Map,this._elementSnapshots=new Map,this._changedMarkers=new Map,this._changeCount=0,this._cachedChanges=null,this._cachedChangesWithGraveyard=null}get isEmpty(){return 0==this._changesInElement.size&&0==this._changedMarkers.size}refreshItem(t){if(this._isInInsertedElement(t.parent))return;this._markRemove(t.parent,t.startOffset,t.offsetSize),this._markInsert(t.parent,t.startOffset,t.offsetSize);const e=vr._createOn(t);for(const t of this._markerCollection.getMarkersIntersectingRange(e)){const e=t.getRange();this.bufferMarkerChange(t.name,e,e,t.affectsData)}this._cachedChanges=null}bufferOperation(t){switch(t.type){case"insert":if(this._isInInsertedElement(t.position.parent))return;this._markInsert(t.position.parent,t.position.offset,t.nodes.maxOffset);break;case"addAttribute":case"removeAttribute":case"changeAttribute":for(const e of t.range.getItems({shallow:!0}))this._isInInsertedElement(e.parent)||this._markAttribute(e);break;case"remove":case"move":case"reinsert":{if(t.sourcePosition.isEqual(t.targetPosition)||t.sourcePosition.getShiftedBy(t.howMany).isEqual(t.targetPosition))return;const e=this._isInInsertedElement(t.sourcePosition.parent),i=this._isInInsertedElement(t.targetPosition.parent);e||this._markRemove(t.sourcePosition.parent,t.sourcePosition.offset,t.howMany),i||this._markInsert(t.targetPosition.parent,t.getMovedRangeStart().offset,t.howMany);break}case"rename":{if(this._isInInsertedElement(t.position.parent))return;this._markRemove(t.position.parent,t.position.offset,1),this._markInsert(t.position.parent,t.position.offset,1);const e=vr._createFromPositionAndShift(t.position,1);for(const t of this._markerCollection.getMarkersIntersectingRange(e)){const e=t.getRange();this.bufferMarkerChange(t.name,e,e,t.affectsData)}break}case"split":{const e=t.splitPosition.parent;this._isInInsertedElement(e)||this._markRemove(e,t.splitPosition.offset,t.howMany),this._isInInsertedElement(t.insertionPosition.parent)||this._markInsert(t.insertionPosition.parent,t.insertionPosition.offset,1),t.graveyardPosition&&this._markRemove(t.graveyardPosition.parent,t.graveyardPosition.offset,1);break}case"merge":{const e=t.sourcePosition.parent;this._isInInsertedElement(e.parent)||this._markRemove(e.parent,e.startOffset,1);const i=t.graveyardPosition.parent;this._markInsert(i,t.graveyardPosition.offset,1);const n=t.targetPosition.parent;this._isInInsertedElement(n)||this._markInsert(n,t.targetPosition.offset,e.maxOffset);break}}this._cachedChanges=null}bufferMarkerChange(t,e,i,n){const o=this._changedMarkers.get(t);o?(o.newRange=i,o.affectsData=n,null==o.oldRange&&null==o.newRange&&this._changedMarkers.delete(t)):this._changedMarkers.set(t,{oldRange:e,newRange:i,affectsData:n})}getMarkersToRemove(){const t=[];for(const[e,i]of this._changedMarkers)null!=i.oldRange&&t.push({name:e,range:i.oldRange});return t}getMarkersToAdd(){const t=[];for(const[e,i]of this._changedMarkers)null!=i.newRange&&t.push({name:e,range:i.newRange});return t}getChangedMarkers(){return Array.from(this._changedMarkers).map(t=>({name:t[0],data:{oldRange:t[1].oldRange,newRange:t[1].newRange}}))}hasDataChanges(){for(const[,t]of this._changedMarkers)if(t.affectsData)return!0;return this._changesInElement.size>0}getChanges(t={includeChangesInGraveyard:!1}){if(this._cachedChanges)return t.includeChangesInGraveyard?this._cachedChangesWithGraveyard.slice():this._cachedChanges.slice();const e=[];for(const t of this._changesInElement.keys()){const i=this._changesInElement.get(t).sort((t,e)=>t.offset===e.offset?t.type!=e.type?"remove"==t.type?-1:1:0:t.offset<e.offset?-1:1),n=this._elementSnapshots.get(t),o=Ya(t.getChildren()),s=Ga(n.length,i);let r=0,a=0;for(const i of s)if("i"===i)e.push(this._getInsertDiff(t,r,o[r].name)),r++;else if("r"===i)e.push(this._getRemoveDiff(t,r,n[a].name)),a++;else if("a"===i){const i=o[r].attributes,s=n[a].attributes;let c;if("$text"==o[r].name)c=new vr(_r._createAt(t,r),_r._createAt(t,r+1));else{const e=t.offsetToIndex(r);c=new vr(_r._createAt(t,r),_r._createAt(t.getChild(e),0))}e.push(...this._getAttributesDiff(c,s,i)),r++,a++}else r++,a++}e.sort((t,e)=>t.position.root!=e.position.root?t.position.root.rootName<e.position.root.rootName?-1:1:t.position.isEqual(e.position)?t.changeCount-e.changeCount:t.position.isBefore(e.position)?-1:1);for(let t=1;t<e.length;t++){const i=e[t-1],n=e[t],o="remove"==i.type&&"remove"==n.type&&"$text"==i.name&&"$text"==n.name&&i.position.isEqual(n.position),s="insert"==i.type&&"insert"==n.type&&"$text"==i.name&&"$text"==n.name&&i.position.parent==n.position.parent&&i.position.offset+i.length==n.position.offset,r="attribute"==i.type&&"attribute"==n.type&&i.position.parent==n.position.parent&&i.range.isFlat&&n.range.isFlat&&i.position.offset+i.length==n.position.offset&&i.attributeKey==n.attributeKey&&i.attributeOldValue==n.attributeOldValue&&i.attributeNewValue==n.attributeNewValue;(o||s||r)&&(e[t-1].length++,r&&(e[t-1].range.end=e[t-1].range.end.getShiftedBy(1)),e.splice(t,1),t--)}for(const t of e)delete t.changeCount,"attribute"==t.type&&(delete t.position,delete t.length);return this._changeCount=0,this._cachedChangesWithGraveyard=e.slice(),this._cachedChanges=e.slice().filter(Qa),t.includeChangesInGraveyard?this._cachedChangesWithGraveyard:this._cachedChanges}reset(){this._changesInElement.clear(),this._elementSnapshots.clear(),this._changedMarkers.clear(),this._cachedChanges=null}_markInsert(t,e,i){const n={type:"insert",offset:e,howMany:i,count:this._changeCount++};this._markChange(t,n)}_markRemove(t,e,i){const n={type:"remove",offset:e,howMany:i,count:this._changeCount++};this._markChange(t,n),this._removeAllNestedChanges(t,e,i)}_markAttribute(t){const e={type:"attribute",offset:t.startOffset,howMany:t.offsetSize,count:this._changeCount++};this._markChange(t.parent,e)}_markChange(t,e){this._makeSnapshot(t);const i=this._getChangesForElement(t);this._handleChange(e,i),i.push(e);for(let t=0;t<i.length;t++)i[t].howMany<1&&(i.splice(t,1),t--)}_getChangesForElement(t){let e;return this._changesInElement.has(t)?e=this._changesInElement.get(t):(e=[],this._changesInElement.set(t,e)),e}_makeSnapshot(t){this._elementSnapshots.has(t)||this._elementSnapshots.set(t,Ya(t.getChildren()))}_handleChange(t,e){t.nodesToHandle=t.howMany;for(const i of e){const n=t.offset+t.howMany,o=i.offset+i.howMany;if("insert"==t.type&&("insert"==i.type&&(t.offset<=i.offset?i.offset+=t.howMany:t.offset<o&&(i.howMany+=t.nodesToHandle,t.nodesToHandle=0)),"remove"==i.type&&t.offset<i.offset&&(i.offset+=t.howMany),"attribute"==i.type))if(t.offset<=i.offset)i.offset+=t.howMany;else if(t.offset<o){const o=i.howMany;i.howMany=t.offset-i.offset,e.unshift({type:"attribute",offset:n,howMany:o-i.howMany,count:this._changeCount++})}if("remove"==t.type){if("insert"==i.type)if(n<=i.offset)i.offset-=t.howMany;else if(n<=o)if(t.offset<i.offset){const e=n-i.offset;i.offset=t.offset,i.howMany-=e,t.nodesToHandle-=e}else i.howMany-=t.nodesToHandle,t.nodesToHandle=0;else if(t.offset<=i.offset)t.nodesToHandle-=i.howMany,i.howMany=0;else if(t.offset<o){const e=o-t.offset;i.howMany-=e,t.nodesToHandle-=e}if("remove"==i.type&&(n<=i.offset?i.offset-=t.howMany:t.offset<i.offset&&(t.nodesToHandle+=i.howMany,i.howMany=0)),"attribute"==i.type)if(n<=i.offset)i.offset-=t.howMany;else if(t.offset<i.offset){const e=n-i.offset;i.offset=t.offset,i.howMany-=e}else if(t.offset<o)if(n<=o){const n=i.howMany;i.howMany=t.offset-i.offset;const o=n-i.howMany-t.nodesToHandle;e.unshift({type:"attribute",offset:t.offset,howMany:o,count:this._changeCount++})}else i.howMany-=o-t.offset}if("attribute"==t.type){if("insert"==i.type)if(t.offset<i.offset&&n>i.offset){if(n>o){const t={type:"attribute",offset:o,howMany:n-o,count:this._changeCount++};this._handleChange(t,e),e.push(t)}t.nodesToHandle=i.offset-t.offset,t.howMany=t.nodesToHandle}else t.offset>=i.offset&&t.offset<o&&(n>o?(t.nodesToHandle=n-o,t.offset=o):t.nodesToHandle=0);if("remove"==i.type&&t.offset<i.offset&&n>i.offset){const o={type:"attribute",offset:i.offset,howMany:n-i.offset,count:this._changeCount++};this._handleChange(o,e),e.push(o),t.nodesToHandle=i.offset-t.offset,t.howMany=t.nodesToHandle}"attribute"==i.type&&(t.offset>=i.offset&&n<=o?(t.nodesToHandle=0,t.howMany=0,t.offset=0):t.offset<=i.offset&&n>=o&&(i.howMany=0))}}t.howMany=t.nodesToHandle,delete t.nodesToHandle}_getInsertDiff(t,e,i){return{type:"insert",position:_r._createAt(t,e),name:i,length:1,changeCount:this._changeCount++}}_getRemoveDiff(t,e,i){return{type:"remove",position:_r._createAt(t,e),name:i,length:1,changeCount:this._changeCount++}}_getAttributesDiff(t,e,i){const n=[];i=new Map(i);for(const[o,s]of e){const e=i.has(o)?i.get(o):null;e!==s&&n.push({type:"attribute",position:t.start,range:t.clone(),length:1,attributeKey:o,attributeOldValue:s,attributeNewValue:e,changeCount:this._changeCount++}),i.delete(o)}for(const[e,o]of i)n.push({type:"attribute",position:t.start,range:t.clone(),length:1,attributeKey:e,attributeOldValue:null,attributeNewValue:o,changeCount:this._changeCount++});return n}_isInInsertedElement(t){const e=t.parent;if(!e)return!1;const i=this._changesInElement.get(e),n=t.startOffset;if(i)for(const t of i)if("insert"==t.type&&n>=t.offset&&n<t.offset+t.howMany)return!0;return this._isInInsertedElement(e)}_removeAllNestedChanges(t,e,i){const n=new vr(_r._createAt(t,e),_r._createAt(t,e+i));for(const t of n.getItems({shallow:!0}))t.is("element")&&(this._elementSnapshots.delete(t),this._changesInElement.delete(t),this._removeAllNestedChanges(t,0,t.maxOffset))}}function Ya(t){const e=[];for(const i of t)if(i.is("text"))for(let t=0;t<i.data.length;t++)e.push({name:"$text",attributes:new Map(i.getAttributes())});else e.push({name:i.name,attributes:new Map(i.getAttributes())});return e}function Ga(t,e){const i=[];let n=0,o=0;for(const t of e){if(t.offset>n){for(let e=0;e<t.offset-n;e++)i.push("e");o+=t.offset-n}if("insert"==t.type){for(let e=0;e<t.howMany;e++)i.push("i");n=t.offset+t.howMany}else if("remove"==t.type){for(let e=0;e<t.howMany;e++)i.push("r");n=t.offset,o+=t.howMany}else i.push(..."a".repeat(t.howMany).split("")),n=t.offset+t.howMany,o+=t.howMany}if(o<t)for(let e=0;e<t-o-n;e++)i.push("e");return i}function Qa(t){const e=t.position&&"$graveyard"==t.position.root.rootName,i=t.range&&"$graveyard"==t.range.root.rootName;return!e&&!i}class Ka{constructor(){this._operations=[],this._undoPairs=new Map,this._undoneOperations=new Set}addOperation(t){this._operations.includes(t)||this._operations.push(t)}getOperations(t=0,e=Number.POSITIVE_INFINITY){return t<0?[]:this._operations.slice(t,e)}getOperation(t){return this._operations[t]}setOperationAsUndone(t,e){this._undoPairs.set(e,t),this._undoneOperations.add(t)}isUndoingOperation(t){return this._undoPairs.has(t)}isUndoneOperation(t){return this._undoneOperations.has(t)}getUndoneOperation(t){return this._undoPairs.get(t)}}function Ja(t,e){return!!(i=t.charAt(e-1))&&1==i.length&&/[\ud800-\udbff]/.test(i)&&function(t){return!!t&&1==t.length&&/[\udc00-\udfff]/.test(t)}(t.charAt(e));var i}function Za(t,e){return!!(i=t.charAt(e))&&1==i.length&&/[\u0300-\u036f\u1ab0-\u1aff\u1dc0-\u1dff\u20d0-\u20ff\ufe20-\ufe2f]/.test(i);var i}class Xa{constructor(t){this.model=t,this.version=0,this.history=new Ka(this),this.selection=new Lr(this),this.roots=new yi({idProperty:"rootName"}),this.differ=new $a(t.markers),this._postFixers=new Set,this._hasSelectionChangedFromTheLastChangeBlock=!1,this.createRoot("$root","$graveyard"),this.listenTo(t,"applyOperation",(t,e)=>{const i=e[0];if(i.isDocumentOperation&&i.baseVersion!==this.version)throw new hi.b("model-document-applyOperation-wrong-version: Only operations with matching versions can be applied.",this,{operation:i})},{priority:"highest"}),this.listenTo(t,"applyOperation",(t,e)=>{const i=e[0];i.isDocumentOperation&&this.differ.bufferOperation(i)},{priority:"high"}),this.listenTo(t,"applyOperation",(t,e)=>{const i=e[0];i.isDocumentOperation&&(this.version++,this.history.addOperation(i))},{priority:"low"}),this.listenTo(this.selection,"change",()=>{this._hasSelectionChangedFromTheLastChangeBlock=!0}),this.listenTo(t.markers,"update",(t,e,i,n)=>{this.differ.bufferMarkerChange(e.name,i,n,e.affectsData),null===i&&e.on("change",(t,i)=>{this.differ.bufferMarkerChange(e.name,i,e.getRange(),e.affectsData)})})}get graveyard(){return this.getRoot("$graveyard")}createRoot(t="$root",e="main"){if(this.roots.get(e))throw new hi.b("model-document-createRoot-name-exists: Root with specified name already exists.",this,{name:e});const i=new Va(this,t,e);return this.roots.add(i),i}destroy(){this.selection.destroy(),this.stopListening()}getRoot(t="main"){return this.roots.get(t)}getRootNames(){return Array.from(this.roots,t=>t.rootName).filter(t=>"$graveyard"!=t)}registerPostFixer(t){this._postFixers.add(t)}toJSON(){const t=Mi(this);return t.selection="[engine.model.DocumentSelection]",t.model="[engine.model.Model]",t}_handleChangeBlock(t){this._hasDocumentChangedFromTheLastChangeBlock()&&(this._callPostFixers(t),this.selection.refresh(),this.differ.hasDataChanges()?this.fire("change:data",t.batch):this.fire("change",t.batch),this.selection.refresh(),this.differ.reset()),this._hasSelectionChangedFromTheLastChangeBlock=!1}_hasDocumentChangedFromTheLastChangeBlock(){return!this.differ.isEmpty||this._hasSelectionChangedFromTheLastChangeBlock}_getDefaultRoot(){for(const t of this.roots)if(t!==this.graveyard)return t;return this.graveyard}_getDefaultRange(){const t=this._getDefaultRoot(),e=this.model,i=e.schema,n=e.createPositionFromPath(t,[0]);return i.getNearestSelectionRange(n)||e.createRange(n)}_validateSelectionRange(t){return tc(t.start)&&tc(t.end)}_callPostFixers(t){let e=!1;do{for(const i of this._postFixers)if(this.selection.refresh(),e=i(t),e)break}while(e)}}function tc(t){const e=t.textNode;if(e){const i=e.data,n=t.offset-e.startOffset;return!Ja(i,n)&&!Za(i,n)}return!0}vi(Xa,mi);class ec{constructor(){this._markers=new Map}[Symbol.iterator](){return this._markers.values()}has(t){return this._markers.has(t)}get(t){return this._markers.get(t)||null}_set(t,e,i=!1,n=!1){const o=t instanceof ic?t.name:t,s=this._markers.get(o);if(s){const t=s.getRange();let r=!1;return t.isEqual(e)||(s._attachLiveRange(Nr.fromRange(e)),r=!0),i!=s.managedUsingOperations&&(s._managedUsingOperations=i,r=!0),"boolean"==typeof n&&n!=s.affectsData&&(s._affectsData=n,r=!0),r&&this.fire("update:"+o,s,t,e),s}const r=Nr.fromRange(e),a=new ic(o,r,i,n);return this._markers.set(o,a),this.fire("update:"+o,a,null,e),a}_remove(t){const e=t instanceof ic?t.name:t,i=this._markers.get(e);return!!i&&(this._markers.delete(e),this.fire("update:"+e,i,i.getRange(),null),this._destroyMarker(i),!0)}_refresh(t){const e=t instanceof ic?t.name:t,i=this._markers.get(e);if(!i)throw new hi.b("markercollection-refresh-marker-not-exists: Marker with provided name does not exists.",this);const n=i.getRange();this.fire("update:"+e,i,n,n,i.managedUsingOperations,i.affectsData)}*getMarkersAtPosition(t){for(const e of this)e.getRange().containsPosition(t)&&(yield e)}*getMarkersIntersectingRange(t){for(const e of this)null!==e.getRange().getIntersection(t)&&(yield e)}destroy(){for(const t of this._markers.values())this._destroyMarker(t);this._markers=null,this.stopListening()}*getMarkersGroup(t){for(const e of this._markers.values())e.name.startsWith(t+":")&&(yield e)}_destroyMarker(t){t.stopListening(),t._detachLiveRange()}}vi(ec,mi);class ic{constructor(t,e,i,n){this.name=t,this._liveRange=this._attachLiveRange(e),this._managedUsingOperations=i,this._affectsData=n}get managedUsingOperations(){if(!this._liveRange)throw new hi.b("marker-destroyed: Cannot use a destroyed marker instance.",this);return this._managedUsingOperations}get affectsData(){if(!this._liveRange)throw new hi.b("marker-destroyed: Cannot use a destroyed marker instance.",this);return this._affectsData}getStart(){if(!this._liveRange)throw new hi.b("marker-destroyed: Cannot use a destroyed marker instance.",this);return this._liveRange.start.clone()}getEnd(){if(!this._liveRange)throw new hi.b("marker-destroyed: Cannot use a destroyed marker instance.",this);return this._liveRange.end.clone()}getRange(){if(!this._liveRange)throw new hi.b("marker-destroyed: Cannot use a destroyed marker instance.",this);return this._liveRange.toRange()}is(t){return"marker"==t||"model:marker"==t}_attachLiveRange(t){return this._liveRange&&this._detachLiveRange(),t.delegate("change:range").to(this),t.delegate("change:content").to(this),this._liveRange=t,t}_detachLiveRange(){this._liveRange.stopDelegating("change:range",this),this._liveRange.stopDelegating("change:content",this),this._liveRange.detach(),this._liveRange=null}}vi(ic,mi);class nc extends _a{get type(){return"noop"}clone(){return new nc(this.baseVersion)}getReversed(){return new nc(this.baseVersion+1)}_execute(){}static get className(){return"NoOperation"}}const oc={};oc[Ma.className]=Ma,oc[Oa.className]=Oa,oc[Ra.className]=Ra,oc[Na.className]=Na,oc[nc.className]=nc,oc[_a.className]=_a,oc[La.className]=La,oc[Da.className]=Da,oc[ja.className]=ja,oc[za.className]=za;class sc extends _r{constructor(t,e,i="toNone"){if(super(t,e,i),!this.root.is("rootElement"))throw new hi.b("model-liveposition-root-not-rootelement: LivePosition's root has to be an instance of RootElement.",t);rc.call(this)}detach(){this.stopListening()}is(t){return"livePosition"==t||"model:livePosition"==t||super.is(t)}toPosition(){return new _r(this.root,this.path.slice(),this.stickiness)}static fromPosition(t,e){return new this(t.root,t.path.slice(),e||t.stickiness)}}function rc(){this.listenTo(this.root.document.model,"applyOperation",(t,e)=>{const i=e[0];i.isDocumentOperation&&ac.call(this,i)},{priority:"low"})}function ac(t){const e=this.getTransformedByOperation(t);if(!this.isEqual(e)){const t=this.toPosition();this.path=e.path,this.root=e.root,this.fire("change",t)}}vi(sc,mi);class cc{constructor(t,e,i){this.model=t,this.writer=e,this.position=i,this.canMergeWith=new Set([this.position.parent]),this.schema=t.schema,this._filterAttributesOf=[],this._affectedStart=null,this._affectedEnd=null}handleNodes(t,e){t=Array.from(t);for(let i=0;i<t.length;i++){const n=t[i];this._handleNode(n,{isFirst:0===i&&e.isFirst,isLast:i===t.length-1&&e.isLast})}this.schema.removeDisallowedAttributes(this._filterAttributesOf,this.writer),this._filterAttributesOf=[]}getSelectionRange(){return this.nodeToSelect?vr._createOn(this.nodeToSelect):this.model.schema.getNearestSelectionRange(this.position)}getAffectedRange(){return this._affectedStart?new vr(this._affectedStart,this._affectedEnd):null}destroy(){this._affectedStart&&this._affectedStart.detach(),this._affectedEnd&&this._affectedEnd.detach()}_handleNode(t,e){if(this.schema.isObject(t))return void this._handleObject(t,e);this._checkAndSplitToAllowedPosition(t,e)?(this._insert(t),this._mergeSiblingsOf(t,e)):this._handleDisallowedNode(t,e)}_handleObject(t,e){this._checkAndSplitToAllowedPosition(t)?this._insert(t):this._tryAutoparagraphing(t,e)}_handleDisallowedNode(t,e){t.is("element")?this.handleNodes(t.getChildren(),e):this._tryAutoparagraphing(t,e)}_insert(t){if(!this.schema.checkChild(this.position,t))throw new hi.b("insertcontent-wrong-position: Given node cannot be inserted on the given position.",this,{node:t,position:this.position});const e=sc.fromPosition(this.position,"toNext");this._setAffectedBoundaries(this.position),this.writer.insert(t,this.position),this.position=e.toPosition(),e.detach(),this.schema.isObject(t)&&!this.schema.checkChild(this.position,"$text")?this.nodeToSelect=t:this.nodeToSelect=null,this._filterAttributesOf.push(t)}_setAffectedBoundaries(t){this._affectedStart||(this._affectedStart=sc.fromPosition(t,"toPrevious")),this._affectedEnd&&!this._affectedEnd.isBefore(t)||(this._affectedEnd&&this._affectedEnd.detach(),this._affectedEnd=sc.fromPosition(t,"toNext"))}_mergeSiblingsOf(t,e){if(!(t instanceof br))return;const i=this._canMergeLeft(t,e),n=this._canMergeRight(t,e),o=sc._createBefore(t);o.stickiness="toNext";const s=sc._createAfter(t);if(s.stickiness="toNext",i){const t=sc.fromPosition(this.position);t.stickiness="toNext",this._affectedStart.isEqual(o)&&(this._affectedStart.detach(),this._affectedStart=sc._createAt(o.nodeBefore,"end","toPrevious")),this.writer.merge(o),o.isEqual(this._affectedEnd)&&e.isLast&&(this._affectedEnd.detach(),this._affectedEnd=sc._createAt(o.nodeBefore,"end","toNext")),this.position=t.toPosition(),t.detach()}if(n){if(!this.position.isEqual(s))throw new hi.b("insertcontent-invalid-insertion-position",this);this.position=_r._createAt(s.nodeBefore,"end");const t=sc.fromPosition(this.position,"toPrevious");this._affectedEnd.isEqual(s)&&(this._affectedEnd.detach(),this._affectedEnd=sc._createAt(s.nodeBefore,"end","toNext")),this.writer.merge(s),s.getShiftedBy(-1).isEqual(this._affectedStart)&&e.isFirst&&(this._affectedStart.detach(),this._affectedStart=sc._createAt(s.nodeBefore,0,"toPrevious")),this.position=t.toPosition(),t.detach()}(i||n)&&this._filterAttributesOf.push(this.position.parent),o.detach(),s.detach()}_canMergeLeft(t,e){const i=t.previousSibling;return e.isFirst&&i instanceof br&&this.canMergeWith.has(i)&&this.model.schema.checkMerge(i,t)}_canMergeRight(t,e){const i=t.nextSibling;return e.isLast&&i instanceof br&&this.canMergeWith.has(i)&&this.model.schema.checkMerge(t,i)}_tryAutoparagraphing(t,e){const i=this.writer.createElement("paragraph");this._getAllowedIn(i,this.position.parent)&&this.schema.checkChild(i,t)&&(i._appendChild(t),this._handleNode(i,e))}_checkAndSplitToAllowedPosition(t){const e=this._getAllowedIn(t,this.position.parent);if(!e)return!1;for(;e!=this.position.parent;){if(this.schema.isLimit(this.position.parent))return!1;if(this.position.isAtStart){const t=this.position.parent;this.position=this.writer.createPositionBefore(t),t.isEmpty&&t.parent===e&&this.writer.remove(t)}else if(this.position.isAtEnd)this.position=this.writer.createPositionAfter(this.position.parent);else{const t=this.writer.createPositionAfter(this.position.parent);this._setAffectedBoundaries(this.position),this.writer.split(this.position),this.position=t,this.canMergeWith.add(this.position.nodeAfter)}}return!0}_getAllowedIn(t,e){return this.schema.checkChild(e,t)?e:e.parent?this._getAllowedIn(t,e.parent):null}}function lc(t,e,i={}){if(e.isCollapsed)return;const n=e.getFirstRange();if("$graveyard"==n.root.rootName)return;const o=t.schema;t.change(t=>{if(!i.doNotResetEntireContent&&function(t,e){const i=t.getLimitElement(e);if(!e.containsEntireContent(i))return!1;const n=e.getFirstRange();if(n.start.parent==n.end.parent)return!1;return t.checkChild(i,"paragraph")}(o,e))return void function(t,e){const i=t.model.schema.getLimitElement(e);t.remove(t.createRangeIn(i)),dc(t,t.createPositionAt(i,0),e)}(t,e);const s=n.start,r=sc.fromPosition(n.end,"toNext");if(n.start.isTouching(n.end)||t.remove(n),i.leaveUnmerged||(!function t(e,i,n){const o=i.parent,s=n.parent;if(o==s)return;if(e.model.schema.isLimit(o)||e.model.schema.isLimit(s))return;if(!function(t,e,i){const n=new vr(t,e);for(const t of n.getWalker())if(i.isLimit(t.item))return!1;return!0}(i,n,e.model.schema))return;i=e.createPositionAfter(o),(n=e.createPositionBefore(s)).isEqual(i)||e.insert(s,i);e.merge(i);for(;n.parent.isEmpty;){const t=n.parent;n=e.createPositionBefore(t),e.remove(t)}t(e,i,n)}(t,s,r),o.removeDisallowedAttributes(s.parent.getChildren(),t)),hc(t,e,s),function(t,e){const i=t.checkChild(e,"$text"),n=t.checkChild(e,"paragraph");return!i&&n}(o,s)){const n=o.getNearestSelectionRange(s);i.doNotAutoparagraph&&n?hc(t,e,n):dc(t,s,e)}r.detach()})}function dc(t,e,i){const n=t.createElement("paragraph");t.insert(n,e),hc(t,i,t.createPositionAt(n,0))}function hc(t,e,i){e instanceof Lr?t.setSelection(i):e.setTo(i)}function uc(t,e){if("text"==e.type)return"word"===t.unit?function(t,e){let i=t.position.textNode;if(i){let n=t.position.offset-i.startOffset;for(;!mc(i.data,n,e)&&!gc(i,n,e);){t.next();const o=e?t.position.nodeAfter:t.position.nodeBefore;if(o&&o.is("text")){const n=o.data.charAt(e?0:o.data.length-1);' ,.?!:;"-()'.includes(n)||(t.next(),i=t.position.textNode)}n=t.position.offset-i.startOffset}}return t.position}(t.walker,t.isForward):function(t,e){const i=t.position.textNode;if(i){const n=i.data;let o=t.position.offset-i.startOffset;for(;Ja(n,o)||"character"==e&&Za(n,o);)t.next(),o=t.position.offset-i.startOffset}return t.position}(t.walker,t.unit,t.isForward);if(e.type==(t.isForward?"elementStart":"elementEnd")){if(t.schema.isObject(e.item))return _r._createAt(e.item,t.isForward?"after":"before");if(t.schema.checkChild(e.nextPosition,"$text"))return e.nextPosition}else{if(t.schema.isLimit(e.item))return void t.walker.skip(()=>!0);if(t.schema.checkChild(e.nextPosition,"$text"))return e.nextPosition}}function fc(t,e){const i=t.root,n=_r._createAt(i,e?"end":0);return e?new vr(t,n):new vr(n,t)}function mc(t,e,i){const n=e+(i?0:-1);return' ,.?!:;"-()'.includes(t.charAt(n))}function gc(t,e,i){return e===(i?t.endOffset:0)}function pc(t,e){const i=[];Array.from(t.getItems({direction:"backward"})).map(t=>e.createRangeOn(t)).filter(e=>(e.start.isAfter(t.start)||e.start.isEqual(t.start))&&(e.end.isBefore(t.end)||e.end.isEqual(t.end))).forEach(t=>{i.push(t.start.parent),e.remove(t)}),i.forEach(t=>{let i=t;for(;i.parent&&i.isEmpty;){const t=e.createRangeOn(i);i=i.parent,e.remove(t)}})}function bc(t){t.document.registerPostFixer(e=>function(t,e){const i=e.document.selection,n=e.schema,o=[];let s=!1;for(const t of i.getRanges()){const e=wc(t,n);e?(o.push(e),s=!0):o.push(t)}s&&t.setSelection(function(t){const e=[];e.push(t.shift());for(const i of t){const t=e.pop();if(i.isIntersecting(t)){const n=t.start.isAfter(i.start)?i.start:t.start,o=t.end.isAfter(i.end)?t.end:i.end,s=new vr(n,o);e.push(s)}else e.push(t),e.push(i)}return e}(o),{backward:i.isBackward})}(e,t))}function wc(t,e){return t.isCollapsed?function(t,e){const i=t.start,n=e.getNearestSelectionRange(i);if(!n)return null;if(!n.isCollapsed)return n;const o=n.start;if(i.isEqual(o))return null;return new vr(o)}(t,e):function(t,e){const i=t.start,n=t.end,o=e.checkChild(i,"$text"),s=e.checkChild(n,"$text"),r=e.getLimitElement(i),a=e.getLimitElement(n);if(r===a){if(o&&s)return null;if(function(t,e,i){const n=t.nodeAfter&&!i.isLimit(t.nodeAfter)||i.checkChild(t,"$text"),o=e.nodeBefore&&!i.isLimit(e.nodeBefore)||i.checkChild(e,"$text");return n||o}(i,n,e)){const t=i.nodeAfter&&e.isObject(i.nodeAfter)?null:e.getNearestSelectionRange(i,"forward"),o=n.nodeBefore&&e.isObject(n.nodeBefore)?null:e.getNearestSelectionRange(n,"backward"),s=t?t.start:i,r=o?o.start:n;return new vr(s,r)}}const c=r&&!r.is("rootElement"),l=a&&!a.is("rootElement");if(c||l){const t=i.nodeAfter&&n.nodeBefore&&i.nodeAfter.parent===n.nodeBefore.parent,o=c&&(!t||!_c(i.nodeAfter,e)),s=l&&(!t||!_c(n.nodeBefore,e));let d=i,h=n;return o&&(d=_r._createBefore(kc(r,e))),s&&(h=_r._createAfter(kc(a,e))),new vr(d,h)}return null}(t,e)}function kc(t,e){let i=t,n=i;for(;e.isLimit(n)&&n.parent;)i=n,n=n.parent;return i}function _c(t,e){return t&&e.isObject(t)}class vc{constructor(){this.markers=new ec,this.document=new Xa(this),this.schema=new ea,this._pendingChanges=[],this._currentWriter=null,["insertContent","deleteContent","modifySelection","getSelectedContent","applyOperation"].forEach(t=>this.decorate(t)),this.on("applyOperation",(t,e)=>{e[0]._validate()},{priority:"highest"}),this.schema.register("$root",{isLimit:!0}),this.schema.register("$block",{allowIn:"$root",isBlock:!0}),this.schema.register("$text",{allowIn:"$block",isInline:!0}),this.schema.register("$clipboardHolder",{allowContentOf:"$root",isLimit:!0}),this.schema.extend("$text",{allowIn:"$clipboardHolder"}),this.schema.register("$marker"),this.schema.addChildCheck((t,e)=>{if("$marker"===e.name)return!0}),bc(this)}change(t){try{return 0===this._pendingChanges.length?(this._pendingChanges.push({batch:new ka,callback:t}),this._runPendingChanges()[0]):t(this._currentWriter)}catch(t){hi.b.rethrowUnexpectedError(t,this)}}enqueueChange(t,e){try{"string"==typeof t?t=new ka(t):"function"==typeof t&&(e=t,t=new ka),this._pendingChanges.push({batch:t,callback:e}),1==this._pendingChanges.length&&this._runPendingChanges()}catch(t){hi.b.rethrowUnexpectedError(t,this)}}applyOperation(t){t._execute()}insertContent(t,e,i){return function(t,e,i,n){return t.change(o=>{let s;s=i?i instanceof Pr||i instanceof Lr?i:o.createSelection(i,n):t.document.selection;const r=s.getFirstPosition();s.isCollapsed||t.deleteContent(s,{doNotAutoparagraph:!0});const a=new cc(t,o,r);let c;c=e.is("documentFragment")?e.getChildren():[e],a.handleNodes(c,{isFirst:!0,isLast:!0});const l=a.getSelectionRange();l&&(s instanceof Lr?o.setSelection(l):s.setTo(l));const d=a.getAffectedRange()||t.createRange(r);return a.destroy(),d})}(this,t,e,i)}deleteContent(t,e){lc(this,t,e)}modifySelection(t,e){!function(t,e,i={}){const n=t.schema,o="backward"!=i.direction,s=i.unit?i.unit:"character",r=e.focus,a=new wr({boundaries:fc(r,o),singleCharacters:!0,direction:o?"forward":"backward"}),c={walker:a,schema:n,isForward:o,unit:s};let l;for(;l=a.next();){if(l.done)return;const i=uc(c,l.value);if(i)return void(e instanceof Lr?t.change(t=>{t.setSelectionFocus(i)}):e.setFocus(i))}}(this,t,e)}getSelectedContent(t){return function(t,e){return t.change(t=>{const i=t.createDocumentFragment(),n=e.getFirstRange();if(!n||n.isCollapsed)return i;const o=n.start.root,s=n.start.getCommonPath(n.end),r=o.getNodeByPath(s);let a;a=n.start.parent==n.end.parent?n:t.createRange(t.createPositionAt(r,n.start.path[s.length]),t.createPositionAt(r,n.end.path[s.length]+1));const c=a.end.offset-a.start.offset;for(const e of a.getItems({shallow:!0}))e.is("textProxy")?t.appendText(e.data,e.getAttributes(),i):t.append(e._clone(!0),i);if(a!=n){const e=n._getTransformedByMove(a.start,t.createPositionAt(i,0),c)[0],o=t.createRange(t.createPositionAt(i,0),e.start);pc(t.createRange(e.end,t.createPositionAt(i,"end")),t),pc(o,t)}return i})}(this,t)}hasContent(t,e){const i=t instanceof br?vr._createIn(t):t;if(i.isCollapsed)return!1;for(const t of this.markers.getMarkersIntersectingRange(i))if(t.affectsData)return!0;const{ignoreWhitespaces:n=!1}=e||{};for(const t of i.getItems())if(t.is("textProxy")){if(!n)return!0;if(-1!==t.data.search(/\S/))return!0}else if(this.schema.isObject(t))return!0;return!1}createPositionFromPath(t,e,i){return new _r(t,e,i)}createPositionAt(t,e){return _r._createAt(t,e)}createPositionAfter(t){return _r._createAfter(t)}createPositionBefore(t){return _r._createBefore(t)}createRange(t,e){return new vr(t,e)}createRangeIn(t){return vr._createIn(t)}createRangeOn(t){return vr._createOn(t)}createSelection(t,e,i){return new Pr(t,e,i)}createBatch(t){return new ka(t)}createOperationFromJSON(t){return class{static fromJSON(t,e){return oc[t.__className].fromJSON(t,e)}}.fromJSON(t,this.document)}destroy(){this.document.destroy(),this.stopListening()}_runPendingChanges(){const t=[];for(this.fire("_beforeChanges");this._pendingChanges.length;){const e=this._pendingChanges[0].batch;this._currentWriter=new Ba(this,e);const i=this._pendingChanges[0].callback(this._currentWriter);t.push(i),this.document._handleChangeBlock(this._currentWriter),this._pendingChanges.shift(),this._currentWriter=null}return this.fire("_afterChanges"),t}}vi(vc,Hn);class yc{constructor(){this._listener=Object.create(ls)}listenTo(t){this._listener.listenTo(t,"keydown",(t,e)=>{this._listener.fire("_keydown:"+bo(e),e)})}set(t,e,i={}){const n=wo(t),o=i.priority;this._listener.listenTo(this._listener,"_keydown:"+n,(t,i)=>{e(i,()=>{i.preventDefault(),i.stopPropagation(),t.stop()}),t.return=!0},{priority:o})}press(t){return!!this._listener.fire("_keydown:"+bo(t),t)}destroy(){this._listener.stopListening()}}class xc extends yc{constructor(t){super(),this.editor=t}set(t,e,i={}){if("string"==typeof e){const t=e;e=(e,i)=>{this.editor.execute(t),i()}}super.set(t,e,i)}}class Ac{constructor(t={}){this._context=t.context||new Si({language:t.language}),this._context._addEditor(this,!t.context);const e=Array.from(this.constructor.builtinPlugins||[]);this.config=new ni(t,this.constructor.defaultConfig),this.config.define("plugins",e),this.config.define(this._context._getEditorConfig()),this.plugins=new xi(this,e,this._context.plugins),this.locale=this._context.locale,this.t=this.locale.t,this.commands=new Zr,this.set("state","initializing"),this.once("ready",()=>this.state="ready",{priority:"high"}),this.once("destroy",()=>this.state="destroyed",{priority:"high"}),this.set("isReadOnly",!1),this.model=new vc,this.data=new ga(this.model),this.editing=new Jr(this.model),this.editing.view.document.bind("isReadOnly").to(this),this.conversion=new pa([this.editing.downcastDispatcher,this.data.downcastDispatcher],this.data.upcastDispatcher),this.conversion.addAlias("dataDowncast",this.data.downcastDispatcher),this.conversion.addAlias("editingDowncast",this.editing.downcastDispatcher),this.keystrokes=new xc(this),this.keystrokes.listenTo(this.editing.view.document)}initPlugins(){const t=this.config,e=t.get("plugins"),i=t.get("removePlugins")||[],n=t.get("extraPlugins")||[];return this.plugins.init(e.concat(n),i)}destroy(){let t=Promise.resolve();return"initializing"==this.state&&(t=new Promise(t=>this.once("ready",t))),t.then(()=>{this.fire("destroy"),this.stopListening(),this.commands.destroy()}).then(()=>this.plugins.destroy()).then(()=>{this.model.destroy(),this.data.destroy(),this.editing.destroy(),this.keystrokes.destroy()}).then(()=>this._context._removeEditor(this))}execute(...t){try{this.commands.execute(...t)}catch(t){hi.b.rethrowUnexpectedError(t,this)}}}vi(Ac,Hn);var Cc={setData(t){this.data.set(t)},getData(t){return this.data.get(t)}};var Tc={updateSourceElement(){if(!this.sourceElement)throw new hi.b("editor-missing-sourceelement: Cannot update the source element of a detached editor.",this);var t,e;t=this.sourceElement,e=this.data.get(),t instanceof HTMLTextAreaElement&&(t.value=e),t.innerHTML=e}};class Pc{getHtml(t){const e=document.implementation.createHTMLDocument("").createElement("div");return e.appendChild(t),e.innerHTML}}class Sc{constructor(){this._domParser=new DOMParser,this._domConverter=new os({blockFillerMode:"nbsp"}),this._htmlWriter=new Pc}toData(t){const e=this._domConverter.viewToDom(t,document);return this._htmlWriter.getHtml(e)}toView(t){const e=this._toDom(t);return this._domConverter.domToView(e)}_toDom(t){const e=this._domParser.parseFromString(t,"text/html"),i=e.createDocumentFragment(),n=e.body.childNodes;for(;n.length>0;)i.appendChild(n[0]);return i}}class Ec{constructor(t){this.editor=t,this._components=new Map}*names(){for(const t of this._components.values())yield t.originalName}add(t,e){if(this.has(t))throw new hi.b("componentfactory-item-exists: The item already exists in the component factory.",this,{name:t});this._components.set(Mc(t),{callback:e,originalName:t})}create(t){if(!this.has(t))throw new hi.b("componentfactory-item-missing: The required component is not registered in the factory.",this,{name:t});return this._components.get(Mc(t)).callback(this.editor.locale)}has(t){return this._components.has(Mc(t))}}function Mc(t){return String(t).toLowerCase()}class Ic{constructor(){this.set("isFocused",!1),this.set("focusedElement",null),this._elements=new Set,this._nextEventLoopTimeout=null}add(t){if(this._elements.has(t))throw new hi.b("focusTracker-add-element-already-exist",this);this.listenTo(t,"focus",()=>this._focus(t),{useCapture:!0}),this.listenTo(t,"blur",()=>this._blur(),{useCapture:!0}),this._elements.add(t)}remove(t){t===this.focusedElement&&this._blur(t),this._elements.has(t)&&(this.stopListening(t),this._elements.delete(t))}destroy(){this.stopListening()}_focus(t){clearTimeout(this._nextEventLoopTimeout),this.focusedElement=t,this.isFocused=!0}_blur(){clearTimeout(this._nextEventLoopTimeout),this._nextEventLoopTimeout=setTimeout(()=>{this.focusedElement=null,this.isFocused=!1},0)}}vi(Ic,ls),vi(Ic,Hn);class Nc{constructor(t){this.editor=t,this.componentFactory=new Ec(t),this.focusTracker=new Ic,this._editableElementsMap=new Map,this.listenTo(t.editing.view.document,"layoutChanged",()=>this.update())}get element(){return null}update(){this.fire("update")}destroy(){this.stopListening(),this.focusTracker.destroy();for(const t of this._editableElementsMap.values())t.ckeditorInstance=null;this._editableElementsMap=new Map}setEditableElement(t,e){this._editableElementsMap.set(t,e),e.ckeditorInstance||(e.ckeditorInstance=this.editor)}getEditableElement(t="main"){return this._editableElementsMap.get(t)}getEditableElementsNames(){return this._editableElementsMap.keys()}get _editableElements(){return console.warn("editor-ui-deprecated-editable-elements: The EditorUI#_editableElements property has been deprecated and will be removed in the near future.",{editorUI:this}),this._editableElementsMap}}vi(Nc,mi);i(14);const Oc=new WeakMap;function Rc(t){const{view:e,element:i,text:n,isDirectHost:o=!0}=t,s=e.document;Oc.has(s)||(Oc.set(s,new Map),s.registerPostFixer(t=>Dc(s,t))),Oc.get(s).set(i,{text:n,isDirectHost:o}),e.change(t=>Dc(s,t))}function Lc(t,e){return!!e.hasClass("ck-placeholder")&&(t.removeClass("ck-placeholder",e),!0)}function Dc(t,e){const i=Oc.get(t);let n=!1;for(const[t,o]of i)zc(e,t,o)&&(n=!0);return n}function zc(t,e,i){const{text:n,isDirectHost:o}=i,s=o?e:function(t){if(1===t.childCount){const e=t.getChild(0);if(e.is("element")&&!e.is("uiElement"))return e}return null}(e);let r=!1;return!!s&&(i.hostElement=s,s.getAttribute("data-placeholder")!==n&&(t.setAttribute("data-placeholder",n,s),r=!0),!function(t){const e=t.document;if(!e)return!1;const i=!Array.from(t.getChildren()).some(t=>!t.is("uiElement"));if(!e.isFocused&&i)return!0;const n=e.selection.anchor;return!(!i||!n||n.parent===t)}(s)?Lc(t,s)&&(r=!0):function(t,e){return!e.hasClass("ck-placeholder")&&(t.addClass("ck-placeholder",e),!0)}(t,s)&&(r=!0),r)}class jc{constructor(){this._replacedElements=[]}replace(t,e){this._replacedElements.push({element:t,newElement:e}),t.style.display="none",e&&t.parentNode.insertBefore(e,t.nextSibling)}restore(){this._replacedElements.forEach(({element:t,newElement:e})=>{t.style.display="",e&&e.remove()}),this._replacedElements=[]}}class Vc extends Nc{constructor(t,e){var i;super(t),this.view=e,this._toolbarConfig=(i=t.config.get("toolbar"),Array.isArray(i)?{items:i}:i?Object.assign({items:[]},i):{items:[]}),this._elementReplacer=new jc}get element(){return this.view.element}init(t){const e=this.editor,i=this.view,n=e.editing.view,o=i.editable,s=n.document.getRoot();o.name=s.rootName,i.render();const r=o.element;this.setEditableElement(o.name,r),this.focusTracker.add(r),i.editable.bind("isFocused").to(this.focusTracker),n.attachDomRoot(r),t&&this._elementReplacer.replace(t,this.element),this._initPlaceholder(),this._initToolbar(),this.fire("ready")}destroy(){const t=this.view,e=this.editor.editing.view;this._elementReplacer.restore(),e.detachDomRoot(t.editable.name),t.destroy(),super.destroy()}_initToolbar(){const t=this.editor,e=this.view,i=t.editing.view;e.stickyPanel.bind("isActive").to(this.focusTracker,"isFocused"),e.stickyPanel.limiterElement=e.element,this._toolbarConfig.viewportTopOffset&&(e.stickyPanel.viewportTopOffset=this._toolbarConfig.viewportTopOffset),e.toolbar.fillFromConfig(this._toolbarConfig.items,this.componentFactory),function({origin:t,originKeystrokeHandler:e,originFocusTracker:i,toolbar:n,beforeFocus:o,afterBlur:s}){i.add(n.element),e.set("Alt+F10",(t,e)=>{i.isFocused&&!n.focusTracker.isFocused&&(o&&o(),n.focus(),e())}),n.keystrokes.set("Esc",(e,i)=>{n.focusTracker.isFocused&&(t.focus(),s&&s(),i())})}({origin:i,originFocusTracker:this.focusTracker,originKeystrokeHandler:t.keystrokes,toolbar:e.toolbar})}_initPlaceholder(){const t=this.editor,e=t.editing.view,i=e.document.getRoot(),n=t.sourceElement,o=t.config.get("placeholder")||n&&"textarea"===n.tagName.toLowerCase()&&n.getAttribute("placeholder");o&&Rc({view:e,element:i,text:o,isDirectHost:!1})}}class Bc extends yi{constructor(t){super({idProperty:"viewUid"}),this.on("add",(t,e,i)=>{e.isRendered||e.render(),e.element&&this._parentElement&&this._parentElement.insertBefore(e.element,this._parentElement.children[i])}),this.on("remove",(t,e)=>{e.element&&this._parentElement&&e.element.remove()}),this.locale=t,this._parentElement=null}destroy(){this.map(t=>t.destroy())}setParent(t){this._parentElement=t}delegate(...t){if(!t.length||!t.every(t=>"string"==typeof t))throw new hi.b("ui-viewcollection-delegate-wrong-events: All event names must be strings.",this);return{to:e=>{for(const i of this)for(const n of t)i.delegate(n).to(e);this.on("add",(i,n)=>{for(const i of t)n.delegate(i).to(e)}),this.on("remove",(i,n)=>{for(const i of t)n.stopDelegating(i,e)})}}}}class Fc{constructor(t){Object.assign(this,Jc(Kc(t))),this._isRendered=!1,this._revertData=null}render(){const t=this._renderNode({intoFragment:!0});return this._isRendered=!0,t}apply(t){return this._revertData={children:[],bindings:[],attributes:{}},this._renderNode({node:t,isApplying:!0,revertData:this._revertData}),t}revert(t){if(!this._revertData)throw new hi.b("ui-template-revert-not-applied: Attempting to revert a template which has not been applied yet.",[this,t]);this._revertTemplateFromNode(t,this._revertData)}*getViews(){yield*function*t(e){if(e.children)for(const i of e.children)il(i)?yield i:nl(i)&&(yield*t(i))}(this)}static bind(t,e){return{to:(i,n)=>new Uc({eventNameOrFunction:i,attribute:i,observable:t,emitter:e,callback:n}),if:(i,n,o)=>new Wc({observable:t,emitter:e,attribute:i,valueIfTrue:n,callback:o})}}static extend(t,e){if(t._isRendered)throw new hi.b("template-extend-render: Attempting to extend a template which has already been rendered.",[this,t]);!function t(e,i){i.attributes&&(e.attributes||(e.attributes={}),tl(e.attributes,i.attributes));i.eventListeners&&(e.eventListeners||(e.eventListeners={}),tl(e.eventListeners,i.eventListeners));i.text&&e.text.push(...i.text);if(i.children&&i.children.length){if(e.children.length!=i.children.length)throw new hi.b("ui-template-extend-children-mismatch: The number of children in extended definition does not match.",e);let n=0;for(const o of i.children)t(e.children[n++],o)}}(t,Jc(Kc(e)))}_renderNode(t){let e;if(e=t.node?this.tag&&this.text:this.tag?this.text:!this.text,e)throw new hi.b('ui-template-wrong-syntax: Node definition must have either "tag" or "text" when rendering a new Node.',this);return this.text?this._renderText(t):this._renderElement(t)}_renderElement(t){let e=t.node;return e||(e=t.node=document.createElementNS(this.ns||"http://www.w3.org/1999/xhtml",this.tag)),this._renderAttributes(t),this._renderElementChildren(t),this._setUpListeners(t),e}_renderText(t){let e=t.node;return e?t.revertData.text=e.textContent:e=t.node=document.createTextNode(""),qc(this.text)?this._bindToObservable({schema:this.text,updater:Yc(e),data:t}):e.textContent=this.text.join(""),e}_renderAttributes(t){let e,i,n,o;if(!this.attributes)return;const s=t.node,r=t.revertData;for(e in this.attributes)if(n=s.getAttribute(e),i=this.attributes[e],r&&(r.attributes[e]=n),o=z(i[0])&&i[0].ns?i[0].ns:null,qc(i)){const a=o?i[0].value:i;r&&sl(e)&&a.unshift(n),this._bindToObservable({schema:a,updater:Gc(s,e,o),data:t})}else"style"==e&&"string"!=typeof i[0]?this._renderStyleAttribute(i[0],t):(r&&n&&sl(e)&&i.unshift(n),i=i.map(t=>t&&t.value||t).reduce((t,e)=>t.concat(e),[]).reduce(Xc,""),el(i)||s.setAttributeNS(o,e,i))}_renderStyleAttribute(t,e){const i=e.node;for(const n in t){const o=t[n];qc(o)?this._bindToObservable({schema:[o],updater:Qc(i,n),data:e}):i.style[n]=o}}_renderElementChildren(t){const e=t.node,i=t.intoFragment?document.createDocumentFragment():e,n=t.isApplying;let o=0;for(const s of this.children)if(ol(s)){if(!n){s.setParent(e);for(const t of s)i.appendChild(t.element)}}else if(il(s))n||(s.isRendered||s.render(),i.appendChild(s.element));else if(Qo(s))i.appendChild(s);else if(n){const e={children:[],bindings:[],attributes:{}};t.revertData.children.push(e),s._renderNode({node:i.childNodes[o++],isApplying:!0,revertData:e})}else i.appendChild(s.render());t.intoFragment&&e.appendChild(i)}_setUpListeners(t){if(this.eventListeners)for(const e in this.eventListeners){const i=this.eventListeners[e].map(i=>{const[n,o]=e.split("@");return i.activateDomEventListener(n,o,t)});t.revertData&&t.revertData.bindings.push(i)}}_bindToObservable({schema:t,updater:e,data:i}){const n=i.revertData;$c(t,e,i);const o=t.filter(t=>!el(t)).filter(t=>t.observable).map(n=>n.activateAttributeListener(t,e,i));n&&n.bindings.push(o)}_revertTemplateFromNode(t,e){for(const t of e.bindings)for(const e of t)e();if(e.text)t.textContent=e.text;else{for(const i in e.attributes){const n=e.attributes[i];null===n?t.removeAttribute(i):t.setAttribute(i,n)}for(let i=0;i<e.children.length;++i)this._revertTemplateFromNode(t.childNodes[i],e.children[i])}}}vi(Fc,mi);class Hc{constructor(t){Object.assign(this,t)}getValue(t){const e=this.observable[this.attribute];return this.callback?this.callback(e,t):e}activateAttributeListener(t,e,i){const n=()=>$c(t,e,i);return this.emitter.listenTo(this.observable,"change:"+this.attribute,n),()=>{this.emitter.stopListening(this.observable,"change:"+this.attribute,n)}}}class Uc extends Hc{activateDomEventListener(t,e,i){const n=(t,i)=>{e&&!i.target.matches(e)||("function"==typeof this.eventNameOrFunction?this.eventNameOrFunction(i):this.observable.fire(this.eventNameOrFunction,i))};return this.emitter.listenTo(i.node,t,n),()=>{this.emitter.stopListening(i.node,t,n)}}}class Wc extends Hc{getValue(t){return!el(super.getValue(t))&&(this.valueIfTrue||!0)}}function qc(t){return!!t&&(t.value&&(t=t.value),Array.isArray(t)?t.some(qc):t instanceof Hc)}function $c(t,e,{node:i}){let n=function(t,e){return t.map(t=>t instanceof Hc?t.getValue(e):t)}(t,i);n=1==t.length&&t[0]instanceof Wc?n[0]:n.reduce(Xc,""),el(n)?e.remove():e.set(n)}function Yc(t){return{set(e){t.textContent=e},remove(){t.textContent=""}}}function Gc(t,e,i){return{set(n){t.setAttributeNS(i,e,n)},remove(){t.removeAttributeNS(i,e)}}}function Qc(t,e){return{set(i){t.style[e]=i},remove(){t.style[e]=null}}}function Kc(t){return ei(t,t=>{if(t&&(t instanceof Hc||nl(t)||il(t)||ol(t)))return t})}function Jc(t){if("string"==typeof t?t=function(t){return{text:[t]}}(t):t.text&&function(t){Array.isArray(t.text)||(t.text=[t.text])}(t),t.on&&(t.eventListeners=function(t){for(const e in t)Zc(t,e);return t}(t.on),delete t.on),!t.text){t.attributes&&function(t){for(const e in t)t[e].value&&(t[e].value=[].concat(t[e].value)),Zc(t,e)}(t.attributes);const e=[];if(t.children)if(ol(t.children))e.push(t.children);else for(const i of t.children)nl(i)||il(i)||Qo(i)?e.push(i):e.push(new Fc(i));t.children=e}return t}function Zc(t,e){Array.isArray(t[e])||(t[e]=[t[e]])}function Xc(t,e){return el(e)?t:el(t)?e:`${t} ${e}`}function tl(t,e){for(const i in e)t[i]?t[i].push(...e[i]):t[i]=e[i]}function el(t){return!t&&0!==t}function il(t){return t instanceof rl}function nl(t){return t instanceof Fc}function ol(t){return t instanceof Bc}function sl(t){return"class"==t||"style"==t}i(16);class rl{constructor(t){this.element=null,this.isRendered=!1,this.locale=t,this.t=t&&t.t,this._viewCollections=new yi,this._unboundChildren=this.createCollection(),this._viewCollections.on("add",(e,i)=>{i.locale=t}),this.decorate("render")}get bindTemplate(){return this._bindTemplate?this._bindTemplate:this._bindTemplate=Fc.bind(this,this)}createCollection(){const t=new Bc;return this._viewCollections.add(t),t}registerChild(t){Ri(t)||(t=[t]);for(const e of t)this._unboundChildren.add(e)}deregisterChild(t){Ri(t)||(t=[t]);for(const e of t)this._unboundChildren.remove(e)}setTemplate(t){this.template=new Fc(t)}extendTemplate(t){Fc.extend(this.template,t)}render(){if(this.isRendered)throw new hi.b("ui-view-render-already-rendered: This View has already been rendered.",this);this.template&&(this.element=this.template.render(),this.registerChild(this.template.getViews())),this.isRendered=!0}destroy(){this.stopListening(),this._viewCollections.map(t=>t.destroy()),this.template&&this.template._revertData&&this.template.revert(this.element)}}vi(rl,ls),vi(rl,Hn);var al=function(t){return"string"==typeof t||!Lt(t)&&p(t)&&"[object String]"==f(t)};class cl extends Bc{attachToDom(){this._bodyCollectionContainer=new Fc({tag:"div",attributes:{class:["ck","ck-reset_all","ck-body","ck-rounded-corners"],dir:this.locale.uiLanguageDirection},children:this}).render();let t=document.querySelector(".ck-body-wrapper");t||(t=function(t,e,i={},n=[]){const o=i&&i.xmlns,s=o?t.createElementNS(o,e):t.createElement(e);for(const t in i)s.setAttribute(t,i[t]);!al(n)&&Ri(n)||(n=[n]);for(let e of n)al(e)&&(e=t.createTextNode(e)),s.appendChild(e);return s}(document,"div",{class:"ck-body-wrapper"}),document.body.appendChild(t)),t.appendChild(this._bodyCollectionContainer)}detachFromDom(){super.destroy(),this._bodyCollectionContainer&&this._bodyCollectionContainer.remove();const t=document.querySelector(".ck-body-wrapper");t&&0==t.childElementCount&&t.remove()}}i(18);class ll extends rl{constructor(t){super(t),this.body=new cl(t)}render(){super.render(),this.body.attachToDom()}destroy(){return this.body.detachFromDom(),super.destroy()}}i(20);class dl extends rl{constructor(t){super(t),this.set("text"),this.set("for"),this.id=`ck-editor__label_${li()}`;const e=this.bindTemplate;this.setTemplate({tag:"label",attributes:{class:["ck","ck-label"],id:this.id,for:e.to("for")},children:[{text:e.to("text")}]})}}class hl extends ll{constructor(t){super(t),this.top=this.createCollection(),this.main=this.createCollection(),this._voiceLabelView=this._createVoiceLabel(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-reset","ck-editor","ck-rounded-corners"],role:"application",dir:t.uiLanguageDirection,lang:t.uiLanguage,"aria-labelledby":this._voiceLabelView.id},children:[this._voiceLabelView,{tag:"div",attributes:{class:["ck","ck-editor__top","ck-reset_all"],role:"presentation"},children:this.top},{tag:"div",attributes:{class:["ck","ck-editor__main"],role:"presentation"},children:this.main}]})}_createVoiceLabel(){const t=this.t,e=new dl;return e.text=t("bn"),e.extendTemplate({attributes:{class:"ck-voice-label"}}),e}}class ul extends rl{constructor(t,e,i){super(t),this.setTemplate({tag:"div",attributes:{class:["ck","ck-content","ck-editor__editable","ck-rounded-corners"],lang:t.contentLanguage,dir:t.contentLanguageDirection}}),this.name=null,this.set("isFocused",!1),this._editableElement=i,this._hasExternalElement=!!this._editableElement,this._editingView=e}render(){super.render(),this._hasExternalElement?this.template.apply(this.element=this._editableElement):this._editableElement=this.element,this.on("change:isFocused",()=>this._updateIsFocusedClasses()),this._updateIsFocusedClasses()}destroy(){this._hasExternalElement&&this.template.revert(this._editableElement),super.destroy()}_updateIsFocusedClasses(){const t=this._editingView;function e(e){t.change(i=>{const n=t.document.getRoot(e.name);i.addClass(e.isFocused?"ck-focused":"ck-blurred",n),i.removeClass(e.isFocused?"ck-blurred":"ck-focused",n)})}t.isRenderingInProgress?function i(n){t.once("change:isRenderingInProgress",(t,o,s)=>{s?i(n):e(n)})}(this):e(this)}}class fl extends ul{constructor(t,e,i){super(t,e,i),this.extendTemplate({attributes:{role:"textbox",class:"ck-editor__editable_inline"}})}render(){super.render();const t=this._editingView,e=this.t;t.change(i=>{const n=t.document.getRoot(this.name);i.setAttribute("aria-label",e("bo",[this.name]),n)})}}function ml(t){return e=>e+t}i(22);const gl=ml("px");class pl extends rl{constructor(t){super(t);const e=this.bindTemplate;this.set("isActive",!1),this.set("isSticky",!1),this.set("limiterElement",null),this.set("limiterBottomOffset",50),this.set("viewportTopOffset",0),this.set("_marginLeft",null),this.set("_isStickyToTheLimiter",!1),this.set("_hasViewportTopOffset",!1),this.content=this.createCollection(),this._contentPanelPlaceholder=new Fc({tag:"div",attributes:{class:["ck","ck-sticky-panel__placeholder"],style:{display:e.to("isSticky",t=>t?"block":"none"),height:e.to("isSticky",t=>t?gl(this._panelRect.height):null)}}}).render(),this._contentPanel=new Fc({tag:"div",attributes:{class:["ck","ck-sticky-panel__content",e.if("isSticky","ck-sticky-panel__content_sticky"),e.if("_isStickyToTheLimiter","ck-sticky-panel__content_sticky_bottom-limit")],style:{width:e.to("isSticky",t=>t?gl(this._contentPanelPlaceholder.getBoundingClientRect().width):null),top:e.to("_hasViewportTopOffset",t=>t?gl(this.viewportTopOffset):null),bottom:e.to("_isStickyToTheLimiter",t=>t?gl(this.limiterBottomOffset):null),marginLeft:e.to("_marginLeft")}},children:this.content}).render(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-sticky-panel"]},children:[this._contentPanelPlaceholder,this._contentPanel]})}render(){super.render(),this._checkIfShouldBeSticky(),this.listenTo(ts.window,"scroll",()=>{this._checkIfShouldBeSticky()}),this.listenTo(this,"change:isActive",()=>{this._checkIfShouldBeSticky()})}_checkIfShouldBeSticky(){const t=this._panelRect=this._contentPanel.getBoundingClientRect();let e;this.limiterElement?(e=this._limiterRect=this.limiterElement.getBoundingClientRect(),this.isSticky=this.isActive&&e.top<this.viewportTopOffset&&this._panelRect.height+this.limiterBottomOffset<e.height):this.isSticky=!1,this.isSticky?(this._isStickyToTheLimiter=e.bottom<t.height+this.limiterBottomOffset+this.viewportTopOffset,this._hasViewportTopOffset=!this._isStickyToTheLimiter&&!!this.viewportTopOffset,this._marginLeft=this._isStickyToTheLimiter?null:gl(-ts.window.scrollX)):(this._isStickyToTheLimiter=!1,this._hasViewportTopOffset=!1,this._marginLeft=null)}}class bl{constructor(t){if(Object.assign(this,t),t.actions&&t.keystrokeHandler)for(const e in t.actions){let i=t.actions[e];"string"==typeof i&&(i=[i]);for(const n of i)t.keystrokeHandler.set(n,(t,i)=>{this[e](),i()})}}get first(){return this.focusables.find(wl)||null}get last(){return this.focusables.filter(wl).slice(-1)[0]||null}get next(){return this._getFocusableItem(1)}get previous(){return this._getFocusableItem(-1)}get current(){let t=null;return null===this.focusTracker.focusedElement?null:(this.focusables.find((e,i)=>{const n=e.element===this.focusTracker.focusedElement;return n&&(t=i),n}),t)}focusFirst(){this._focus(this.first)}focusLast(){this._focus(this.last)}focusNext(){this._focus(this.next)}focusPrevious(){this._focus(this.previous)}_focus(t){t&&t.focus()}_getFocusableItem(t){const e=this.current,i=this.focusables.length;if(!i)return null;if(null===e)return this[1===t?"first":"last"];let n=(e+i+t)%i;do{const e=this.focusables.get(n);if(wl(e))return e;n=(n+i+t)%i}while(n!==e);return null}}function wl(t){return!(!t.focus||"none"==ts.window.getComputedStyle(t.element).display)}class kl extends rl{constructor(t){super(t),this.setTemplate({tag:"span",attributes:{class:["ck","ck-toolbar__separator"]}})}}class _l{constructor(t,e){_l._observerInstance||_l._createObserver(),this._element=t,this._callback=e,_l._addElementCallback(t,e),_l._observerInstance.observe(t)}destroy(){_l._deleteElementCallback(this._element,this._callback)}static _addElementCallback(t,e){_l._elementCallbacks||(_l._elementCallbacks=new Map);let i=_l._elementCallbacks.get(t);i||(i=new Set,_l._elementCallbacks.set(t,i)),i.add(e)}static _deleteElementCallback(t,e){const i=_l._getElementCallbacks(t);i&&(i.delete(e),i.size||(_l._elementCallbacks.delete(t),_l._observerInstance.unobserve(t))),_l._elementCallbacks&&!_l._elementCallbacks.size&&(_l._observerInstance=null,_l._elementCallbacks=null)}static _getElementCallbacks(t){return _l._elementCallbacks?_l._elementCallbacks.get(t):null}static _createObserver(){let t;t="function"==typeof ts.window.ResizeObserver?ts.window.ResizeObserver:vl,_l._observerInstance=new t(t=>{for(const e of t){const t=_l._getElementCallbacks(e.target);if(t)for(const i of t)i(e)}})}}_l._observerInstance=null,_l._elementCallbacks=null;class vl{constructor(t){this._callback=t,this._elements=new Set,this._previousRects=new Map,this._periodicCheckTimeout=null}observe(t){this._elements.add(t),this._checkElementRectsAndExecuteCallback(),1===this._elements.size&&this._startPeriodicCheck()}unobserve(t){this._elements.delete(t),this._previousRects.delete(t),this._elements.size||this._stopPeriodicCheck()}_startPeriodicCheck(){const t=()=>{this._checkElementRectsAndExecuteCallback(),this._periodicCheckTimeout=setTimeout(t,100)};this.listenTo(ts.window,"resize",()=>{this._checkElementRectsAndExecuteCallback()}),this._periodicCheckTimeout=setTimeout(t,100)}_stopPeriodicCheck(){clearTimeout(this._periodicCheckTimeout),this.stopListening(),this._previousRects.clear()}_checkElementRectsAndExecuteCallback(){const t=[];for(const e of this._elements)this._hasRectChanged(e)&&t.push({target:e,contentRect:this._previousRects.get(e)});t.length&&this._callback(t)}_hasRectChanged(t){if(!t.ownerDocument.body.contains(t))return!1;const e=new Xs(t),i=this._previousRects.get(t),n=!i||!i.isEqual(e);return this._previousRects.set(t,e),n}}vi(vl,ls);class yl extends rl{constructor(t){super(t);const e=this.bindTemplate;this.set("isVisible",!1),this.set("position","se"),this.children=this.createCollection(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-reset","ck-dropdown__panel",e.to("position",t=>`ck-dropdown__panel_${t}`),e.if("isVisible","ck-dropdown__panel-visible")]},children:this.children,on:{selectstart:e.to(t=>t.preventDefault())}})}focus(){this.children.length&&this.children.first.focus()}focusLast(){if(this.children.length){const t=this.children.last;"function"==typeof t.focusLast?t.focusLast():t.focus()}}}i(24);function xl({element:t,target:e,positions:i,limiter:n,fitInViewport:o}){V(e)&&(e=e()),V(n)&&(n=n());const s=function(t){for(;t&&"html"!=t.tagName.toLowerCase();){if("static"!=ts.window.getComputedStyle(t).position)return t;t=t.parentElement}return null}(t.parentElement),r=new Xs(t),a=new Xs(e);let c,l;if(n||o){const t=n&&new Xs(n).getVisible(),e=o&&new Xs(ts.window);[l,c]=function(t,e,i,n,o){let s,r,a=0,c=0;const l=i.getArea();return t.some(t=>{const[d,h]=Al(t,e,i);let u,f;if(n)if(o){const t=n.getIntersection(o);u=t?t.getIntersectionArea(h):0}else u=n.getIntersectionArea(h);function m(){c=f,a=u,s=h,r=d}return o&&(f=o.getIntersectionArea(h)),o&&!n?f>c&&m():!o&&n?u>a&&m():(f>c&&u>=a||f>=c&&u>a)&&m(),u===l}),s?[r,s]:null}(i,a,r,t,e)||Al(i[0],a,r)}else[l,c]=Al(i[0],a,r);let{left:d,top:h}=Cl(c);if(s){const t=Cl(new Xs(s)),e=Js(s);d-=t.left,h-=t.top,d+=s.scrollLeft,h+=s.scrollTop,d-=e.left,h-=e.top}return{left:d,top:h,name:l}}function Al(t,e,i){const{left:n,top:o,name:s}=t(e,i);return[s,i.clone().moveTo(n,o)]}function Cl({left:t,top:e}){const{scrollX:i,scrollY:n}=ts.window;return{left:t+i,top:e+n}}class Tl extends rl{constructor(t,e,i){super(t);const n=this.bindTemplate;this.buttonView=e,this.panelView=i,this.set("isOpen",!1),this.set("isEnabled",!0),this.set("class"),this.set("id"),this.set("panelPosition","auto"),this.focusTracker=new Ic,this.keystrokes=new yc,this.setTemplate({tag:"div",attributes:{class:["ck","ck-dropdown",n.to("class"),n.if("isEnabled","ck-disabled",t=>!t)],id:n.to("id"),"aria-describedby":n.to("ariaDescribedById")},children:[e,i]}),e.extendTemplate({attributes:{class:["ck-dropdown__button"]}})}render(){super.render(),this.listenTo(this.buttonView,"open",()=>{this.isOpen=!this.isOpen}),this.panelView.bind("isVisible").to(this,"isOpen"),this.on("change:isOpen",()=>{this.isOpen&&("auto"===this.panelPosition?this.panelView.position=Tl._getOptimalPosition({element:this.panelView.element,target:this.buttonView.element,fitInViewport:!0,positions:this._panelPositions}).name:this.panelView.position=this.panelPosition)}),this.keystrokes.listenTo(this.element),this.focusTracker.add(this.element);const t=(t,e)=>{this.isOpen&&(this.buttonView.focus(),this.isOpen=!1,e())};this.keystrokes.set("arrowdown",(t,e)=>{this.buttonView.isEnabled&&!this.isOpen&&(this.isOpen=!0,e())}),this.keystrokes.set("arrowright",(t,e)=>{this.isOpen&&e()}),this.keystrokes.set("arrowleft",t),this.keystrokes.set("esc",t)}focus(){this.buttonView.focus()}get _panelPositions(){const{southEast:t,southWest:e,northEast:i,northWest:n}=Tl.defaultPanelPositions;return"ltr"===this.locale.uiLanguageDirection?[t,e,i,n]:[e,t,n,i]}}Tl.defaultPanelPositions={southEast:t=>({top:t.bottom,left:t.left,name:"se"}),southWest:(t,e)=>({top:t.bottom,left:t.left-e.width+t.width,name:"sw"}),northEast:(t,e)=>({top:t.top-e.height,left:t.left,name:"ne"}),northWest:(t,e)=>({top:t.bottom-e.height,left:t.left-e.width+t.width,name:"nw"})},Tl._getOptimalPosition=xl;i(26);class Pl extends rl{constructor(){super();const t=this.bindTemplate;this.set("content",""),this.set("viewBox","0 0 20 20"),this.set("fillColor",""),this.setTemplate({tag:"svg",ns:"http://www.w3.org/2000/svg",attributes:{class:["ck","ck-icon"],viewBox:t.to("viewBox")}})}render(){super.render(),this._updateXMLContent(),this._colorFillPaths(),this.on("change:content",()=>{this._updateXMLContent(),this._colorFillPaths()}),this.on("change:fillColor",()=>{this._colorFillPaths()})}_updateXMLContent(){if(this.content){const t=(new DOMParser).parseFromString(this.content.trim(),"image/svg+xml").querySelector("svg"),e=t.getAttribute("viewBox");for(e&&(this.viewBox=e),this.element.innerHTML="";t.childNodes.length>0;)this.element.appendChild(t.childNodes[0])}}_colorFillPaths(){this.fillColor&&this.element.querySelectorAll(".ck-icon__fill").forEach(t=>{t.style.fill=this.fillColor})}}i(28);class Sl extends rl{constructor(t){super(t),this.set("text",""),this.set("position","s");const e=this.bindTemplate;this.setTemplate({tag:"span",attributes:{class:["ck","ck-tooltip",e.to("position",t=>"ck-tooltip_"+t),e.if("text","ck-hidden",t=>!t.trim())]},children:[{tag:"span",attributes:{class:["ck","ck-tooltip__text"]},children:[{text:e.to("text")}]}]})}}i(30);class El extends rl{constructor(t){super(t);const e=this.bindTemplate,i=li();this.set("class"),this.set("labelStyle"),this.set("icon"),this.set("isEnabled",!0),this.set("isOn",!1),this.set("isVisible",!0),this.set("isToggleable",!1),this.set("keystroke"),this.set("label"),this.set("tabindex",-1),this.set("tooltip"),this.set("tooltipPosition","s"),this.set("type","button"),this.set("withText",!1),this.set("withKeystroke",!1),this.children=this.createCollection(),this.tooltipView=this._createTooltipView(),this.labelView=this._createLabelView(i),this.iconView=new Pl,this.iconView.extendTemplate({attributes:{class:"ck-button__icon"}}),this.keystrokeView=this._createKeystrokeView(),this.bind("_tooltipString").to(this,"tooltip",this,"label",this,"keystroke",this._getTooltipString.bind(this)),this.setTemplate({tag:"button",attributes:{class:["ck","ck-button",e.to("class"),e.if("isEnabled","ck-disabled",t=>!t),e.if("isVisible","ck-hidden",t=>!t),e.to("isOn",t=>t?"ck-on":"ck-off"),e.if("withText","ck-button_with-text"),e.if("withKeystroke","ck-button_with-keystroke")],type:e.to("type",t=>t||"button"),tabindex:e.to("tabindex"),"aria-labelledby":`ck-editor__aria-label_${i}`,"aria-disabled":e.if("isEnabled",!0,t=>!t),"aria-pressed":e.to("isOn",t=>!!this.isToggleable&&String(t))},children:this.children,on:{mousedown:e.to(t=>{t.preventDefault()}),click:e.to(t=>{this.isEnabled?this.fire("execute"):t.preventDefault()})}})}render(){super.render(),this.icon&&(this.iconView.bind("content").to(this,"icon"),this.children.add(this.iconView)),this.children.add(this.tooltipView),this.children.add(this.labelView),this.withKeystroke&&this.children.add(this.keystrokeView)}focus(){this.element.focus()}_createTooltipView(){const t=new Sl;return t.bind("text").to(this,"_tooltipString"),t.bind("position").to(this,"tooltipPosition"),t}_createLabelView(t){const e=new rl,i=this.bindTemplate;return e.setTemplate({tag:"span",attributes:{class:["ck","ck-button__label"],style:i.to("labelStyle"),id:`ck-editor__aria-label_${t}`},children:[{text:this.bindTemplate.to("label")}]}),e}_createKeystrokeView(){const t=new rl;return t.setTemplate({tag:"span",attributes:{class:["ck","ck-button__keystroke"]},children:[{text:this.bindTemplate.to("keystroke",t=>ko(t))}]}),t}_getTooltipString(t,e,i){return t?"string"==typeof t?t:(i&&(i=ko(i)),t instanceof Function?t(e,i):`${e}${i?` (${i})`:""}`):""}}class Ml extends El{constructor(t){super(t),this.arrowView=this._createArrowView(),this.extendTemplate({attributes:{"aria-haspopup":!0}}),this.delegate("execute").to(this,"open")}render(){super.render(),this.children.add(this.arrowView)}_createArrowView(){const t=new Pl;return t.content='<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"><path d="M.941 4.523a.75.75 0 111.06-1.06l3.006 3.005 3.005-3.005a.75.75 0 111.06 1.06l-3.549 3.55a.75.75 0 01-1.168-.136L.941 4.523z"/></svg>',t.extendTemplate({attributes:{class:"ck-dropdown__arrow"}}),t}}i(32);class Il extends rl{constructor(){super(),this.items=this.createCollection(),this.focusTracker=new Ic,this.keystrokes=new yc,this._focusCycler=new bl({focusables:this.items,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"arrowup",focusNext:"arrowdown"}}),this.setTemplate({tag:"ul",attributes:{class:["ck","ck-reset","ck-list"]},children:this.items})}render(){super.render();for(const t of this.items)this.focusTracker.add(t.element);this.items.on("add",(t,e)=>{this.focusTracker.add(e.element)}),this.items.on("remove",(t,e)=>{this.focusTracker.remove(e.element)}),this.keystrokes.listenTo(this.element)}focus(){this._focusCycler.focusFirst()}focusLast(){this._focusCycler.focusLast()}}class Nl extends rl{constructor(t){super(t),this.children=this.createCollection(),this.setTemplate({tag:"li",attributes:{class:["ck","ck-list__item"]},children:this.children})}focus(){this.children.first.focus()}}class Ol extends rl{constructor(t){super(t),this.setTemplate({tag:"li",attributes:{class:["ck","ck-list__separator"]}})}}i(34);class Rl extends El{constructor(t){super(t),this.isToggleable=!0,this.toggleSwitchView=this._createToggleView(),this.extendTemplate({attributes:{class:"ck-switchbutton"}})}render(){super.render(),this.children.add(this.toggleSwitchView)}_createToggleView(){const t=new rl;return t.setTemplate({tag:"span",attributes:{class:["ck","ck-button__toggle"]},children:[{tag:"span",attributes:{class:["ck","ck-button__toggle__inner"]}}]}),t}}function Ll({emitter:t,activator:e,callback:i,contextElements:n}){t.listenTo(document,"mousedown",(t,{target:o})=>{if(e()){for(const t of n)if(t.contains(o))return;i()}})}i(36),i(38);function Dl(t,e=Ml){const i=new e(t),n=new yl(t),o=new Tl(t,i,n);return i.bind("isEnabled").to(o),i instanceof Ml?i.bind("isOn").to(o,"isOpen"):i.arrowView.bind("isOn").to(o,"isOpen"),function(t){(function(t){t.on("render",()=>{Ll({emitter:t,activator:()=>t.isOpen,callback:()=>{t.isOpen=!1},contextElements:[t.element]})})})(t),function(t){t.on("execute",e=>{e.source instanceof Rl||(t.isOpen=!1)})}(t),function(t){t.keystrokes.set("arrowdown",(e,i)=>{t.isOpen&&(t.panelView.focus(),i())}),t.keystrokes.set("arrowup",(e,i)=>{t.isOpen&&(t.panelView.focusLast(),i())})}(t)}(o),o}function zl(t,e){const i=t.locale,n=i.t,o=t.toolbarView=new Vl(i);o.set("ariaLabel",n("ca")),t.extendTemplate({attributes:{class:["ck-toolbar-dropdown"]}}),e.map(t=>o.items.add(t)),t.panelView.children.add(o),o.items.delegate("execute").to(t)}function jl(t,e){const i=t.locale,n=t.listView=new Il(i);n.items.bindTo(e).using(({type:t,model:e})=>{if("separator"===t)return new Ol(i);if("button"===t||"switchbutton"===t){const n=new Nl(i);let o;return o="button"===t?new El(i):new Rl(i),o.bind(...Object.keys(e)).to(e),o.delegate("execute").to(n),n.children.add(o),n}}),t.panelView.children.add(n),n.items.delegate("execute").to(t)}i(40);class Vl extends rl{constructor(t,e){super(t);const i=this.bindTemplate,n=this.t;var o;this.options=e||{},this.set("ariaLabel",n("by")),this.items=this.createCollection(),this.focusTracker=new Ic,this.keystrokes=new yc,this.set("class"),this.set("isCompact",!1),this.itemsView=new Bl(t),this.children=this.createCollection(),this.children.add(this.itemsView),this.focusables=this.createCollection(),this._focusCycler=new bl({focusables:this.focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:["arrowleft","arrowup"],focusNext:["arrowright","arrowdown"]}}),this.setTemplate({tag:"div",attributes:{class:["ck","ck-toolbar",i.to("class"),i.if("isCompact","ck-toolbar_compact")],role:"toolbar","aria-label":i.to("ariaLabel")},children:this.children,on:{mousedown:(o=this,o.bindTemplate.to(t=>{t.target===o.element&&t.preventDefault()}))}}),this._behavior=this.options.shouldGroupWhenFull?new Hl(this):new Fl(this)}render(){super.render();for(const t of this.items)this.focusTracker.add(t.element);this.items.on("add",(t,e)=>{this.focusTracker.add(e.element)}),this.items.on("remove",(t,e)=>{this.focusTracker.remove(e.element)}),this.keystrokes.listenTo(this.element),this._behavior.render(this)}destroy(){return this._behavior.destroy(),super.destroy()}focus(){this._focusCycler.focusFirst()}focusLast(){this._focusCycler.focusLast()}fillFromConfig(t,e){t.map(t=>{"|"==t?this.items.add(new kl):e.has(t)?this.items.add(e.create(t)):console.warn(Object(hi.a)("toolbarview-item-unavailable: The requested toolbar item is unavailable."),{name:t})})}}class Bl extends rl{constructor(t){super(t),this.children=this.createCollection(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-toolbar__items"]},children:this.children})}}class Fl{constructor(t){const e=t.bindTemplate;t.set("isVertical",!1),t.itemsView.children.bindTo(t.items).using(t=>t),t.focusables.bindTo(t.items).using(t=>t),t.extendTemplate({attributes:{class:[e.if("isVertical","ck-toolbar_vertical")]}})}render(){}destroy(){}}class Hl{constructor(t){this.viewChildren=t.children,this.viewFocusables=t.focusables,this.viewItemsView=t.itemsView,this.viewFocusTracker=t.focusTracker,this.viewLocale=t.locale,this.ungroupedItems=t.createCollection(),this.groupedItems=t.createCollection(),this.groupedItemsDropdown=this._createGroupedItemsDropdown(),this.resizeObserver=null,this.cachedPadding=null,t.itemsView.children.bindTo(this.ungroupedItems).using(t=>t),this.ungroupedItems.on("add",this._updateFocusCycleableItems.bind(this)),this.ungroupedItems.on("remove",this._updateFocusCycleableItems.bind(this)),t.children.on("add",this._updateFocusCycleableItems.bind(this)),t.children.on("remove",this._updateFocusCycleableItems.bind(this)),t.items.on("add",(t,e,i)=>{i>this.ungroupedItems.length?this.groupedItems.add(e,i-this.ungroupedItems.length):this.ungroupedItems.add(e,i),this._updateGrouping()}),t.items.on("remove",(t,e,i)=>{i>this.ungroupedItems.length?this.groupedItems.remove(e):this.ungroupedItems.remove(e),this._updateGrouping()}),t.extendTemplate({attributes:{class:["ck-toolbar_grouping"]}})}render(t){this.viewElement=t.element,this._enableGroupingOnResize()}destroy(){this.groupedItemsDropdown.destroy(),this.resizeObserver.destroy()}_updateGrouping(){if(!this.viewElement.ownerDocument.body.contains(this.viewElement))return;let t;for(;this._areItemsOverflowing;)this._groupLastItem(),t=!0;if(!t&&this.groupedItems.length){for(;this.groupedItems.length&&!this._areItemsOverflowing;)this._ungroupFirstItem();this._areItemsOverflowing&&this._groupLastItem()}}get _areItemsOverflowing(){if(!this.ungroupedItems.length)return!1;const t=this.viewElement,e=this.viewLocale.uiLanguageDirection,i=new Xs(t.lastChild),n=new Xs(t);if(!this.cachedPadding){const i=ts.window.getComputedStyle(t),n="ltr"===e?"paddingRight":"paddingLeft";this.cachedPadding=Number.parseInt(i[n])}return"ltr"===e?i.right>n.right-this.cachedPadding:i.left<n.left+this.cachedPadding}_enableGroupingOnResize(){let t;this.resizeObserver=new _l(this.viewElement,e=>{t&&t===e.contentRect.width||(this._updateGrouping(),t=e.contentRect.width)}),this._updateGrouping()}_groupLastItem(){this.groupedItems.length||(this.viewChildren.add(new kl),this.viewChildren.add(this.groupedItemsDropdown),this.viewFocusTracker.add(this.groupedItemsDropdown.element)),this.groupedItems.add(this.ungroupedItems.remove(this.ungroupedItems.last),0)}_ungroupFirstItem(){this.ungroupedItems.add(this.groupedItems.remove(this.groupedItems.first)),this.groupedItems.length||(this.viewChildren.remove(this.groupedItemsDropdown),this.viewChildren.remove(this.viewChildren.last),this.viewFocusTracker.remove(this.groupedItemsDropdown.element))}_createGroupedItemsDropdown(){const t=this.viewLocale,e=t.t,i=Dl(t);return i.class="ck-toolbar__grouped-dropdown",i.panelPosition="ltr"===t.uiLanguageDirection?"sw":"se",zl(i,[]),i.buttonView.set({label:e("bz"),tooltip:!0,icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="9.5" cy="4.5" r="1.5"/><circle cx="9.5" cy="10.5" r="1.5"/><circle cx="9.5" cy="16.5" r="1.5"/></svg>'}),i.toolbarView.items.bindTo(this.groupedItems).using(t=>t),i}_updateFocusCycleableItems(){this.viewFocusables.clear(),this.ungroupedItems.map(t=>{this.viewFocusables.add(t)}),this.groupedItems.length&&this.viewFocusables.add(this.groupedItemsDropdown)}}i(42);class Ul extends hl{constructor(t,e,i={}){super(t),this.stickyPanel=new pl(t),this.toolbar=new Vl(t,{shouldGroupWhenFull:i.shouldToolbarGroupWhenFull}),this.editable=new fl(t,e)}render(){super.render(),this.stickyPanel.content.add(this.toolbar),this.top.add(this.stickyPanel),this.main.add(this.editable)}}class Wl extends Ac{constructor(t,e){super(e),ii(t)&&(this.sourceElement=t),this.data.processor=new Sc,this.model.document.createRoot();const i=!this.config.get("toolbar.shouldNotGroupWhenFull"),n=new Ul(this.locale,this.editing.view,{shouldToolbarGroupWhenFull:i});this.ui=new Vc(this,n),function(t){if(!V(t.updateSourceElement))throw new hi.b("attachtoform-missing-elementapi-interface: Editor passed to attachToForm() must implement ElementApi.",t);const e=t.sourceElement;if(e&&"textarea"===e.tagName.toLowerCase()&&e.form){let i;const n=e.form,o=()=>t.updateSourceElement();V(n.submit)&&(i=n.submit,n.submit=()=>{o(),i.apply(n)}),n.addEventListener("submit",o),t.on("destroy",()=>{n.removeEventListener("submit",o),i&&(n.submit=i)})}}(this)}destroy(){return this.sourceElement&&this.updateSourceElement(),this.ui.destroy(),super.destroy()}static create(t,e={}){return new Promise(i=>{const n=new this(t,e);i(n.initPlugins().then(()=>n.ui.init(ii(t)?t:null)).then(()=>{if(!ii(t)&&e.initialData)throw new hi.b("editor-create-initial-data: The config.initialData option cannot be used together with initial data passed in Editor.create().",null);const i=e.initialData||function(t){return ii(t)?(e=t,e instanceof HTMLTextAreaElement?e.value:e.innerHTML):t;var e}(t);return n.data.init(i)}).then(()=>n.fire("ready")).then(()=>n))})}}vi(Wl,Cc),vi(Wl,Tc);class ql{constructor(t){this.editor=t,this.set("isEnabled",!0),this._disableStack=new Set}forceDisabled(t){this._disableStack.add(t),1==this._disableStack.size&&(this.on("set:isEnabled",$l,{priority:"highest"}),this.isEnabled=!1)}clearForceDisabled(t){this._disableStack.delete(t),0==this._disableStack.size&&(this.off("set:isEnabled",$l),this.isEnabled=!0)}destroy(){this.stopListening()}static get isContextPlugin(){return!1}}function $l(t){t.return=!1,t.stop()}vi(ql,Hn);class Yl{constructor(t){this.files=function(t){const e=t.files?Array.from(t.files):[],i=t.items?Array.from(t.items):[];if(e.length)return e;return i.filter(t=>"file"===t.kind).map(t=>t.getAsFile())}(t),this._native=t}get types(){return this._native.types}getData(t){return this._native.getData(t)}setData(t,e){this._native.setData(t,e)}}class Gl extends Os{constructor(t){super(t);const e=this.document;function i(t,i){i.preventDefault();const n=i.dropRange?[i.dropRange]:Array.from(e.selection.getRanges()),o=new ai(e,"clipboardInput");e.fire(o,{dataTransfer:i.dataTransfer,targetRanges:n}),o.stop.called&&i.stopPropagation()}this.domEventType=["paste","copy","cut","drop","dragover"],this.listenTo(e,"paste",i,{priority:"low"}),this.listenTo(e,"drop",i,{priority:"low"})}onDomEvent(t){const e={dataTransfer:new Yl(t.clipboardData?t.clipboardData:t.dataTransfer)};"drop"==t.type&&(e.dropRange=function(t,e){const i=e.target.ownerDocument,n=e.clientX,o=e.clientY;let s;i.caretRangeFromPoint&&i.caretRangeFromPoint(n,o)?s=i.caretRangeFromPoint(n,o):e.rangeParent&&(s=i.createRange(),s.setStart(e.rangeParent,e.rangeOffset),s.collapse(!0));return s?t.domConverter.domRangeToView(s):t.document.selection.getFirstRange()}(this.view,t)),this.fire(t.type,t,e)}}const Ql=["figcaption","li"];class Kl extends ql{static get pluginName(){return"Clipboard"}init(){const t=this.editor,e=t.model.document,i=t.editing.view,n=i.document;function o(i,o){const s=o.dataTransfer;o.preventDefault();const r=t.data.toView(t.model.getSelectedContent(e.selection));n.fire("clipboardOutput",{dataTransfer:s,content:r,method:i.name})}this._htmlDataProcessor=new Sc,i.addObserver(Gl),this.listenTo(n,"clipboardInput",e=>{t.isReadOnly&&e.stop()},{priority:"highest"}),this.listenTo(n,"clipboardInput",(t,e)=>{const n=e.dataTransfer;let o="";var s;n.getData("text/html")?o=function(t){return t.replace(/<span(?: class="Apple-converted-space"|)>(\s+)<\/span>/g,(t,e)=>1==e.length?" ":e)}(n.getData("text/html")):n.getData("text/plain")&&((s=(s=n.getData("text/plain")).replace(/</g,"<").replace(/>/g,">").replace(/\n/g,"</p><p>").replace(/^\s/," ").replace(/\s$/," ").replace(/\s\s/g," ")).indexOf("</p><p>")>-1&&(s=`<p>${s}</p>`),o=s),o=this._htmlDataProcessor.toView(o),this.fire("inputTransformation",{content:o,dataTransfer:n}),i.scrollToTheSelection()},{priority:"low"}),this.listenTo(this,"inputTransformation",(t,e)=>{if(!e.content.isEmpty){const t=this.editor.data,i=this.editor.model,n=t.toModel(e.content,"$clipboardHolder");if(0==n.childCount)return;i.insertContent(n)}},{priority:"low"}),this.listenTo(n,"copy",o,{priority:"low"}),this.listenTo(n,"cut",(e,i)=>{t.isReadOnly?i.preventDefault():o(e,i)},{priority:"low"}),this.listenTo(n,"clipboardOutput",(i,n)=>{n.content.isEmpty||(n.dataTransfer.setData("text/html",this._htmlDataProcessor.toData(n.content)),n.dataTransfer.setData("text/plain",function t(e){let i="";if(e.is("text")||e.is("textProxy"))i=e.data;else if(e.is("img")&&e.hasAttribute("alt"))i=e.getAttribute("alt");else{let n=null;for(const o of e.getChildren()){const e=t(o);n&&(n.is("containerElement")||o.is("containerElement"))&&(Ql.includes(n.name)||Ql.includes(o.name)?i+="\n":i+="\n\n"),i+=e,n=o}}return i}(n.content))),"cut"==n.method&&t.model.deleteContent(e.selection)},{priority:"low"})}}class Jl{constructor(t){this.editor=t,this.set("value",void 0),this.set("isEnabled",!1),this._disableStack=new Set,this.decorate("execute"),this.listenTo(this.editor.model.document,"change",()=>{this.refresh()}),this.on("execute",t=>{this.isEnabled||t.stop()},{priority:"high"}),this.listenTo(t,"change:isReadOnly",(t,e,i)=>{i?this.forceDisabled("readOnlyMode"):this.clearForceDisabled("readOnlyMode")})}refresh(){this.isEnabled=!0}forceDisabled(t){this._disableStack.add(t),1==this._disableStack.size&&(this.on("set:isEnabled",Zl,{priority:"highest"}),this.isEnabled=!1)}clearForceDisabled(t){this._disableStack.delete(t),0==this._disableStack.size&&(this.off("set:isEnabled",Zl),this.refresh())}execute(){}destroy(){this.stopListening()}}function Zl(t){t.return=!1,t.stop()}function*Xl(t,e){for(const i of e)i&&t.getAttributeProperties(i[0]).copyOnEnter&&(yield i)}vi(Jl,Hn);class td extends Jl{execute(){const t=this.editor.model,e=t.document;t.change(i=>{!function(t,e,i,n){const o=i.isCollapsed,s=i.getFirstRange(),r=s.start.parent,a=s.end.parent;if(n.isLimit(r)||n.isLimit(a))return void(o||r!=a||t.deleteContent(i));if(o){const t=Xl(e.model.schema,i.getAttributes());ed(e,s.start),e.setSelectionAttribute(t)}else{const n=!(s.start.isAtStart&&s.end.isAtEnd),o=r==a;t.deleteContent(i,{leaveUnmerged:n}),n&&(o?ed(e,i.focus):e.setSelection(a,0))}}(this.editor.model,i,e.selection,t.schema),this.fire("afterExecute",{writer:i})})}}function ed(t,e){t.split(e),t.setSelection(e.parent.nextSibling,0)}class id extends us{constructor(t){super(t);const e=this.document;e.on("keydown",(t,i)=>{if(this.isEnabled&&i.keyCode==po.enter){let n;e.once("enter",t=>n=t,{priority:"highest"}),e.fire("enter",new Ns(e,i.domEvent,{isSoft:i.shiftKey})),n&&n.stop.called&&t.stop()}})}observe(){}}class nd extends ql{static get pluginName(){return"Enter"}init(){const t=this.editor,e=t.editing.view,i=e.document;e.addObserver(id),t.commands.add("enter",new td(t)),this.listenTo(i,"enter",(i,n)=>{n.preventDefault(),n.isSoft||(t.execute("enter"),e.scrollToTheSelection())},{priority:"low"})}}class od extends Jl{execute(){const t=this.editor.model,e=t.document;t.change(i=>{!function(t,e,i){const n=i.isCollapsed,o=i.getFirstRange(),s=o.start.parent,r=o.end.parent,a=s==r;if(n){const n=Xl(t.schema,i.getAttributes());sd(t,e,o.end),e.removeSelectionAttribute(i.getAttributeKeys()),e.setSelectionAttribute(n)}else{const n=!(o.start.isAtStart&&o.end.isAtEnd);t.deleteContent(i,{leaveUnmerged:n}),a?sd(t,e,i.focus):n&&e.setSelection(r,0)}}(t,i,e.selection),this.fire("afterExecute",{writer:i})})}refresh(){const t=this.editor.model,e=t.document;this.isEnabled=function(t,e){if(e.rangeCount>1)return!1;const i=e.anchor;if(!i||!t.checkChild(i,"softBreak"))return!1;const n=e.getFirstRange(),o=n.start.parent,s=n.end.parent;if((rd(o,t)||rd(s,t))&&o!==s)return!1;return!0}(t.schema,e.selection)}}function sd(t,e,i){const n=e.createElement("softBreak");t.insertContent(n,i),e.setSelection(n,"after")}function rd(t,e){return!t.is("rootElement")&&(e.isLimit(t)||rd(t.parent,e))}class ad extends ql{static get pluginName(){return"ShiftEnter"}init(){const t=this.editor,e=t.model.schema,i=t.conversion,n=t.editing.view,o=n.document;e.register("softBreak",{allowWhere:"$text",isInline:!0}),i.for("upcast").elementToElement({model:"softBreak",view:"br"}),i.for("downcast").elementToElement({model:"softBreak",view:(t,e)=>e.createEmptyElement("br")}),n.addObserver(id),t.commands.add("shiftEnter",new od(t)),this.listenTo(o,"enter",(e,i)=>{i.preventDefault(),i.isSoft&&(t.execute("shiftEnter"),n.scrollToTheSelection())},{priority:"low"})}}class cd{constructor(t,e=20){this.model=t,this.size=0,this.limit=e,this.isLocked=!1,this._changeCallback=(t,e)=>{"transparent"!=e.type&&e!==this._batch&&this._reset(!0)},this._selectionChangeCallback=()=>{this._reset()},this.model.document.on("change",this._changeCallback),this.model.document.selection.on("change:range",this._selectionChangeCallback),this.model.document.selection.on("change:attribute",this._selectionChangeCallback)}get batch(){return this._batch||(this._batch=this.model.createBatch()),this._batch}input(t){this.size+=t,this.size>=this.limit&&this._reset(!0)}lock(){this.isLocked=!0}unlock(){this.isLocked=!1}destroy(){this.model.document.off("change",this._changeCallback),this.model.document.selection.off("change:range",this._selectionChangeCallback),this.model.document.selection.off("change:attribute",this._selectionChangeCallback)}_reset(t){this.isLocked&&!t||(this._batch=null,this.size=0)}}class ld extends Jl{constructor(t,e){super(t),this._buffer=new cd(t.model,e),this._batches=new WeakSet}get buffer(){return this._buffer}destroy(){super.destroy(),this._buffer.destroy()}execute(t={}){const e=this.editor.model,i=e.document,n=t.text||"",o=n.length,s=t.range||i.selection.getFirstRange(),r=t.resultRange;e.enqueueChange(this._buffer.batch,t=>{const a=s.isCollapsed;this._buffer.lock(),e.deleteContent(e.createSelection(s)),n&&e.insertContent(t.createText(n,i.selection.getAttributes()),s.start),r?t.setSelection(r):a&&t.setSelection(s.start.getShiftedBy(o)),this._buffer.unlock(),this._buffer.input(o),this._batches.add(this._buffer.batch)})}}function dd(t){let e=null;const i=t.model,n=t.editing.view,o=t.commands.get("input");function s(t){const s=i.document,a=n.document.isComposing,c=e&&e.isEqual(s.selection);e=null,o.isEnabled&&(function(t){if(t.ctrlKey)return!0;return hd.includes(t.keyCode)}(t)||s.selection.isCollapsed||a&&229===t.keyCode||!a&&229===t.keyCode&&c||r())}function r(){const t=o.buffer;t.lock(),i.enqueueChange(t.batch,()=>{i.deleteContent(i.document.selection)}),t.unlock()}fo.isAndroid?n.document.on("beforeinput",(t,e)=>s(e),{priority:"lowest"}):n.document.on("keydown",(t,e)=>s(e),{priority:"lowest"}),n.document.on("compositionstart",(function(){const t=i.document,e=1!==t.selection.rangeCount||t.selection.getFirstRange().isFlat;if(t.selection.isCollapsed||e)return;r()}),{priority:"lowest"}),n.document.on("compositionend",()=>{e=i.createSelection(i.document.selection)},{priority:"lowest"})}const hd=[bo("arrowUp"),bo("arrowRight"),bo("arrowDown"),bo("arrowLeft"),9,16,17,18,19,20,27,33,34,35,36,45,91,93,144,145,173,174,175,176,177,178,179,255];for(let t=112;t<=135;t++)hd.push(t);function ud(t){if(t.newChildren.length-t.oldChildren.length!=1)return;const e=function(t,e){const i=[];let n,o=0;return t.forEach(t=>{"equal"==t?(s(),o++):"insert"==t?(r("insert")?n.values.push(e[o]):(s(),n={type:"insert",index:o,values:[e[o]]}),o++):r("delete")?n.howMany++:(s(),n={type:"delete",index:o,howMany:1})}),s(),i;function s(){n&&(i.push(n),n=null)}function r(t){return n&&n.type==t}}($o(t.oldChildren,t.newChildren,fd),t.newChildren);if(e.length>1)return;const i=e[0];return i.values[0]&&i.values[0].is("text")?i:void 0}function fd(t,e){return t&&t.is("text")&&e&&e.is("text")?t.data===e.data:t===e}class md{constructor(t){this.editor=t,this.editing=this.editor.editing}handle(t,e){if(function(t){if(0==t.length)return!1;for(const e of t)if("children"===e.type&&!ud(e))return!0;return!1}(t))this._handleContainerChildrenMutations(t,e);else for(const i of t)this._handleTextMutation(i,e),this._handleTextNodeInsertion(i)}_handleContainerChildrenMutations(t,e){const i=function(t){const e=t.map(t=>t.node).reduce((t,e)=>t.getCommonAncestor(e,{includeSelf:!0}));if(!e)return;return e.getAncestors({includeSelf:!0,parentFirst:!0}).find(t=>t.is("containerElement")||t.is("rootElement"))}(t);if(!i)return;const n=this.editor.editing.view.domConverter.mapViewToDom(i),o=new os,s=this.editor.data.toModel(o.domToView(n)).getChild(0),r=this.editor.editing.mapper.toModelElement(i);if(!r)return;const a=Array.from(s.getChildren()),c=Array.from(r.getChildren()),l=a[a.length-1],d=c[c.length-1];l&&l.is("softBreak")&&d&&!d.is("softBreak")&&a.pop();const h=this.editor.model.schema;if(!gd(a,h)||!gd(c,h))return;const u=a.map(t=>t.is("text")?t.data:"@").join("").replace(/\u00A0/g," "),f=c.map(t=>t.is("text")?t.data:"@").join("").replace(/\u00A0/g," ");if(f===u)return;const m=$o(f,u),{firstChangeAt:g,insertions:p,deletions:b}=pd(m);let w=null;e&&(w=this.editing.mapper.toModelRange(e.getFirstRange()));const k=u.substr(g,p),_=this.editor.model.createRange(this.editor.model.createPositionAt(r,g),this.editor.model.createPositionAt(r,g+b));this.editor.execute("input",{text:k,range:_,resultRange:w})}_handleTextMutation(t,e){if("text"!=t.type)return;const i=t.newText.replace(/\u00A0/g," "),n=t.oldText.replace(/\u00A0/g," ");if(n===i)return;const o=$o(n,i),{firstChangeAt:s,insertions:r,deletions:a}=pd(o);let c=null;e&&(c=this.editing.mapper.toModelRange(e.getFirstRange()));const l=this.editing.view.createPositionAt(t.node,s),d=this.editing.mapper.toModelPosition(l),h=this.editor.model.createRange(d,d.getShiftedBy(a)),u=i.substr(s,r);this.editor.execute("input",{text:u,range:h,resultRange:c})}_handleTextNodeInsertion(t){if("children"!=t.type)return;const e=ud(t),i=this.editing.view.createPositionAt(t.node,e.index),n=this.editing.mapper.toModelPosition(i),o=e.values[0].data;this.editor.execute("input",{text:o.replace(/\u00A0/g," "),range:this.editor.model.createRange(n)})}}function gd(t,e){return t.every(t=>e.isInline(t))}function pd(t){let e=null,i=null;for(let n=0;n<t.length;n++){"equal"!=t[n]&&(e=null===e?n:e,i=n)}let n=0,o=0;for(let s=e;s<=i;s++)"insert"!=t[s]&&n++,"delete"!=t[s]&&o++;return{insertions:o,deletions:n,firstChangeAt:e}}class bd extends ql{static get pluginName(){return"Input"}init(){const t=this.editor,e=new ld(t,t.config.get("typing.undoStep")||20);t.commands.add("input",e),dd(t),function(t){t.editing.view.document.on("mutations",(e,i,n)=>{new md(t).handle(i,n)})}(t)}isInput(t){return this.editor.commands.get("input")._batches.has(t)}}class wd extends Jl{constructor(t,e){super(t),this.direction=e,this._buffer=new cd(t.model,t.config.get("typing.undoStep"))}get buffer(){return this._buffer}execute(t={}){const e=this.editor.model,i=e.document;e.enqueueChange(this._buffer.batch,n=>{this._buffer.lock();const o=n.createSelection(t.selection||i.selection),s=o.isCollapsed;if(o.isCollapsed&&e.modifySelection(o,{direction:this.direction,unit:t.unit}),this._shouldEntireContentBeReplacedWithParagraph(t.sequence||1))return void this._replaceEntireContentWithParagraph(n);if(o.isCollapsed)return;let r=0;o.getFirstRange().getMinimalFlatRanges().forEach(t=>{r+=io(t.getWalker({singleCharacters:!0,ignoreElementEnd:!0,shallow:!0}))}),e.deleteContent(o,{doNotResetEntireContent:s}),this._buffer.input(r),n.setSelection(o),this._buffer.unlock()})}_shouldEntireContentBeReplacedWithParagraph(t){if(t>1)return!1;const e=this.editor.model,i=e.document.selection,n=e.schema.getLimitElement(i);if(!(i.isCollapsed&&i.containsEntireContent(n)))return!1;if(!e.schema.checkChild(n,"paragraph"))return!1;const o=n.getChild(0);return!o||"paragraph"!==o.name}_replaceEntireContentWithParagraph(t){const e=this.editor.model,i=e.document.selection,n=e.schema.getLimitElement(i),o=t.createElement("paragraph");t.remove(t.createRangeIn(n)),t.insert(o,n),t.setSelection(o,0)}}class kd extends us{constructor(t){super(t);const e=t.document;let i=0;function n(t,i,n){let o;e.once("delete",t=>o=t,{priority:Number.POSITIVE_INFINITY}),e.fire("delete",new Ns(e,i,n)),o&&o.stop.called&&t.stop()}e.on("keyup",(t,e)=>{e.keyCode!=po.delete&&e.keyCode!=po.backspace||(i=0)}),e.on("keydown",(t,e)=>{const o={};if(e.keyCode==po.delete)o.direction="forward",o.unit="character";else{if(e.keyCode!=po.backspace)return;o.direction="backward",o.unit="codePoint"}const s=fo.isMac?e.altKey:e.ctrlKey;o.unit=s?"word":o.unit,o.sequence=++i,n(t,e.domEvent,o)}),fo.isAndroid&&e.on("beforeinput",(e,i)=>{if("deleteContentBackward"!=i.domEvent.inputType)return;const o={unit:"codepoint",direction:"backward",sequence:1},s=i.domTarget.ownerDocument.defaultView.getSelection();s.anchorNode==s.focusNode&&s.anchorOffset+1!=s.focusOffset&&(o.selectionToRemove=t.domConverter.domSelectionToView(s)),n(e,i.domEvent,o)})}observe(){}}class _d extends ql{static get pluginName(){return"Delete"}init(){const t=this.editor,e=t.editing.view,i=e.document;if(e.addObserver(kd),t.commands.add("forwardDelete",new wd(t,"forward")),t.commands.add("delete",new wd(t,"backward")),this.listenTo(i,"delete",(i,n)=>{const o={unit:n.unit,sequence:n.sequence};if(n.selectionToRemove){const e=t.model.createSelection(),i=[];for(const e of n.selectionToRemove.getRanges())i.push(t.editing.mapper.toModelRange(e));e.setTo(i),o.selection=e}t.execute("forward"==n.direction?"forwardDelete":"delete",o),n.preventDefault(),e.scrollToTheSelection()}),fo.isAndroid){let t=null;this.listenTo(i,"delete",(e,i)=>{const n=i.domTarget.ownerDocument.defaultView.getSelection();t={anchorNode:n.anchorNode,anchorOffset:n.anchorOffset,focusNode:n.focusNode,focusOffset:n.focusOffset}},{priority:"lowest"}),this.listenTo(i,"keyup",(e,i)=>{if(t){const e=i.domTarget.ownerDocument.defaultView.getSelection();e.collapse(t.anchorNode,t.anchorOffset),e.extend(t.focusNode,t.focusOffset),t=null}})}}}class vd extends ql{static get requires(){return[bd,_d]}static get pluginName(){return"Typing"}}const yd=new Map;function xd(t,e,i){let n=yd.get(t);n||(n=new Map,yd.set(t,n)),n.set(e,i)}function Ad(t){return[t]}function Cd(t,e,i={}){const n=function(t,e){const i=yd.get(t);return i&&i.has(e)?i.get(e):Ad}(t.constructor,e.constructor);try{return n(t=t.clone(),e,i)}catch(t){throw t}}function Td(t,e,i){t=t.slice(),e=e.slice();const n=new Pd(i.document,i.useRelations,i.forceWeakRemove);n.setOriginalOperations(t),n.setOriginalOperations(e);const o=n.originalOperations;if(0==t.length||0==e.length)return{operationsA:t,operationsB:e,originalOperations:o};const s=new WeakMap;for(const e of t)s.set(e,0);const r={nextBaseVersionA:t[t.length-1].baseVersion+1,nextBaseVersionB:e[e.length-1].baseVersion+1,originalOperationsACount:t.length,originalOperationsBCount:e.length};let a=0;for(;a<t.length;){const i=t[a],o=s.get(i);if(o==e.length){a++;continue}const r=e[o],c=Cd(i,r,n.getContext(i,r,!0)),l=Cd(r,i,n.getContext(r,i,!1));n.updateRelation(i,r),n.setOriginalOperations(c,i),n.setOriginalOperations(l,r);for(const t of c)s.set(t,o+l.length);t.splice(a,1,...c),e.splice(o,1,...l)}if(i.padWithNoOps){const i=t.length-r.originalOperationsACount,n=e.length-r.originalOperationsBCount;Ed(t,n-i),Ed(e,i-n)}return Sd(t,r.nextBaseVersionB),Sd(e,r.nextBaseVersionA),{operationsA:t,operationsB:e,originalOperations:o}}class Pd{constructor(t,e,i=!1){this.originalOperations=new Map,this._history=t.history,this._useRelations=e,this._forceWeakRemove=!!i,this._relations=new Map}setOriginalOperations(t,e=null){const i=e?this.originalOperations.get(e):null;for(const e of t)this.originalOperations.set(e,i||e)}updateRelation(t,e){switch(t.constructor){case Na:switch(e.constructor){case za:t.targetPosition.isEqual(e.sourcePosition)||e.movedRange.containsPosition(t.targetPosition)?this._setRelation(t,e,"insertAtSource"):t.targetPosition.isEqual(e.deletionPosition)?this._setRelation(t,e,"insertBetween"):t.targetPosition.isAfter(e.sourcePosition)&&this._setRelation(t,e,"moveTargetAfter");break;case Na:t.targetPosition.isEqual(e.sourcePosition)||t.targetPosition.isBefore(e.sourcePosition)?this._setRelation(t,e,"insertBefore"):this._setRelation(t,e,"insertAfter")}break;case ja:switch(e.constructor){case za:t.splitPosition.isBefore(e.sourcePosition)&&this._setRelation(t,e,"splitBefore");break;case Na:(t.splitPosition.isEqual(e.sourcePosition)||t.splitPosition.isBefore(e.sourcePosition))&&this._setRelation(t,e,"splitBefore")}break;case za:switch(e.constructor){case za:t.targetPosition.isEqual(e.sourcePosition)||this._setRelation(t,e,"mergeTargetNotMoved"),t.sourcePosition.isEqual(e.targetPosition)&&this._setRelation(t,e,"mergeSourceNotMoved"),t.sourcePosition.isEqual(e.sourcePosition)&&this._setRelation(t,e,"mergeSameElement");break;case ja:t.sourcePosition.isEqual(e.splitPosition)&&this._setRelation(t,e,"splitAtSource")}break;case Ra:{const i=t.newRange;if(!i)return;switch(e.constructor){case Na:{const n=vr._createFromPositionAndShift(e.sourcePosition,e.howMany),o=n.containsPosition(i.start)||n.start.isEqual(i.start),s=n.containsPosition(i.end)||n.end.isEqual(i.end);!o&&!s||n.containsRange(i)||this._setRelation(t,e,{side:o?"left":"right",path:o?i.start.path.slice():i.end.path.slice()});break}case za:{const n=i.start.isEqual(e.targetPosition),o=i.start.isEqual(e.deletionPosition),s=i.end.isEqual(e.deletionPosition),r=i.end.isEqual(e.sourcePosition);(n||o||s||r)&&this._setRelation(t,e,{wasInLeftElement:n,wasStartBeforeMergedElement:o,wasEndBeforeMergedElement:s,wasInRightElement:r});break}}break}}}getContext(t,e,i){return{aIsStrong:i,aWasUndone:this._wasUndone(t),bWasUndone:this._wasUndone(e),abRelation:this._useRelations?this._getRelation(t,e):null,baRelation:this._useRelations?this._getRelation(e,t):null,forceWeakRemove:this._forceWeakRemove}}_wasUndone(t){const e=this.originalOperations.get(t);return e.wasUndone||this._history.isUndoneOperation(e)}_getRelation(t,e){const i=this.originalOperations.get(e),n=this._history.getUndoneOperation(i);if(!n)return null;const o=this.originalOperations.get(t),s=this._relations.get(o);return s&&s.get(n)||null}_setRelation(t,e,i){const n=this.originalOperations.get(t),o=this.originalOperations.get(e);let s=this._relations.get(n);s||(s=new Map,this._relations.set(n,s)),s.set(o,i)}}function Sd(t,e){for(const i of t)i.baseVersion=e++}function Ed(t,e){for(let i=0;i<e;i++)t.push(new nc(0))}function Md(t,e,i){const n=t.nodes.getNode(0).getAttribute(e);if(n==i)return null;const o=new vr(t.position,t.position.getShiftedBy(t.howMany));return new Ma(o,e,n,i,0)}function Id(t,e){return null===t.targetPosition._getTransformedByDeletion(e.sourcePosition,e.howMany)}function Nd(t,e){const i=[];for(let n=0;n<t.length;n++){const o=t[n],s=new Na(o.start,o.end.offset-o.start.offset,e,0);i.push(s);for(let e=n+1;e<t.length;e++)t[e]=t[e]._getTransformedByMove(s.sourcePosition,s.targetPosition,s.howMany)[0];e=e._getTransformedByMove(s.sourcePosition,s.targetPosition,s.howMany)}return i}xd(Ma,Ma,(t,e,i)=>{if(t.key===e.key){const n=t.range.getDifference(e.range).map(e=>new Ma(e,t.key,t.oldValue,t.newValue,0)),o=t.range.getIntersection(e.range);return o&&i.aIsStrong&&n.push(new Ma(o,e.key,e.newValue,t.newValue,0)),0==n.length?[new nc(0)]:n}return[t]}),xd(Ma,Oa,(t,e)=>{if(t.range.start.hasSameParentAs(e.position)&&t.range.containsPosition(e.position)){const i=t.range._getTransformedByInsertion(e.position,e.howMany,!e.shouldReceiveAttributes).map(e=>new Ma(e,t.key,t.oldValue,t.newValue,t.baseVersion));if(e.shouldReceiveAttributes){const n=Md(e,t.key,t.oldValue);n&&i.unshift(n)}return i}return t.range=t.range._getTransformedByInsertion(e.position,e.howMany,!1)[0],[t]}),xd(Ma,za,(t,e)=>{const i=[];t.range.start.hasSameParentAs(e.deletionPosition)&&(t.range.containsPosition(e.deletionPosition)||t.range.start.isEqual(e.deletionPosition))&&i.push(vr._createFromPositionAndShift(e.graveyardPosition,1));const n=t.range._getTransformedByMergeOperation(e);return n.isCollapsed||i.push(n),i.map(e=>new Ma(e,t.key,t.oldValue,t.newValue,t.baseVersion))}),xd(Ma,Na,(t,e)=>function(t,e){const i=vr._createFromPositionAndShift(e.sourcePosition,e.howMany);let n=null,o=[];i.containsRange(t,!0)?n=t:t.start.hasSameParentAs(i.start)?(o=t.getDifference(i),n=t.getIntersection(i)):o=[t];const s=[];for(let t of o){t=t._getTransformedByDeletion(e.sourcePosition,e.howMany);const i=e.getMovedRangeStart(),n=t.start.hasSameParentAs(i);t=t._getTransformedByInsertion(i,e.howMany,n),s.push(...t)}n&&s.push(n._getTransformedByMove(e.sourcePosition,e.targetPosition,e.howMany,!1)[0]);return s}(t.range,e).map(e=>new Ma(e,t.key,t.oldValue,t.newValue,t.baseVersion))),xd(Ma,ja,(t,e)=>{if(t.range.end.isEqual(e.insertionPosition))return e.graveyardPosition||t.range.end.offset++,[t];if(t.range.start.hasSameParentAs(e.splitPosition)&&t.range.containsPosition(e.splitPosition)){const i=t.clone();return i.range=new vr(e.moveTargetPosition.clone(),t.range.end._getCombined(e.splitPosition,e.moveTargetPosition)),t.range.end=e.splitPosition.clone(),t.range.end.stickiness="toPrevious",[t,i]}return t.range=t.range._getTransformedBySplitOperation(e),[t]}),xd(Oa,Ma,(t,e)=>{const i=[t];if(t.shouldReceiveAttributes&&t.position.hasSameParentAs(e.range.start)&&e.range.containsPosition(t.position)){const n=Md(t,e.key,e.newValue);n&&i.push(n)}return i}),xd(Oa,Oa,(t,e,i)=>(t.position.isEqual(e.position)&&i.aIsStrong||(t.position=t.position._getTransformedByInsertOperation(e)),[t])),xd(Oa,Na,(t,e)=>(t.position=t.position._getTransformedByMoveOperation(e),[t])),xd(Oa,ja,(t,e)=>(t.position=t.position._getTransformedBySplitOperation(e),[t])),xd(Oa,za,(t,e)=>(t.position=t.position._getTransformedByMergeOperation(e),[t])),xd(Ra,Oa,(t,e)=>(t.oldRange&&(t.oldRange=t.oldRange._getTransformedByInsertOperation(e)[0]),t.newRange&&(t.newRange=t.newRange._getTransformedByInsertOperation(e)[0]),[t])),xd(Ra,Ra,(t,e,i)=>{if(t.name==e.name){if(!i.aIsStrong)return[new nc(0)];t.oldRange=e.newRange?e.newRange.clone():null}return[t]}),xd(Ra,za,(t,e)=>(t.oldRange&&(t.oldRange=t.oldRange._getTransformedByMergeOperation(e)),t.newRange&&(t.newRange=t.newRange._getTransformedByMergeOperation(e)),[t])),xd(Ra,Na,(t,e,i)=>{if(t.oldRange&&(t.oldRange=vr._createFromRanges(t.oldRange._getTransformedByMoveOperation(e))),t.newRange){if(i.abRelation){const n=vr._createFromRanges(t.newRange._getTransformedByMoveOperation(e));if("left"==i.abRelation.side&&e.targetPosition.isEqual(t.newRange.start))return t.newRange.start.path=i.abRelation.path,t.newRange.end=n.end,[t];if("right"==i.abRelation.side&&e.targetPosition.isEqual(t.newRange.end))return t.newRange.start=n.start,t.newRange.end.path=i.abRelation.path,[t]}t.newRange=vr._createFromRanges(t.newRange._getTransformedByMoveOperation(e))}return[t]}),xd(Ra,ja,(t,e,i)=>{if(t.oldRange&&(t.oldRange=t.oldRange._getTransformedBySplitOperation(e)),t.newRange){if(i.abRelation){const n=t.newRange._getTransformedBySplitOperation(e);return t.newRange.start.isEqual(e.splitPosition)&&i.abRelation.wasStartBeforeMergedElement?t.newRange.start=_r._createAt(e.insertionPosition):t.newRange.start.isEqual(e.splitPosition)&&!i.abRelation.wasInLeftElement&&(t.newRange.start=_r._createAt(e.moveTargetPosition)),t.newRange.end.isEqual(e.splitPosition)&&i.abRelation.wasInRightElement?t.newRange.end=_r._createAt(e.moveTargetPosition):t.newRange.end.isEqual(e.splitPosition)&&i.abRelation.wasEndBeforeMergedElement?t.newRange.end=_r._createAt(e.insertionPosition):t.newRange.end=n.end,[t]}t.newRange=t.newRange._getTransformedBySplitOperation(e)}return[t]}),xd(za,Oa,(t,e)=>(t.sourcePosition.hasSameParentAs(e.position)&&(t.howMany+=e.howMany),t.sourcePosition=t.sourcePosition._getTransformedByInsertOperation(e),t.targetPosition=t.targetPosition._getTransformedByInsertOperation(e),[t])),xd(za,za,(t,e,i)=>{if(t.sourcePosition.isEqual(e.sourcePosition)&&t.targetPosition.isEqual(e.targetPosition)){if(i.bWasUndone){const i=e.graveyardPosition.path.slice();return i.push(0),t.sourcePosition=new _r(e.graveyardPosition.root,i),t.howMany=0,[t]}return[new nc(0)]}if(t.sourcePosition.isEqual(e.sourcePosition)&&!t.targetPosition.isEqual(e.targetPosition)&&!i.bWasUndone&&"splitAtSource"!=i.abRelation){const n="$graveyard"==t.targetPosition.root.rootName,o="$graveyard"==e.targetPosition.root.rootName,s=n&&!o;if(o&&!n||!s&&i.aIsStrong){const i=e.targetPosition._getTransformedByMergeOperation(e),n=t.targetPosition._getTransformedByMergeOperation(e);return[new Na(i,t.howMany,n,0)]}return[new nc(0)]}return t.sourcePosition.hasSameParentAs(e.targetPosition)&&(t.howMany+=e.howMany),t.sourcePosition=t.sourcePosition._getTransformedByMergeOperation(e),t.targetPosition=t.targetPosition._getTransformedByMergeOperation(e),t.graveyardPosition.isEqual(e.graveyardPosition)&&i.aIsStrong||(t.graveyardPosition=t.graveyardPosition._getTransformedByMergeOperation(e)),[t]}),xd(za,Na,(t,e,i)=>{const n=vr._createFromPositionAndShift(e.sourcePosition,e.howMany);return"remove"==e.type&&!i.bWasUndone&&!i.forceWeakRemove&&t.deletionPosition.hasSameParentAs(e.sourcePosition)&&n.containsPosition(t.sourcePosition)?[new nc(0)]:(t.sourcePosition.hasSameParentAs(e.targetPosition)&&(t.howMany+=e.howMany),t.sourcePosition.hasSameParentAs(e.sourcePosition)&&(t.howMany-=e.howMany),t.sourcePosition=t.sourcePosition._getTransformedByMoveOperation(e),t.targetPosition=t.targetPosition._getTransformedByMoveOperation(e),t.graveyardPosition.isEqual(e.targetPosition)||(t.graveyardPosition=t.graveyardPosition._getTransformedByMoveOperation(e)),[t])}),xd(za,ja,(t,e,i)=>{if(e.graveyardPosition&&(t.graveyardPosition=t.graveyardPosition._getTransformedByDeletion(e.graveyardPosition,1),t.deletionPosition.isEqual(e.graveyardPosition)&&(t.howMany=e.howMany)),t.targetPosition.isEqual(e.splitPosition)){const n=0!=e.howMany,o=e.graveyardPosition&&t.deletionPosition.isEqual(e.graveyardPosition);if(n||o||"mergeTargetNotMoved"==i.abRelation)return t.sourcePosition=t.sourcePosition._getTransformedBySplitOperation(e),[t]}if(t.sourcePosition.isEqual(e.splitPosition)){if("mergeSourceNotMoved"==i.abRelation)return t.howMany=0,t.targetPosition=t.targetPosition._getTransformedBySplitOperation(e),[t];if("mergeSameElement"==i.abRelation||t.sourcePosition.offset>0)return t.sourcePosition=e.moveTargetPosition.clone(),t.targetPosition=t.targetPosition._getTransformedBySplitOperation(e),[t]}return t.sourcePosition.hasSameParentAs(e.splitPosition)&&(t.howMany=e.splitPosition.offset),t.sourcePosition=t.sourcePosition._getTransformedBySplitOperation(e),t.targetPosition=t.targetPosition._getTransformedBySplitOperation(e),[t]}),xd(Na,Oa,(t,e)=>{const i=vr._createFromPositionAndShift(t.sourcePosition,t.howMany)._getTransformedByInsertOperation(e,!1)[0];return t.sourcePosition=i.start,t.howMany=i.end.offset-i.start.offset,t.targetPosition.isEqual(e.position)||(t.targetPosition=t.targetPosition._getTransformedByInsertOperation(e)),[t]}),xd(Na,Na,(t,e,i)=>{const n=vr._createFromPositionAndShift(t.sourcePosition,t.howMany),o=vr._createFromPositionAndShift(e.sourcePosition,e.howMany);let s,r=i.aIsStrong,a=!i.aIsStrong;if("insertBefore"==i.abRelation||"insertAfter"==i.baRelation?a=!0:"insertAfter"!=i.abRelation&&"insertBefore"!=i.baRelation||(a=!1),s=t.targetPosition.isEqual(e.targetPosition)&&a?t.targetPosition._getTransformedByDeletion(e.sourcePosition,e.howMany):t.targetPosition._getTransformedByMove(e.sourcePosition,e.targetPosition,e.howMany),Id(t,e)&&Id(e,t))return[e.getReversed()];if(n.containsPosition(e.targetPosition)&&n.containsRange(o,!0))return n.start=n.start._getTransformedByMove(e.sourcePosition,e.targetPosition,e.howMany),n.end=n.end._getTransformedByMove(e.sourcePosition,e.targetPosition,e.howMany),Nd([n],s);if(o.containsPosition(t.targetPosition)&&o.containsRange(n,!0))return n.start=n.start._getCombined(e.sourcePosition,e.getMovedRangeStart()),n.end=n.end._getCombined(e.sourcePosition,e.getMovedRangeStart()),Nd([n],s);const c=Ei(t.sourcePosition.getParentPath(),e.sourcePosition.getParentPath());if("prefix"==c||"extension"==c)return n.start=n.start._getTransformedByMove(e.sourcePosition,e.targetPosition,e.howMany),n.end=n.end._getTransformedByMove(e.sourcePosition,e.targetPosition,e.howMany),Nd([n],s);"remove"!=t.type||"remove"==e.type||i.aWasUndone||i.forceWeakRemove?"remove"==t.type||"remove"!=e.type||i.bWasUndone||i.forceWeakRemove||(r=!1):r=!0;const l=[],d=n.getDifference(o);for(const t of d){t.start=t.start._getTransformedByDeletion(e.sourcePosition,e.howMany),t.end=t.end._getTransformedByDeletion(e.sourcePosition,e.howMany);const i="same"==Ei(t.start.getParentPath(),e.getMovedRangeStart().getParentPath()),n=t._getTransformedByInsertion(e.getMovedRangeStart(),e.howMany,i);l.push(...n)}const h=n.getIntersection(o);return null!==h&&r&&(h.start=h.start._getCombined(e.sourcePosition,e.getMovedRangeStart()),h.end=h.end._getCombined(e.sourcePosition,e.getMovedRangeStart()),0===l.length?l.push(h):1==l.length?o.start.isBefore(n.start)||o.start.isEqual(n.start)?l.unshift(h):l.push(h):l.splice(1,0,h)),0===l.length?[new nc(t.baseVersion)]:Nd(l,s)}),xd(Na,ja,(t,e,i)=>{let n=t.targetPosition.clone();t.targetPosition.isEqual(e.insertionPosition)&&e.graveyardPosition&&"moveTargetAfter"!=i.abRelation||(n=t.targetPosition._getTransformedBySplitOperation(e));const o=vr._createFromPositionAndShift(t.sourcePosition,t.howMany);if(o.end.isEqual(e.insertionPosition))return e.graveyardPosition||t.howMany++,t.targetPosition=n,[t];if(o.start.hasSameParentAs(e.splitPosition)&&o.containsPosition(e.splitPosition)){let t=new vr(e.splitPosition,o.end);return t=t._getTransformedBySplitOperation(e),Nd([new vr(o.start,e.splitPosition),t],n)}t.targetPosition.isEqual(e.splitPosition)&&"insertAtSource"==i.abRelation&&(n=e.moveTargetPosition),t.targetPosition.isEqual(e.insertionPosition)&&"insertBetween"==i.abRelation&&(n=t.targetPosition);const s=[o._getTransformedBySplitOperation(e)];if(e.graveyardPosition){const n=o.start.isEqual(e.graveyardPosition)||o.containsPosition(e.graveyardPosition);t.howMany>1&&n&&!i.aWasUndone&&s.push(vr._createFromPositionAndShift(e.insertionPosition,1))}return Nd(s,n)}),xd(Na,za,(t,e,i)=>{const n=vr._createFromPositionAndShift(t.sourcePosition,t.howMany);if(e.deletionPosition.hasSameParentAs(t.sourcePosition)&&n.containsPosition(e.sourcePosition))if("remove"!=t.type||i.forceWeakRemove){if(1==t.howMany)return i.bWasUndone?(t.sourcePosition=e.graveyardPosition.clone(),t.targetPosition=t.targetPosition._getTransformedByMergeOperation(e),[t]):[new nc(0)]}else if(!i.aWasUndone){const i=[];let n=e.graveyardPosition.clone(),o=e.targetPosition._getTransformedByMergeOperation(e);t.howMany>1&&(i.push(new Na(t.sourcePosition,t.howMany-1,t.targetPosition,0)),n=n._getTransformedByMove(t.sourcePosition,t.targetPosition,t.howMany-1),o=o._getTransformedByMove(t.sourcePosition,t.targetPosition,t.howMany-1));const s=e.deletionPosition._getCombined(t.sourcePosition,t.targetPosition),r=new Na(n,1,s,0),a=r.getMovedRangeStart().path.slice();a.push(0);const c=new _r(r.targetPosition.root,a);o=o._getTransformedByMove(n,s,1);const l=new Na(o,e.howMany,c,0);return i.push(r),i.push(l),i}const o=vr._createFromPositionAndShift(t.sourcePosition,t.howMany)._getTransformedByMergeOperation(e);return t.sourcePosition=o.start,t.howMany=o.end.offset-o.start.offset,t.targetPosition=t.targetPosition._getTransformedByMergeOperation(e),[t]}),xd(La,Oa,(t,e)=>(t.position=t.position._getTransformedByInsertOperation(e),[t])),xd(La,za,(t,e)=>t.position.isEqual(e.deletionPosition)?(t.position=e.graveyardPosition.clone(),t.position.stickiness="toNext",[t]):(t.position=t.position._getTransformedByMergeOperation(e),[t])),xd(La,Na,(t,e)=>(t.position=t.position._getTransformedByMoveOperation(e),[t])),xd(La,La,(t,e,i)=>{if(t.position.isEqual(e.position)){if(!i.aIsStrong)return[new nc(0)];t.oldName=e.newName}return[t]}),xd(La,ja,(t,e)=>{if("same"==Ei(t.position.path,e.splitPosition.getParentPath())&&!e.graveyardPosition){const e=new La(t.position.getShiftedBy(1),t.oldName,t.newName,0);return[t,e]}return t.position=t.position._getTransformedBySplitOperation(e),[t]}),xd(Da,Da,(t,e,i)=>{if(t.root===e.root&&t.key===e.key){if(!i.aIsStrong||t.newValue===e.newValue)return[new nc(0)];t.oldValue=e.newValue}return[t]}),xd(ja,Oa,(t,e)=>(t.splitPosition.hasSameParentAs(e.position)&&t.splitPosition.offset<e.position.offset&&(t.howMany+=e.howMany),t.splitPosition=t.splitPosition._getTransformedByInsertOperation(e),t.insertionPosition=ja.getInsertionPosition(t.splitPosition),[t])),xd(ja,za,(t,e,i)=>{if(!t.graveyardPosition&&!i.bWasUndone&&t.splitPosition.hasSameParentAs(e.sourcePosition)){const i=e.graveyardPosition.path.slice();i.push(0);const n=new _r(e.graveyardPosition.root,i),o=ja.getInsertionPosition(new _r(e.graveyardPosition.root,i)),s=new ja(n,0,null,0);return s.insertionPosition=o,t.splitPosition=t.splitPosition._getTransformedByMergeOperation(e),t.insertionPosition=ja.getInsertionPosition(t.splitPosition),t.graveyardPosition=s.insertionPosition.clone(),t.graveyardPosition.stickiness="toNext",[s,t]}return t.splitPosition.hasSameParentAs(e.deletionPosition)&&!t.splitPosition.isAfter(e.deletionPosition)&&t.howMany--,t.splitPosition.hasSameParentAs(e.targetPosition)&&(t.howMany+=e.howMany),t.splitPosition=t.splitPosition._getTransformedByMergeOperation(e),t.insertionPosition=ja.getInsertionPosition(t.splitPosition),t.graveyardPosition&&(t.graveyardPosition=t.graveyardPosition._getTransformedByMergeOperation(e)),[t]}),xd(ja,Na,(t,e,i)=>{const n=vr._createFromPositionAndShift(e.sourcePosition,e.howMany);if(t.graveyardPosition){const o=n.start.isEqual(t.graveyardPosition)||n.containsPosition(t.graveyardPosition);if(!i.bWasUndone&&o){const i=t.splitPosition._getTransformedByMoveOperation(e),n=t.graveyardPosition._getTransformedByMoveOperation(e),o=n.path.slice();o.push(0);const s=new _r(n.root,o);return[new Na(i,t.howMany,s,0)]}t.graveyardPosition=t.graveyardPosition._getTransformedByMoveOperation(e)}if(t.splitPosition.hasSameParentAs(e.sourcePosition)&&n.containsPosition(t.splitPosition)){const i=e.howMany-(t.splitPosition.offset-e.sourcePosition.offset);return t.howMany-=i,t.splitPosition.hasSameParentAs(e.targetPosition)&&t.splitPosition.offset<e.targetPosition.offset&&(t.howMany+=e.howMany),t.splitPosition=e.sourcePosition.clone(),t.insertionPosition=ja.getInsertionPosition(t.splitPosition),[t]}return!t.splitPosition.isEqual(e.targetPosition)||"insertAtSource"!=i.baRelation&&"splitBefore"!=i.abRelation?(e.sourcePosition.isEqual(e.targetPosition)||(t.splitPosition.hasSameParentAs(e.sourcePosition)&&t.splitPosition.offset<=e.sourcePosition.offset&&(t.howMany-=e.howMany),t.splitPosition.hasSameParentAs(e.targetPosition)&&t.splitPosition.offset<e.targetPosition.offset&&(t.howMany+=e.howMany)),t.splitPosition.stickiness="toNone",t.splitPosition=t.splitPosition._getTransformedByMoveOperation(e),t.splitPosition.stickiness="toNext",t.graveyardPosition?t.insertionPosition=t.insertionPosition._getTransformedByMoveOperation(e):t.insertionPosition=ja.getInsertionPosition(t.splitPosition),[t]):(t.howMany+=e.howMany,t.splitPosition=t.splitPosition._getTransformedByDeletion(e.sourcePosition,e.howMany),t.insertionPosition=ja.getInsertionPosition(t.splitPosition),[t])}),xd(ja,ja,(t,e,i)=>{if(t.splitPosition.isEqual(e.splitPosition)){if(!t.graveyardPosition&&!e.graveyardPosition)return[new nc(0)];if(t.graveyardPosition&&e.graveyardPosition&&t.graveyardPosition.isEqual(e.graveyardPosition))return[new nc(0)];if("splitBefore"==i.abRelation)return t.howMany=0,t.graveyardPosition=t.graveyardPosition._getTransformedBySplitOperation(e),[t]}if(t.graveyardPosition&&e.graveyardPosition&&t.graveyardPosition.isEqual(e.graveyardPosition)){const n="$graveyard"==t.splitPosition.root.rootName,o="$graveyard"==e.splitPosition.root.rootName,s=n&&!o;if(o&&!n||!s&&i.aIsStrong){const i=[];return e.howMany&&i.push(new Na(e.moveTargetPosition,e.howMany,e.splitPosition,0)),t.howMany&&i.push(new Na(t.splitPosition,t.howMany,t.moveTargetPosition,0)),i}return[new nc(0)]}if(t.graveyardPosition&&(t.graveyardPosition=t.graveyardPosition._getTransformedBySplitOperation(e)),t.splitPosition.isEqual(e.insertionPosition)&&"splitBefore"==i.abRelation)return t.howMany++,[t];if(e.splitPosition.isEqual(t.insertionPosition)&&"splitBefore"==i.baRelation){const i=e.insertionPosition.path.slice();i.push(0);const n=new _r(e.insertionPosition.root,i);return[t,new Na(t.insertionPosition,1,n,0)]}return t.splitPosition.hasSameParentAs(e.splitPosition)&&t.splitPosition.offset<e.splitPosition.offset&&(t.howMany-=e.howMany),t.splitPosition=t.splitPosition._getTransformedBySplitOperation(e),t.insertionPosition=ja.getInsertionPosition(t.splitPosition),[t]});class Od extends Jl{constructor(t){super(t),this._stack=[],this._createdBatches=new WeakSet,this.refresh()}refresh(){this.isEnabled=this._stack.length>0}addBatch(t){const e=this.editor.model.document.selection,i={ranges:e.hasOwnRange?Array.from(e.getRanges()):[],isBackward:e.isBackward};this._stack.push({batch:t,selection:i}),this.refresh()}clearStack(){this._stack=[],this.refresh()}_restoreSelection(t,e,i){const n=this.editor.model,o=n.document,s=[];for(const e of t){const t=Rd(e,i).find(t=>t.start.root!=o.graveyard);t&&s.push(t)}s.length&&n.change(t=>{t.setSelection(s,{backward:e})})}_undo(t,e){const i=this.editor.model,n=i.document;this._createdBatches.add(e);const o=t.operations.slice().filter(t=>t.isDocumentOperation);o.reverse();for(const t of o){const o=t.baseVersion+1,s=Array.from(n.history.getOperations(o)),r=Td([t.getReversed()],s,{useRelations:!0,document:this.editor.model.document,padWithNoOps:!1,forceWeakRemove:!0}).operationsA;for(const o of r)e.addOperation(o),i.applyOperation(o),n.history.setOperationAsUndone(t,o)}}}function Rd(t,e){const i=t.getTransformedByOperations(e);i.sort((t,e)=>t.start.isBefore(e.start)?-1:1);for(let t=1;t<i.length;t++){const e=i[t-1],n=i[t];e.end.isTouching(n.start)&&(e.end=n.end,i.splice(t,1),t--)}return i}class Ld extends Od{execute(t=null){const e=t?this._stack.findIndex(e=>e.batch==t):this._stack.length-1,i=this._stack.splice(e,1)[0],n=this.editor.model.createBatch("transparent");this.editor.model.enqueueChange(n,()=>{this._undo(i.batch,n);const t=this.editor.model.document.history.getOperations(i.batch.baseVersion);this._restoreSelection(i.selection.ranges,i.selection.isBackward,t),this.fire("revert",i.batch,n)}),this.refresh()}}class Dd extends Od{execute(){const t=this._stack.pop(),e=this.editor.model.createBatch("transparent");this.editor.model.enqueueChange(e,()=>{const i=t.batch.operations[t.batch.operations.length-1].baseVersion+1,n=this.editor.model.document.history.getOperations(i);this._restoreSelection(t.selection.ranges,t.selection.isBackward,n),this._undo(t.batch,e)}),this.refresh()}}class zd extends ql{static get pluginName(){return"UndoEditing"}constructor(t){super(t),this._batchRegistry=new WeakSet}init(){const t=this.editor;this._undoCommand=new Ld(t),this._redoCommand=new Dd(t),t.commands.add("undo",this._undoCommand),t.commands.add("redo",this._redoCommand),this.listenTo(t.model,"applyOperation",(t,e)=>{const i=e[0];if(!i.isDocumentOperation)return;const n=i.batch,o=this._redoCommand._createdBatches.has(n),s=this._undoCommand._createdBatches.has(n);this._batchRegistry.has(n)||"transparent"==n.type&&!o&&!s||(o?this._undoCommand.addBatch(n):s||(this._undoCommand.addBatch(n),this._redoCommand.clearStack()),this._batchRegistry.add(n))},{priority:"highest"}),this.listenTo(this._undoCommand,"revert",(t,e,i)=>{this._redoCommand.addBatch(i)}),t.keystrokes.set("CTRL+Z","undo"),t.keystrokes.set("CTRL+Y","redo"),t.keystrokes.set("CTRL+SHIFT+Z","redo")}}var jd='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5.042 9.367l2.189 1.837a.75.75 0 01-.965 1.149l-3.788-3.18a.747.747 0 01-.21-.284.75.75 0 01.17-.945L6.23 4.762a.75.75 0 11.964 1.15L4.863 7.866h8.917A.75.75 0 0114 7.9a4 4 0 11-1.477 7.718l.344-1.489a2.5 2.5 0 101.094-4.73l.008-.032H5.042z"/></svg>',Vd='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M14.958 9.367l-2.189 1.837a.75.75 0 00.965 1.149l3.788-3.18a.747.747 0 00.21-.284.75.75 0 00-.17-.945L13.77 4.762a.75.75 0 10-.964 1.15l2.331 1.955H6.22A.75.75 0 006 7.9a4 4 0 101.477 7.718l-.344-1.489A2.5 2.5 0 116.039 9.4l-.008-.032h8.927z"/></svg>';class Bd extends ql{init(){const t=this.editor,e=t.locale,i=t.t,n="ltr"==e.uiLanguageDirection?jd:Vd,o="ltr"==e.uiLanguageDirection?Vd:jd;this._addButton("undo",i("di"),"CTRL+Z",n),this._addButton("redo",i("dj"),"CTRL+Y",o)}_addButton(t,e,i,n){const o=this.editor;o.ui.componentFactory.add(t,s=>{const r=o.commands.get(t),a=new El(s);return a.set({label:e,icon:n,keystroke:i,tooltip:!0}),a.bind("isEnabled").to(r,"isEnabled"),this.listenTo(a,"execute",()=>{o.execute(t),o.editing.view.focus()}),a})}}class Fd extends ql{static get requires(){return[zd,Bd]}static get pluginName(){return"Undo"}}class Hd{constructor(t){this.context=t}destroy(){this.stopListening()}static get isContextPlugin(){return!0}}vi(Hd,Hn);class Ud extends Hd{static get pluginName(){return"PendingActions"}init(){this.set("hasAny",!1),this._actions=new yi({idProperty:"_id"}),this._actions.delegate("add","remove").to(this)}add(t){if("string"!=typeof t)throw new hi.b("pendingactions-add-invalid-message: The message must be a string.",this);const e=Object.create(Hn);return e.set("message",t),this._actions.add(e),this.hasAny=!0,e}remove(t){this._actions.remove(t),this.hasAny=!!this._actions.length}get first(){return this._actions.get(0)}[Symbol.iterator](){return this._actions[Symbol.iterator]()}}class Wd{constructor(){const t=new window.FileReader;this._reader=t,this._data=void 0,this.set("loaded",0),t.onprogress=t=>{this.loaded=t.loaded}}get error(){return this._reader.error}get data(){return this._data}read(t){const e=this._reader;return this.total=t.size,new Promise((i,n)=>{e.onload=()=>{const t=e.result;this._data=t,i(t)},e.onerror=()=>{n("error")},e.onabort=()=>{n("aborted")},this._reader.readAsDataURL(t)})}abort(){this._reader.abort()}}vi(Wd,Hn);class qd extends ql{static get pluginName(){return"FileRepository"}static get requires(){return[Ud]}init(){this.loaders=new yi,this.loaders.on("add",()=>this._updatePendingAction()),this.loaders.on("remove",()=>this._updatePendingAction()),this._loadersMap=new Map,this._pendingAction=null,this.set("uploaded",0),this.set("uploadTotal",null),this.bind("uploadedPercent").to(this,"uploaded",this,"uploadTotal",(t,e)=>e?t/e*100:0)}getLoader(t){return this._loadersMap.get(t)||null}createLoader(t){if(!this.createUploadAdapter)return console.warn(Object(hi.a)("filerepository-no-upload-adapter: Upload adapter is not defined.")),null;const e=new $d(Promise.resolve(t),this.createUploadAdapter);return this.loaders.add(e),this._loadersMap.set(t,e),t instanceof Promise&&e.file.then(t=>{this._loadersMap.set(t,e)}).catch(()=>{}),e.on("change:uploaded",()=>{let t=0;for(const e of this.loaders)t+=e.uploaded;this.uploaded=t}),e.on("change:uploadTotal",()=>{let t=0;for(const e of this.loaders)e.uploadTotal&&(t+=e.uploadTotal);this.uploadTotal=t}),e}destroyLoader(t){const e=t instanceof $d?t:this.getLoader(t);e._destroy(),this.loaders.remove(e),this._loadersMap.forEach((t,i)=>{t===e&&this._loadersMap.delete(i)})}_updatePendingAction(){const t=this.editor.plugins.get(Ud);if(this.loaders.length){if(!this._pendingAction){const e=this.editor.t,i=t=>`${e("ai")} ${parseInt(t)}%.`;this._pendingAction=t.add(i(this.uploadedPercent)),this._pendingAction.bind("message").to(this,"uploadedPercent",i)}}else t.remove(this._pendingAction),this._pendingAction=null}}vi(qd,Hn);class $d{constructor(t,e){this.id=li(),this._filePromiseWrapper=this._createFilePromiseWrapper(t),this._adapter=e(this),this._reader=new Wd,this.set("status","idle"),this.set("uploaded",0),this.set("uploadTotal",null),this.bind("uploadedPercent").to(this,"uploaded",this,"uploadTotal",(t,e)=>e?t/e*100:0),this.set("uploadResponse",null)}get file(){return this._filePromiseWrapper?this._filePromiseWrapper.promise.then(t=>this._filePromiseWrapper?t:null):Promise.resolve(null)}get data(){return this._reader.data}read(){if("idle"!=this.status)throw new hi.b("filerepository-read-wrong-status: You cannot call read if the status is different than idle.",this);return this.status="reading",this.file.then(t=>this._reader.read(t)).then(t=>(this.status="idle",t)).catch(t=>{if("aborted"===t)throw this.status="aborted","aborted";throw this.status="error",this._reader.error?this._reader.error:t})}upload(){if("idle"!=this.status)throw new hi.b("filerepository-upload-wrong-status: You cannot call upload if the status is different than idle.",this);return this.status="uploading",this.file.then(()=>this._adapter.upload()).then(t=>(this.uploadResponse=t,this.status="idle",t)).catch(t=>{if("aborted"===this.status)throw"aborted";throw this.status="error",t})}abort(){const t=this.status;this.status="aborted",this._filePromiseWrapper.isFulfilled?"reading"==t?this._reader.abort():"uploading"==t&&this._adapter.abort&&this._adapter.abort():(this._filePromiseWrapper.promise.catch(()=>{}),this._filePromiseWrapper.rejecter("aborted")),this._destroy()}_destroy(){this._filePromiseWrapper=void 0,this._reader=void 0,this._adapter=void 0,this.uploadResponse=void 0}_createFilePromiseWrapper(t){const e={};return e.promise=new Promise((i,n)=>{e.rejecter=n,e.isFulfilled=!1,t.then(t=>{e.isFulfilled=!0,i(t)}).catch(t=>{e.isFulfilled=!0,n(t)})}),e}}vi($d,Hn);function Yd(){let t=function(t){t=t.toLowerCase();const e=document.cookie.split(";");for(const i of e){const e=i.split("=");if(decodeURIComponent(e[0].trim().toLowerCase())===t)return decodeURIComponent(e[1])}return null}("ckCsrfToken");var e,i;return t&&40==t.length||(t=function(t){let e="";const i=new Uint8Array(t);window.crypto.getRandomValues(i);for(let t=0;t<i.length;t++){const n="abcdefghijklmnopqrstuvwxyz0123456789".charAt(i[t]%"abcdefghijklmnopqrstuvwxyz0123456789".length);e+=Math.random()>.5?n.toUpperCase():n}return e}(40),e="ckCsrfToken",i=t,document.cookie=encodeURIComponent(e)+"="+encodeURIComponent(i)+";path=/"),t}class Gd extends ql{static get requires(){return[qd]}static get pluginName(){return"CKFinderUploadAdapter"}init(){const t=this.editor.config.get("ckfinder.uploadUrl");t&&(this.editor.plugins.get(qd).createUploadAdapter=e=>new Qd(e,t,this.editor.t))}}class Qd{constructor(t,e,i){this.loader=t,this.url=e,this.t=i}upload(){return this.loader.file.then(t=>new Promise((e,i)=>{this._initRequest(),this._initListeners(e,i,t),this._sendRequest(t)}))}abort(){this.xhr&&this.xhr.abort()}_initRequest(){const t=this.xhr=new XMLHttpRequest;t.open("POST",this.url,!0),t.responseType="json"}_initListeners(t,e,i){const n=this.xhr,o=this.loader,s=(0,this.t)("a")+` ${i.name}.`;n.addEventListener("error",()=>e(s)),n.addEventListener("abort",()=>e()),n.addEventListener("load",()=>{const i=n.response;if(!i||!i.uploaded)return e(i&&i.error&&i.error.message?i.error.message:s);t({default:i.url})}),n.upload&&n.upload.addEventListener("progress",t=>{t.lengthComputable&&(o.uploadTotal=t.total,o.uploaded=t.loaded)})}_sendRequest(t){const e=new FormData;e.append("upload",t),e.append("ckCsrfToken",Yd()),this.xhr.send(e)}}class Kd{static get pluginName(){return"BlockAutoformatEditing"}constructor(t,e,i){let n,o=null;"function"==typeof i?n=i:(o=t.commands.get(i),n=()=>{t.execute(i)}),t.model.document.on("change",(i,s)=>{if(o&&!o.isEnabled)return;if("transparent"==s.type)return;const r=Array.from(t.model.document.differ.getChanges()),a=r[0];if(1!=r.length||"insert"!==a.type||"$text"!=a.name||1!=a.length)return;const c=a.position.parent;if(!c.is("paragraph")||1!==c.childCount)return;const l=e.exec(c.getChild(0).data);l&&t.model.enqueueChange(t=>{const e=t.createPositionAt(c,0),i=t.createPositionAt(c,l[0].length),o=new Nr(e,i);!1!==n({match:l})&&t.remove(o),o.detach()})})}}class Jd{static get pluginName(){return"InlineAutoformatEditing"}constructor(t,e,i){let n,o,s,r;e instanceof RegExp?n=e:s=e,"string"==typeof i?o=i:r=i,s=s||(t=>{let e;const i=[],o=[];for(;null!==(e=n.exec(t))&&!(e&&e.length<4);){let{index:t,1:n,2:s,3:r}=e;const a=n+s+r;t+=e[0].length-a.length;const c=[t,t+n.length],l=[t+n.length+s.length,t+n.length+s.length+r.length];i.push(c),i.push(l),o.push([t+n.length,t+n.length+s.length])}return{remove:i,format:o}}),r=r||((e,i)=>{const n=t.model.schema.getValidRanges(i,o);for(const t of n)e.setAttribute(o,!0,t);e.removeSelectionAttribute(o)}),t.model.document.on("change",(e,i)=>{if("transparent"==i.type)return;const n=t.model,o=n.document.selection;if(!o.isCollapsed)return;const a=Array.from(n.document.differ.getChanges()),c=a[0];if(1!=a.length||"insert"!==c.type||"$text"!=c.name||1!=c.length)return;const l=o.focus,d=l.parent,{text:h,range:u}=function(t,e){let i=t.start;return{text:Array.from(t.getItems()).reduce((t,n)=>n.is("text")||n.is("textProxy")?t+n.data:(i=e.createPositionAfter(n),""),""),range:e.createRange(i,t.end)}}(n.createRange(n.createPositionAt(d,0),l),n),f=s(h),m=Zd(u.start,f.format,n),g=Zd(u.start,f.remove,n);m.length&&g.length&&n.enqueueChange(t=>{if(!1!==r(t,m))for(const e of g.reverse())t.remove(e)})})}}function Zd(t,e,i){return e.filter(t=>void 0!==t[0]&&void 0!==t[1]).map(e=>i.createRange(t.getShiftedBy(e[0]),t.getShiftedBy(e[1])))}function Xd(t,e){return(i,n)=>{if(!t.commands.get(e).isEnabled)return!1;const o=t.model.schema.getValidRanges(n,e);for(const t of o)i.setAttribute(e,!0,t);i.removeSelectionAttribute(e)}}class th extends Jl{constructor(t,e){super(t),this.attributeKey=e}refresh(){const t=this.editor.model,e=t.document;this.value=this._getValueFromFirstAllowedNode(),this.isEnabled=t.schema.checkAttributeInSelection(e.selection,this.attributeKey)}execute(t={}){const e=this.editor.model,i=e.document.selection,n=void 0===t.forceValue?!this.value:t.forceValue;e.change(t=>{if(i.isCollapsed)n?t.setSelectionAttribute(this.attributeKey,!0):t.removeSelectionAttribute(this.attributeKey);else{const o=e.schema.getValidRanges(i.getRanges(),this.attributeKey);for(const e of o)n?t.setAttribute(this.attributeKey,n,e):t.removeAttribute(this.attributeKey,e)}})}_getValueFromFirstAllowedNode(){const t=this.editor.model,e=t.schema,i=t.document.selection;if(i.isCollapsed)return i.hasAttribute(this.attributeKey);for(const t of i.getRanges())for(const i of t.getItems())if(e.checkAttribute(i,this.attributeKey))return i.hasAttribute(this.attributeKey);return!1}}class eh extends ql{static get pluginName(){return"BoldEditing"}init(){const t=this.editor;t.model.schema.extend("$text",{allowAttributes:"bold"}),t.model.schema.setAttributeProperties("bold",{isFormatting:!0,copyOnEnter:!0}),t.conversion.attributeToElement({model:"bold",view:"strong",upcastAlso:["b",t=>{const e=t.getStyle("font-weight");return e?"bold"==e||Number(e)>=600?{name:!0,styles:["font-weight"]}:void 0:null}]}),t.commands.add("bold",new th(t,"bold")),t.keystrokes.set("CTRL+B","bold")}}class ih extends ql{init(){const t=this.editor,e=t.t;t.ui.componentFactory.add("bold",i=>{const n=t.commands.get("bold"),o=new El(i);return o.set({label:e("g"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.187 17H5.773c-.637 0-1.092-.138-1.364-.415-.273-.277-.409-.718-.409-1.323V4.738c0-.617.14-1.062.419-1.332.279-.27.73-.406 1.354-.406h4.68c.69 0 1.288.041 1.793.124.506.083.96.242 1.36.478.341.197.644.447.906.75a3.262 3.262 0 01.808 2.162c0 1.401-.722 2.426-2.167 3.075C15.05 10.175 16 11.315 16 13.01a3.756 3.756 0 01-2.296 3.504 6.1 6.1 0 01-1.517.377c-.571.073-1.238.11-2 .11zm-.217-6.217H7v4.087h3.069c1.977 0 2.965-.69 2.965-2.072 0-.707-.256-1.22-.768-1.537-.512-.319-1.277-.478-2.296-.478zM7 5.13v3.619h2.606c.729 0 1.292-.067 1.69-.2a1.6 1.6 0 00.91-.765c.165-.267.247-.566.247-.897 0-.707-.26-1.176-.778-1.409-.519-.232-1.31-.348-2.375-.348H7z"/></svg>',keystroke:"CTRL+B",tooltip:!0,isToggleable:!0}),o.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(o,"execute",()=>{t.execute("bold"),t.editing.view.focus()}),o})}}class nh extends ql{static get pluginName(){return"ItalicEditing"}init(){const t=this.editor;t.model.schema.extend("$text",{allowAttributes:"italic"}),t.model.schema.setAttributeProperties("italic",{isFormatting:!0,copyOnEnter:!0}),t.conversion.attributeToElement({model:"italic",view:"i",upcastAlso:["em",{styles:{"font-style":"italic"}}]}),t.commands.add("italic",new th(t,"italic")),t.keystrokes.set("CTRL+I","italic")}}class oh extends ql{init(){const t=this.editor,e=t.t;t.ui.componentFactory.add("italic",i=>{const n=t.commands.get("italic"),o=new El(i);return o.set({label:e("d"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.586 14.633l.021.004c-.036.335.095.655.393.962.082.083.173.15.274.201h1.474a.6.6 0 110 1.2H5.304a.6.6 0 010-1.2h1.15c.474-.07.809-.182 1.005-.334.157-.122.291-.32.404-.597l2.416-9.55a1.053 1.053 0 00-.281-.823 1.12 1.12 0 00-.442-.296H8.15a.6.6 0 010-1.2h6.443a.6.6 0 110 1.2h-1.195c-.376.056-.65.155-.823.296-.215.175-.423.439-.623.79l-2.366 9.347z"/></svg>',keystroke:"CTRL+I",tooltip:!0,isToggleable:!0}),o.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(o,"execute",()=>{t.execute("italic"),t.editing.view.focus()}),o})}}function sh(t){const e=t.next();return e.done?null:e.value}class rh extends Jl{refresh(){this.value=this._getValue(),this.isEnabled=this._checkEnabled()}execute(t={}){const e=this.editor.model,i=e.schema,n=e.document.selection,o=Array.from(n.getSelectedBlocks()),s=void 0===t.forceValue?!this.value:t.forceValue;e.change(t=>{if(s){const e=o.filter(t=>ah(t)||lh(i,t));this._applyQuote(t,e)}else this._removeQuote(t,o.filter(ah))})}_getValue(){const t=sh(this.editor.model.document.selection.getSelectedBlocks());return!(!t||!ah(t))}_checkEnabled(){if(this.value)return!0;const t=this.editor.model.document.selection,e=this.editor.model.schema,i=sh(t.getSelectedBlocks());return!!i&&lh(e,i)}_removeQuote(t,e){ch(t,e).reverse().forEach(e=>{if(e.start.isAtStart&&e.end.isAtEnd)return void t.unwrap(e.start.parent);if(e.start.isAtStart){const i=t.createPositionBefore(e.start.parent);return void t.move(e,i)}e.end.isAtEnd||t.split(e.end);const i=t.createPositionAfter(e.end.parent);t.move(e,i)})}_applyQuote(t,e){const i=[];ch(t,e).reverse().forEach(e=>{let n=ah(e.start);n||(n=t.createElement("blockQuote"),t.wrap(e,n)),i.push(n)}),i.reverse().reduce((e,i)=>e.nextSibling==i?(t.merge(t.createPositionAfter(e)),e):i)}}function ah(t){return"blockQuote"==t.parent.name?t.parent:null}function ch(t,e){let i,n=0;const o=[];for(;n<e.length;){const s=e[n],r=e[n+1];i||(i=t.createPositionBefore(s)),r&&s.nextSibling==r||(o.push(t.createRange(i,t.createPositionAfter(s))),i=null),n++}return o}function lh(t,e){const i=t.checkChild(e.parent,"blockQuote"),n=t.checkChild(["$root","blockQuote"],e);return i&&n}class dh extends ql{static get pluginName(){return"BlockQuoteEditing"}init(){const t=this.editor,e=t.model.schema;t.commands.add("blockQuote",new rh(t)),e.register("blockQuote",{allowWhere:"$block",allowContentOf:"$root"}),e.addChildCheck((t,e)=>{if(t.endsWith("blockQuote")&&"blockQuote"==e.name)return!1}),t.conversion.elementToElement({model:"blockQuote",view:"blockquote"}),t.model.document.registerPostFixer(i=>{const n=t.model.document.differ.getChanges();for(const t of n)if("insert"==t.type){const n=t.position.nodeAfter;if(!n)continue;if(n.is("blockQuote")&&n.isEmpty)return i.remove(n),!0;if(n.is("blockQuote")&&!e.checkChild(t.position,n))return i.unwrap(n),!0;if(n.is("element")){const t=i.createRangeIn(n);for(const n of t.getItems())if(n.is("blockQuote")&&!e.checkChild(i.createPositionBefore(n),n))return i.unwrap(n),!0}}else if("remove"==t.type){const e=t.position.parent;if(e.is("blockQuote")&&e.isEmpty)return i.remove(e),!0}return!1})}afterInit(){const t=this.editor.commands.get("blockQuote");this.listenTo(this.editor.editing.view.document,"enter",(e,i)=>{const n=this.editor.model.document,o=n.selection.getLastPosition().parent;n.selection.isCollapsed&&o.isEmpty&&t.value&&(this.editor.execute("blockQuote"),this.editor.editing.view.scrollToTheSelection(),i.preventDefault(),e.stop())})}}i(44);class hh extends ql{init(){const t=this.editor,e=t.t;t.ui.componentFactory.add("blockQuote",i=>{const n=t.commands.get("blockQuote"),o=new El(i);return o.set({label:e("k"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 10.423a6.5 6.5 0 016.056-6.408l.038.67C6.448 5.423 5.354 7.663 5.22 10H9c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.574zm8 0a6.5 6.5 0 016.056-6.408l.038.67c-2.646.739-3.74 2.979-3.873 5.315H17c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.574z"/></svg>',tooltip:!0,isToggleable:!0}),o.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(o,"execute",()=>{t.execute("blockQuote"),t.editing.view.focus()}),o})}}class uh extends ql{static get pluginName(){return"CKFinderUI"}init(){const t=this.editor,e=t.ui.componentFactory,i=t.t;e.add("ckfinder",e=>{const n=t.commands.get("ckfinder"),o=new El(e);return o.set({label:i("t"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.627 16.5zm5.873-.196zm0-7.001V8h-13v8.5h4.341c.191.54.457 1.044.785 1.5H2a1.5 1.5 0 01-1.5-1.5v-13A1.5 1.5 0 012 2h4.5a1.5 1.5 0 011.06.44L9.122 4H16a1.5 1.5 0 011.5 1.5v1A1.5 1.5 0 0119 8v2.531a6.027 6.027 0 00-1.5-1.228zM16 6.5v-1H8.5l-2-2H2v13h1V8a1.5 1.5 0 011.5-1.5H16z"/><path d="M14.5 19.5a5 5 0 110-10 5 5 0 010 10zM15 14v-2h-1v2h-2v1h2v2h1v-2h2v-1h-2z"/></svg>',tooltip:!0}),o.bind("isEnabled").to(n),o.on("execute",()=>{t.execute("ckfinder"),t.editing.view.focus()}),o})}}class fh extends us{observe(t){this.listenTo(t,"load",(t,e)=>{"IMG"==e.target.tagName&&this._fireEvents(e)},{useCapture:!0})}_fireEvents(t){this.isEnabled&&(this.document.fire("layoutChanged"),this.document.fire("imageLoaded",t))}}function mh(t){return i=>{i.on(`attribute:${t}:image`,e)};function e(t,e,i){if(!i.consumable.consume(e.item,t.name))return;const n=i.writer,o=i.mapper.toViewElement(e.item).getChild(0);null!==e.attributeNewValue?n.setAttribute(e.attributeKey,e.attributeNewValue,o):n.removeAttribute(e.attributeKey,o)}}class gh{constructor(){this._stack=[]}add(t,e){const i=this._stack,n=i[0];this._insertDescriptor(t);const o=i[0];n===o||ph(n,o)||this.fire("change:top",{oldDescriptor:n,newDescriptor:o,writer:e})}remove(t,e){const i=this._stack,n=i[0];this._removeDescriptor(t);const o=i[0];n===o||ph(n,o)||this.fire("change:top",{oldDescriptor:n,newDescriptor:o,writer:e})}_insertDescriptor(t){const e=this._stack,i=e.findIndex(e=>e.id===t.id);if(ph(t,e[i]))return;i>-1&&e.splice(i,1);let n=0;for(;e[n]&&bh(e[n],t);)n++;e.splice(n,0,t)}_removeDescriptor(t){const e=this._stack,i=e.findIndex(e=>e.id===t);i>-1&&e.splice(i,1)}}function ph(t,e){return t&&e&&t.priority==e.priority&&wh(t.classes)==wh(e.classes)}function bh(t,e){return t.priority>e.priority||!(t.priority<e.priority)&&wh(t.classes)>wh(e.classes)}function wh(t){return Array.isArray(t)?t.sort().join(","):t}vi(gh,mi);function kh(t){return!!t.is("element")&&!!t.getCustomProperty("widget")}function _h(t,e,i={}){return fo.isEdge||e.setAttribute("contenteditable","false",t),e.addClass("ck-widget",t),e.setCustomProperty("widget",!0,t),t.getFillerOffset=Ah,i.label&&function(t,e,i){i.setCustomProperty("widgetLabel",e,t)}(t,i.label,e),i.hasSelectionHandle&&function(t,e){const i=e.createUIElement("div",{class:"ck ck-widget__selection-handle"},(function(t){const e=this.toDomElement(t),i=new Pl;return i.set("content",'<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M4 0v1H1v3H0V.5A.5.5 0 01.5 0H4zm8 0h3.5a.5.5 0 01.5.5V4h-1V1h-3V0zM4 16H.5a.5.5 0 01-.5-.5V12h1v3h3v1zm8 0v-1h3v-3h1v3.5a.5.5 0 01-.5.5H12z"/><path fill-opacity=".256" d="M1 1h14v14H1z"/><g class="ck-icon__selected-indicator"><path d="M7 0h2v1H7V0zM0 7h1v2H0V7zm15 0h1v2h-1V7zm-8 8h2v1H7v-1z"/><path fill-opacity=".254" d="M1 1h14v14H1z"/></g></svg>'),i.render(),e.appendChild(i.element),e}));e.insert(e.createPositionAt(t,0),i),e.addClass(["ck-widget_with-selection-handle"],t)}(t,e),function(t,e,i,n){const o=new gh;o.on("change:top",(e,o)=>{o.oldDescriptor&&n(t,o.oldDescriptor,o.writer),o.newDescriptor&&i(t,o.newDescriptor,o.writer)}),e.setCustomProperty("addHighlight",(t,e,i)=>o.add(e,i),t),e.setCustomProperty("removeHighlight",(t,e,i)=>o.remove(e,i),t)}(t,e,(t,e,i)=>i.addClass(n(e.classes),t),(t,e,i)=>i.removeClass(n(e.classes),t)),t;function n(t){return Array.isArray(t)?t:[t]}}function vh(t){const e=t.getCustomProperty("widgetLabel");return e?"function"==typeof e?e():e:""}function yh(t,e){return e.addClass(["ck-editor__editable","ck-editor__nested-editable"],t),fo.isEdge||(e.setAttribute("contenteditable",t.isReadOnly?"false":"true",t),t.on("change:isReadOnly",(i,n,o)=>{e.setAttribute("contenteditable",o?"false":"true",t)})),t.on("change:isFocused",(i,n,o)=>{o?e.addClass("ck-editor__nested-editable_focused",t):e.removeClass("ck-editor__nested-editable_focused",t)}),t}function xh(t,e){const i=t.getSelectedElement();if(i&&e.schema.isBlock(i))return e.createPositionAfter(i);const n=t.getSelectedBlocks().next().value;if(n){if(n.isEmpty)return e.createPositionAt(n,0);const i=e.createPositionAfter(n);return t.focus.isTouching(i)?i:e.createPositionBefore(n)}return t.focus}function Ah(){return null}function Ch(t){const e=t.getSelectedElement();return e&&function(t){return!!t.getCustomProperty("image")&&kh(t)}(e)?e:null}function Th(t){return!!t&&t.is("image")}function Ph(t,e,i={}){const n=t.createElement("image",i),o=xh(e.document.selection,e);e.insertContent(n,o),n.parent&&t.setSelection(n,"on")}function Sh(t){const e=t.schema,i=t.document.selection;return function(t,e,i){const n=function(t,e){const i=xh(t,e).parent;if(i.isEmpty&&!i.is("$root"))return i.parent;return i}(t,i);return e.checkChild(n,"image")}(i,e,t)&&!function(t,e){const i=t.getSelectedElement();return i&&e.isObject(i)}(i,e)&&function(t){return[...t.focus.getAncestors()].every(t=>!t.is("image"))}(i)}class Eh extends Jl{refresh(){this.isEnabled=Sh(this.editor.model)}execute(t){const e=this.editor.model;e.change(i=>{const n=Array.isArray(t.source)?t.source:[t.source];for(const t of n)Ph(i,e,{src:t})})}}class Mh extends ql{static get pluginName(){return"ImageEditing"}init(){const t=this.editor,e=t.model.schema,i=t.t,n=t.conversion;t.editing.view.addObserver(fh),e.register("image",{isObject:!0,isBlock:!0,allowWhere:"$block",allowAttributes:["alt","src","srcset"]}),n.for("dataDowncast").elementToElement({model:"image",view:(t,e)=>Ih(e)}),n.for("editingDowncast").elementToElement({model:"image",view:(t,e)=>{return n=Ih(e),o=e,s=i("s"),o.setCustomProperty("image",!0,n),_h(n,o,{label:function(){const t=n.getChild(0).getAttribute("alt");return t?`${t} ${s}`:s}});var n,o,s}}),n.for("downcast").add(mh("src")).add(mh("alt")).add(function(){return e=>{e.on("attribute:srcset:image",t)};function t(t,e,i){if(!i.consumable.consume(e.item,t.name))return;const n=i.writer,o=i.mapper.toViewElement(e.item).getChild(0);if(null===e.attributeNewValue){const t=e.attributeOldValue;t.data&&(n.removeAttribute("srcset",o),n.removeAttribute("sizes",o),t.width&&n.removeAttribute("width",o))}else{const t=e.attributeNewValue;t.data&&(n.setAttribute("srcset",t.data,o),n.setAttribute("sizes","100vw",o),t.width&&n.setAttribute("width",t.width,o))}}}()),n.for("upcast").elementToElement({view:{name:"img",attributes:{src:!0}},model:(t,e)=>e.createElement("image",{src:t.getAttribute("src")})}).attributeToAttribute({view:{name:"img",key:"alt"},model:"alt"}).attributeToAttribute({view:{name:"img",key:"srcset"},model:{key:"srcset",value:t=>{const e={data:t.getAttribute("srcset")};return t.hasAttribute("width")&&(e.width=t.getAttribute("width")),e}}}).add(function(){return e=>{e.on("element:figure",t)};function t(t,e,i){if(!i.consumable.test(e.viewItem,{name:!0,classes:"image"}))return;const n=Array.from(e.viewItem.getChildren()).find(t=>t.is("img"));if(!n||!n.hasAttribute("src")||!i.consumable.test(n,{name:!0}))return;const o=i.convertItem(n,e.modelCursor),s=sh(o.modelRange.getItems());s&&(i.convertChildren(e.viewItem,i.writer.createPositionAt(s,0)),e.modelRange=o.modelRange,e.modelCursor=o.modelCursor)}}()),t.commands.add("imageInsert",new Eh(t))}}function Ih(t){const e=t.createEmptyElement("img"),i=t.createContainerElement("figure",{class:"image"});return t.insert(t.createPositionAt(i,0),e),i}function Nh(t,e,i){return i.createRange(Oh(t,e,!0,i),Oh(t,e,!1,i))}function Oh(t,e,i,n){let o=t.textNode||(i?t.nodeBefore:t.nodeAfter),s=null;for(;o&&o.getAttribute("linkHref")==e;)s=o,o=i?o.previousSibling:o.nextSibling;return s?n.createPositionAt(s,i?"before":"after"):t}class Rh extends Jl{constructor(t){super(t),this.manualDecorators=new yi}restoreManualDecoratorStates(){for(const t of this.manualDecorators)t.value=this._getDecoratorStateFromModel(t.id)}refresh(){const t=this.editor.model,e=t.document;this.value=e.selection.getAttribute("linkHref");for(const t of this.manualDecorators)t.value=this._getDecoratorStateFromModel(t.id);this.isEnabled=t.schema.checkAttributeInSelection(e.selection,"linkHref")}execute(t,e={}){const i=this.editor.model,n=i.document.selection,o=[],s=[];for(const t in e)e[t]?o.push(t):s.push(t);i.change(e=>{if(n.isCollapsed){const r=n.getFirstPosition();if(n.hasAttribute("linkHref")){const a=Nh(r,n.getAttribute("linkHref"),i);e.setAttribute("linkHref",t,a),o.forEach(t=>{e.setAttribute(t,!0,a)}),s.forEach(t=>{e.removeAttribute(t,a)}),e.setSelection(a)}else if(""!==t){const s=Li(n.getAttributes());s.set("linkHref",t),o.forEach(t=>{s.set(t,!0)});const a=e.createText(t,s);i.insertContent(a,r),e.setSelection(e.createRangeOn(a))}}else{const r=i.schema.getValidRanges(n.getRanges(),"linkHref");for(const i of r)e.setAttribute("linkHref",t,i),o.forEach(t=>{e.setAttribute(t,!0,i)}),s.forEach(t=>{e.removeAttribute(t,i)})}})}_getDecoratorStateFromModel(t){return this.editor.model.document.selection.getAttribute(t)||!1}}class Lh extends Jl{refresh(){this.isEnabled=this.editor.model.document.selection.hasAttribute("linkHref")}execute(){const t=this.editor,e=this.editor.model,i=e.document.selection,n=t.commands.get("link");e.change(t=>{const o=i.isCollapsed?[Nh(i.getFirstPosition(),i.getAttribute("linkHref"),e)]:i.getRanges();for(const e of o)if(t.removeAttribute("linkHref",e),n)for(const i of n.manualDecorators)t.removeAttribute(i.id,e)})}}var Dh=function(t,e,i){var n=t.length;return i=void 0===i?n:i,!e&&i>=n?t:nn(t,e,i)},zh=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]");var jh=function(t){return zh.test(t)};var Vh=function(t){return t.split("")},Bh="[\\ud800-\\udfff]",Fh="[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]",Hh="\\ud83c[\\udffb-\\udfff]",Uh="[^\\ud800-\\udfff]",Wh="(?:\\ud83c[\\udde6-\\uddff]){2}",qh="[\\ud800-\\udbff][\\udc00-\\udfff]",$h="(?:"+Fh+"|"+Hh+")"+"?",Yh="[\\ufe0e\\ufe0f]?"+$h+("(?:\\u200d(?:"+[Uh,Wh,qh].join("|")+")[\\ufe0e\\ufe0f]?"+$h+")*"),Gh="(?:"+[Uh+Fh+"?",Fh,Wh,qh,Bh].join("|")+")",Qh=RegExp(Hh+"(?="+Hh+")|"+Gh+Yh,"g");var Kh=function(t){return t.match(Qh)||[]};var Jh=function(t){return jh(t)?Kh(t):Vh(t)};var Zh=function(t){return function(e){e=Ji(e);var i=jh(e)?Jh(e):void 0,n=i?i[0]:e.charAt(0),o=i?Dh(i,1).join(""):e.slice(1);return n[t]()+o}}("toUpperCase");const Xh=/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g,tu=/^(?:(?:https?|ftps?|mailto):|[^a-z]|[a-z+.-]+(?:[^a-z+.:-]|$))/i;function eu(t,e){const i=e.createAttributeElement("a",{href:t},{priority:5});return e.setCustomProperty("link",!0,i),i}function iu(t){return function(t){return t.replace(Xh,"").match(tu)}(t=String(t))?t:"#"}class nu{constructor(){this._definitions=new Set}get length(){return this._definitions.size}add(t){Array.isArray(t)?t.forEach(t=>this._definitions.add(t)):this._definitions.add(t)}getDispatcher(){return t=>{t.on("attribute:linkHref",(t,e,i)=>{if(!i.consumable.test(e.item,"attribute:linkHref"))return;const n=i.writer,o=n.document.selection;for(const t of this._definitions){const s=n.createAttributeElement("a",t.attributes,{priority:5});n.setCustomProperty("link",!0,s),t.callback(e.attributeNewValue)?e.item.is("selection")?n.wrap(o.getFirstRange(),s):n.wrap(i.mapper.toViewRange(e.range),s):n.unwrap(i.mapper.toViewRange(e.range),s)}},{priority:"high"})}}}class ou{constructor({id:t,label:e,attributes:i}){this.id=t,this.set("value"),this.label=e,this.attributes=i}}vi(ou,Hn);class su{constructor(t,e,i){this.model=t,this.attribute=i,this._modelSelection=t.document.selection,this._overrideUid=null,this._isNextGravityRestorationSkipped=!1,e.listenTo(this._modelSelection,"change:range",(t,e)=>{this._isNextGravityRestorationSkipped?this._isNextGravityRestorationSkipped=!1:this._isGravityOverridden&&(!e.directChange&&ru(this._modelSelection.getFirstPosition(),i)||this._restoreGravity())})}handleForwardMovement(t,e){const i=this.attribute;if(!(this._isGravityOverridden||t.isAtStart&&this._hasSelectionAttribute))return lu(t,i)&&this._hasSelectionAttribute?(this._preventCaretMovement(e),this._removeSelectionAttribute(),!0):au(t,i)||cu(t,i)&&this._hasSelectionAttribute?(this._preventCaretMovement(e),this._overrideGravity(),!0):void 0}handleBackwardMovement(t,e){const i=this.attribute;return this._isGravityOverridden?lu(t,i)&&this._hasSelectionAttribute?(this._preventCaretMovement(e),this._restoreGravity(),this._removeSelectionAttribute(),!0):(this._preventCaretMovement(e),this._restoreGravity(),t.isAtStart&&this._removeSelectionAttribute(),!0):lu(t,i)&&!this._hasSelectionAttribute?(this._preventCaretMovement(e),this._setSelectionAttributeFromTheNodeBefore(t),!0):t.isAtEnd&&cu(t,i)?this._hasSelectionAttribute?void(du(t,i)&&(this._skipNextAutomaticGravityRestoration(),this._overrideGravity())):(this._preventCaretMovement(e),this._setSelectionAttributeFromTheNodeBefore(t),!0):t.isAtStart?this._hasSelectionAttribute?(this._removeSelectionAttribute(),this._preventCaretMovement(e),!0):void 0:void(du(t,i)&&(this._skipNextAutomaticGravityRestoration(),this._overrideGravity()))}get _isGravityOverridden(){return!!this._overrideUid}get _hasSelectionAttribute(){return this._modelSelection.hasAttribute(this.attribute)}_overrideGravity(){this._overrideUid=this.model.change(t=>t.overrideSelectionGravity())}_restoreGravity(){this.model.change(t=>{t.restoreSelectionGravity(this._overrideUid),this._overrideUid=null})}_preventCaretMovement(t){t.preventDefault()}_removeSelectionAttribute(){this.model.change(t=>{t.removeSelectionAttribute(this.attribute)})}_setSelectionAttributeFromTheNodeBefore(t){const e=this.attribute;this.model.change(i=>{i.setSelectionAttribute(this.attribute,t.nodeBefore.getAttribute(e))})}_skipNextAutomaticGravityRestoration(){this._isNextGravityRestorationSkipped=!0}}function ru(t,e){return au(t,e)||cu(t,e)}function au(t,e){const{nodeBefore:i,nodeAfter:n}=t,o=!!i&&i.hasAttribute(e);return!!n&&n.hasAttribute(e)&&(!o||i.getAttribute(e)!==n.getAttribute(e))}function cu(t,e){const{nodeBefore:i,nodeAfter:n}=t,o=!!i&&i.hasAttribute(e),s=!!n&&n.hasAttribute(e);return o&&(!s||i.getAttribute(e)!==n.getAttribute(e))}function lu(t,e){const{nodeBefore:i,nodeAfter:n}=t,o=!!i&&i.hasAttribute(e);if(!!n&&n.hasAttribute(e)&&o)return n.getAttribute(e)!==i.getAttribute(e)}function du(t,e){return ru(t.getShiftedBy(-1),e)}i(46);const hu=/^(https?:)?\/\//;class uu extends ql{static get pluginName(){return"LinkEditing"}constructor(t){super(t),t.config.define("link",{addTargetToExternalLinks:!1})}init(){const t=this.editor,e=t.locale;t.model.schema.extend("$text",{allowAttributes:"linkHref"}),t.conversion.for("dataDowncast").attributeToElement({model:"linkHref",view:eu}),t.conversion.for("editingDowncast").attributeToElement({model:"linkHref",view:(t,e)=>eu(iu(t),e)}),t.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{href:!0}},model:{key:"linkHref",value:t=>t.getAttribute("href")}}),t.commands.add("link",new Rh(t)),t.commands.add("unlink",new Lh(t));const i=function(t,e){const i={"Open in a new tab":t("dg"),Downloadable:t("dh")};return e.forEach(t=>(t.label&&i[t.label]&&(t.label=i[t.label]),t)),e}(t.t,function(t){const e=[];if(t)for(const[i,n]of Object.entries(t)){const t=Object.assign({},n,{id:`link${Zh(i)}`});e.push(t)}return e}(t.config.get("link.decorators")));this._enableAutomaticDecorators(i.filter(t=>"automatic"===t.mode)),this._enableManualDecorators(i.filter(t=>"manual"===t.mode)),function({view:t,model:e,emitter:i,attribute:n,locale:o}){const s=new su(e,i,n),r=e.document.selection;i.listenTo(t.document,"keydown",(t,e)=>{if(!r.isCollapsed)return;if(e.shiftKey||e.altKey||e.ctrlKey)return;const i=e.keyCode==po.arrowright,n=e.keyCode==po.arrowleft;if(!i&&!n)return;const a=r.getFirstPosition(),c=o.contentLanguageDirection;let l;l="ltr"===c&&i||"rtl"===c&&n?s.handleForwardMovement(a,e):s.handleBackwardMovement(a,e),l&&t.stop()},{priority:di.get("high")+1})}({view:t.editing.view,model:t.model,emitter:this,attribute:"linkHref",locale:e}),this._setupLinkHighlight()}_enableAutomaticDecorators(t){const e=this.editor,i=new nu;e.config.get("link.addTargetToExternalLinks")&&i.add({id:"linkIsExternal",mode:"automatic",callback:t=>hu.test(t),attributes:{target:"_blank",rel:"noopener noreferrer"}}),i.add(t),i.length&&e.conversion.for("downcast").add(i.getDispatcher())}_enableManualDecorators(t){if(!t.length)return;const e=this.editor,i=e.commands.get("link").manualDecorators;t.forEach(t=>{e.model.schema.extend("$text",{allowAttributes:t.id}),i.add(new ou(t)),e.conversion.for("downcast").attributeToElement({model:t.id,view:(e,n)=>{if(e){const e=i.get(t.id).attributes,o=n.createAttributeElement("a",e,{priority:5});return n.setCustomProperty("link",!0,o),o}}}),e.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:i.get(t.id).attributes},model:{key:t.id}})})}_setupLinkHighlight(){const t=this.editor,e=t.editing.view,i=new Set;e.document.registerPostFixer(e=>{const n=t.model.document.selection;let o=!1;if(n.hasAttribute("linkHref")){const s=Nh(n.getFirstPosition(),n.getAttribute("linkHref"),t.model),r=t.editing.mapper.toViewRange(s);for(const t of r.getItems())t.is("a")&&!t.hasClass("ck-link_selected")&&(e.addClass("ck-link_selected",t),i.add(t),o=!0)}return o}),t.conversion.for("editingDowncast").add(t=>{function n(){e.change(t=>{for(const e of i.values())t.removeClass("ck-link_selected",e),i.delete(e)})}t.on("insert",n,{priority:"highest"}),t.on("remove",n,{priority:"highest"}),t.on("attribute",n,{priority:"highest"}),t.on("selection",n,{priority:"highest"})})}}class fu extends Hd{static get pluginName(){return"Notification"}init(){this.on("show:warning",(t,e)=>{window.alert(e.message)},{priority:"lowest"})}showSuccess(t,e={}){this._showNotification({message:t,type:"success",namespace:e.namespace,title:e.title})}showInfo(t,e={}){this._showNotification({message:t,type:"info",namespace:e.namespace,title:e.title})}showWarning(t,e={}){this._showNotification({message:t,type:"warning",namespace:e.namespace,title:e.title})}_showNotification(t){const e=`show:${t.type}`+(t.namespace?`:${t.namespace}`:"");this.fire(e,{message:t.message,type:t.type,title:t.title||""})}}class mu extends Jl{constructor(t){super(t),this.stopListening(this.editor.model.document,"change"),this.listenTo(this.editor.model.document,"change",()=>this.refresh(),{priority:"low"})}refresh(){const t=this.editor.commands.get("imageInsert"),e=this.editor.commands.get("link");this.isEnabled=t.isEnabled||e.isEnabled}execute(){const t=this.editor,e=this.editor.config.get("ckfinder.openerMethod")||"modal";if("popup"!=e&&"modal"!=e)throw new hi.b('ckfinder-unknown-openerMethod: The openerMethod config option must by "popup" or "modal".',t);const i=this.editor.config.get("ckfinder.options")||{};i.chooseFiles=!0;const n=i.onInit;i.language||(i.language=t.locale.uiLanguage),i.onInit=e=>{n&&n(e),e.on("files:choose",i=>{const n=i.data.files.toArray(),o=n.filter(t=>!t.isImage()),s=n.filter(t=>t.isImage());for(const e of o)t.execute("link",e.getUrl());const r=[];for(const t of s){const i=t.getUrl();r.push(i||e.request("file:getProxyUrl",{file:t}))}r.length&&gu(t,r)}),e.on("file:choose:resizedImage",e=>{const i=e.data.resizedUrl;if(i)gu(t,[i]);else{const e=t.plugins.get("Notification"),i=t.locale.t;e.showWarning(i("bj"),{title:i("bk"),namespace:"ckfinder"})}})},window.CKFinder[e](i)}}function gu(t,e){if(t.commands.get("imageInsert").isEnabled)t.execute("imageInsert",{source:e});else{const e=t.plugins.get("Notification"),i=t.locale.t;e.showWarning(i("bl"),{title:i("bm"),namespace:"ckfinder"})}}class pu extends ql{static get pluginName(){return"CKFinderEditing"}static get requires(){return[fu,Mh,uu]}init(){const t=this.editor;t.commands.add("ckfinder",new mu(t))}}const bu=/^data:(\S*?);base64,/;class wu{constructor(t,e,i){if(!t)throw new hi.b("fileuploader-missing-file: File must be provided as the first argument",null);if(!e)throw new hi.b("fileuploader-missing-token: Token must be provided as the second argument.",null);if(!i)throw new hi.b("fileuploader-missing-api-address: Api address must be provided as the third argument.",null);this.file=function(t){if("string"!=typeof t)return!1;const e=t.match(bu);return!(!e||!e.length)}(t)?function(t,e=512){try{const i=t.match(bu)[1],n=atob(t.replace(bu,"")),o=[];for(let t=0;t<n.length;t+=e){const i=n.slice(t,t+e),s=new Array(i.length);for(let t=0;t<i.length;t++)s[t]=i.charCodeAt(t);o.push(new Uint8Array(s))}return new Blob(o,{type:i})}catch(t){throw new hi.b("fileuploader-decoding-image-data-error: Problem with decoding Base64 image data.",null)}}(t):t,this._token=e,this._apiAddress=i}onProgress(t){return this.on("progress",(e,i)=>t(i)),this}onError(t){return this.once("error",(e,i)=>t(i)),this}abort(){this.xhr.abort()}send(){return this._prepareRequest(),this._attachXHRListeners(),this._sendRequest()}_prepareRequest(){const t=new XMLHttpRequest;t.open("POST",this._apiAddress),t.setRequestHeader("Authorization",this._token.value),t.responseType="json",this.xhr=t}_attachXHRListeners(){const t=this,e=this.xhr;function i(e){return()=>t.fire("error",e)}e.addEventListener("error",i("Network Error")),e.addEventListener("abort",i("Abort")),e.upload&&e.upload.addEventListener("progress",t=>{t.lengthComputable&&this.fire("progress",{total:t.total,uploaded:t.loaded})}),e.addEventListener("load",()=>{const t=e.status,i=e.response;if(t<200||t>299)return this.fire("error",i.message||i.error)})}_sendRequest(){const t=new FormData,e=this.xhr;return t.append("file",this.file),new Promise((i,n)=>{e.addEventListener("load",()=>{const t=e.status,o=e.response;return t<200||t>299?o.message?n(new hi.b("fileuploader-uploading-data-failed: Uploading file failed.",this,{message:o.message})):n(o.error):i(o)}),e.addEventListener("error",()=>n(new Error("Network Error"))),e.addEventListener("abort",()=>n(new Error("Abort"))),e.send(t)})}}vi(wu,mi);const ku={refreshInterval:36e5,autoRefresh:!0};class _u{constructor(t,e=ku){if(!t)throw new hi.b("token-missing-token-url: A `tokenUrl` must be provided as the first constructor argument.",this);this.set("value",e.initValue),this._refresh="function"==typeof t?t:()=>{return e=t,new Promise((t,i)=>{const n=new XMLHttpRequest;n.open("GET",e),n.addEventListener("load",()=>{const e=n.status,o=n.response;return e<200||e>299?i(new hi.b("token-cannot-download-new-token: Cannot download new token from the provided url.",null)):t(o)}),n.addEventListener("error",()=>i(new Error("Network Error"))),n.addEventListener("abort",()=>i(new Error("Abort"))),n.send()});var e},this._options=Object.assign({},ku,e)}init(){return new Promise((t,e)=>{this._options.autoRefresh&&this._startRefreshing(),this.value?t(this):this._refreshToken().then(t).catch(e)})}_refreshToken(){return this._refresh().then(t=>this.set("value",t)).then(()=>this)}destroy(){this._stopRefreshing()}_startRefreshing(){this._refreshInterval=setInterval(()=>this._refreshToken(),this._options.refreshInterval)}_stopRefreshing(){clearInterval(this._refreshInterval)}static create(t,e=ku){return new _u(t,e).init()}}vi(_u,Hn);var vu=_u;class yu extends Hd{static get pluginName(){return"CloudServices"}init(){const t=this.context.config.get("cloudServices")||{};for(const e in t)this[e]=t[e];if(this.tokenUrl)return this.token=new yu.Token(this.tokenUrl),this.token.init();this.token=null}}yu.Token=vu;class xu extends ql{static get requires(){return[qd,yu]}init(){const t=this.editor,e=t.plugins.get(yu),i=e.token,n=e.uploadUrl;i&&(this._uploadGateway=new xu._UploadGateway(i,n),t.plugins.get(qd).createUploadAdapter=t=>new Au(this._uploadGateway,t))}}class Au{constructor(t,e){this.uploadGateway=t,this.loader=e}upload(){return this.loader.file.then(t=>(this.fileUploader=this.uploadGateway.upload(t),this.fileUploader.on("progress",(t,e)=>{this.loader.uploadTotal=e.total,this.loader.uploaded=e.uploaded}),this.fileUploader.send()))}abort(){this.fileUploader.abort()}}xu._UploadGateway=class{constructor(t,e){if(!t)throw new hi.b("uploadgateway-missing-token: Token must be provided.",null);if(!e)throw new hi.b("uploadgateway-missing-api-address: Api address must be provided.",null);this._token=t,this._apiAddress=e}upload(t){return new wu(t,this._token,this._apiAddress)}};class Cu extends Os{constructor(t){super(t),this.domEventType="mousedown"}onDomEvent(t){this.fire(t.type,t)}}i(48);const Tu=wo("Ctrl+A");class Pu extends ql{static get pluginName(){return"Widget"}init(){const t=this.editor.editing.view,e=t.document;this._previouslySelected=new Set,this.editor.editing.downcastDispatcher.on("selection",(t,e,i)=>{this._clearPreviouslySelectedWidgets(i.writer);const n=i.writer,o=n.document.selection,s=o.getSelectedElement();let r=null;for(const t of o.getRanges())for(const e of t){const t=e.item;kh(t)&&!Su(t,r)&&(n.addClass("ck-widget_selected",t),this._previouslySelected.add(t),r=t,t==s&&n.setSelection(o.getRanges(),{fake:!0,label:vh(s)}))}},{priority:"low"}),t.addObserver(Cu),this.listenTo(e,"mousedown",(...t)=>this._onMousedown(...t)),this.listenTo(e,"keydown",(...t)=>this._onKeydown(...t),{priority:"high"}),this.listenTo(e,"delete",(t,e)=>{this._handleDelete("forward"==e.direction)&&(e.preventDefault(),t.stop())},{priority:"high"})}_onMousedown(t,e){const i=this.editor,n=i.editing.view,o=n.document;let s=e.target;if(function(t){for(;t;){if(t.is("editableElement")&&!t.is("rootElement"))return!0;if(kh(t))return!1;t=t.parent}return!1}(s)){if(fo.isSafari&&e.domEvent.detail>=3){const t=i.editing.mapper.toModelElement(s);this.editor.model.change(i=>{e.preventDefault(),i.setSelection(t,"in")})}return}if(!kh(s)&&(s=s.findAncestor(kh),!s))return;e.preventDefault(),o.isFocused||n.focus();const r=i.editing.mapper.toModelElement(s);this._setSelectionOverElement(r)}_onKeydown(t,e){const i=e.keyCode,n="ltr"===this.editor.locale.contentLanguageDirection,o=i==po.arrowdown||i==po[n?"arrowright":"arrowleft"];let s=!1;!function(t){return t==po.arrowright||t==po.arrowleft||t==po.arrowup||t==po.arrowdown}(i)?!function(t){return bo(t)==Tu}(e)?i===po.enter&&(s=this._handleEnterKey(e.shiftKey)):s=this._selectAllNestedEditableContent()||this._selectAllContent():s=this._handleArrowKeys(o),s&&(e.preventDefault(),t.stop())}_handleDelete(t){if(this.editor.isReadOnly)return;const e=this.editor.model.document.selection;if(!e.isCollapsed)return;const i=this._getObjectElementNextToSelection(t);return i?(this.editor.model.change(t=>{let n=e.anchor.parent;for(;n.isEmpty;){const e=n;n=e.parent,t.remove(e)}this._setSelectionOverElement(i)}),!0):void 0}_handleArrowKeys(t){const e=this.editor.model,i=e.schema,n=e.document.selection,o=n.getSelectedElement();if(o&&i.isObject(o)){const o=t?n.getLastPosition():n.getFirstPosition(),s=i.getNearestSelectionRange(o,t?"forward":"backward");return s&&e.change(t=>{t.setSelection(s)}),!0}if(!n.isCollapsed)return;const s=this._getObjectElementNextToSelection(t);return s&&i.isObject(s)?(this._setSelectionOverElement(s),!0):void 0}_handleEnterKey(t){const e=this.editor.model,i=e.document.selection.getSelectedElement();if(n=i,o=e.schema,n&&o.isObject(n)&&!o.isInline(n))return e.change(n=>{let o=n.createPositionAt(i,t?"before":"after");const s=n.createElement("paragraph");if(e.schema.isBlock(i.parent)){const t=e.schema.findAllowedParent(o,s);o=n.split(o,t).position}n.insert(s,o),n.setSelection(s,"in")}),!0;var n,o}_selectAllNestedEditableContent(){const t=this.editor.model,e=t.document.selection,i=t.schema.getLimitElement(e);return e.getFirstRange().root!=i&&(t.change(t=>{t.setSelection(t.createRangeIn(i))}),!0)}_selectAllContent(){const t=this.editor.model,e=this.editor.editing,i=e.view.document.selection.getSelectedElement();if(i&&kh(i)){const n=e.mapper.toModelElement(i.parent);return t.change(t=>{t.setSelection(t.createRangeIn(n))}),!0}return!1}_setSelectionOverElement(t){this.editor.model.change(e=>{e.setSelection(e.createRangeOn(t))})}_getObjectElementNextToSelection(t){const e=this.editor.model,i=e.schema,n=e.document.selection,o=e.createSelection(n);e.modifySelection(o,{direction:t?"forward":"backward"});const s=t?o.focus.nodeBefore:o.focus.nodeAfter;return s&&i.isObject(s)?s:null}_clearPreviouslySelectedWidgets(t){for(const e of this._previouslySelected)t.removeClass("ck-widget_selected",e);this._previouslySelected.clear()}}function Su(t,e){return!!e&&Array.from(t.getAncestors()).includes(e)}class Eu extends Jl{refresh(){const t=this.editor.model.document.selection.getSelectedElement();this.isEnabled=Th(t),Th(t)&&t.hasAttribute("alt")?this.value=t.getAttribute("alt"):this.value=!1}execute(t){const e=this.editor.model,i=e.document.selection.getSelectedElement();e.change(e=>{e.setAttribute("alt",t.newValue,i)})}}class Mu extends ql{static get pluginName(){return"ImageTextAlternativeEditing"}init(){this.editor.commands.add("imageTextAlternative",new Eu(this.editor))}}i(50);class Iu extends rl{constructor(t,e){super(t);const i=`ck-input-${li()}`,n=`ck-status-${li()}`;this.set("label"),this.set("value"),this.set("isReadOnly",!1),this.set("errorText",null),this.set("infoText",null),this.labelView=this._createLabelView(i),this.inputView=this._createInputView(e,i,n),this.statusView=this._createStatusView(n),this.bind("_statusText").to(this,"errorText",this,"infoText",(t,e)=>t||e);const o=this.bindTemplate;this.setTemplate({tag:"div",attributes:{class:["ck","ck-labeled-input",o.if("isReadOnly","ck-disabled")]},children:[this.labelView,this.inputView,this.statusView]})}_createLabelView(t){const e=new dl(this.locale);return e.for=t,e.bind("text").to(this,"label"),e}_createInputView(t,e,i){const n=new t(this.locale,i);return n.id=e,n.ariaDescribedById=i,n.bind("value").to(this),n.bind("isReadOnly").to(this),n.bind("hasError").to(this,"errorText",t=>!!t),n.on("input",()=>{this.errorText=null}),n}_createStatusView(t){const e=new rl(this.locale),i=this.bindTemplate;return e.setTemplate({tag:"div",attributes:{class:["ck","ck-labeled-input__status",i.if("errorText","ck-labeled-input__status_error"),i.if("_statusText","ck-hidden",t=>!t)],id:t,role:i.if("errorText","alert")},children:[{text:i.to("_statusText")}]}),e}select(){this.inputView.select()}focus(){this.inputView.focus()}}i(52);class Nu extends rl{constructor(t){super(t),this.set("value"),this.set("id"),this.set("placeholder"),this.set("isReadOnly",!1),this.set("hasError",!1),this.set("ariaDescribedById");const e=this.bindTemplate;this.setTemplate({tag:"input",attributes:{type:"text",class:["ck","ck-input","ck-input-text",e.if("hasError","ck-error")],id:e.to("id"),placeholder:e.to("placeholder"),readonly:e.to("isReadOnly"),"aria-invalid":e.if("hasError",!0),"aria-describedby":e.to("ariaDescribedById")},on:{input:e.to("input")}})}render(){super.render();const t=t=>{this.element.value=t||0===t?t:""};t(this.value),this.on("change:value",(e,i,n)=>{t(n)})}select(){this.element.select()}focus(){this.element.focus()}}function Ou({view:t}){t.listenTo(t.element,"submit",(e,i)=>{i.preventDefault(),t.fire("submit")},{useCapture:!0})}var Ru='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.972 16.615a.997.997 0 01-.744-.292l-4.596-4.596a1 1 0 111.414-1.414l3.926 3.926 9.937-9.937a1 1 0 011.414 1.415L7.717 16.323a.997.997 0 01-.745.292z"/></svg>',Lu='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.591 10.177l4.243 4.242a1 1 0 01-1.415 1.415l-4.242-4.243-4.243 4.243a1 1 0 01-1.414-1.415l4.243-4.242L4.52 5.934A1 1 0 015.934 4.52l4.243 4.243 4.242-4.243a1 1 0 111.415 1.414l-4.243 4.243z"/></svg>';i(54);class Du extends rl{constructor(t){super(t);const e=this.locale.t;this.focusTracker=new Ic,this.keystrokes=new yc,this.labeledInput=this._createLabeledInputView(),this.saveButtonView=this._createButton(e("cf"),Ru,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton(e("cg"),Lu,"ck-button-cancel","cancel"),this._focusables=new Bc,this._focusCycler=new bl({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"form",attributes:{class:["ck","ck-text-alternative-form"],tabindex:"-1"},children:[this.labeledInput,this.saveButtonView,this.cancelButtonView]})}render(){super.render(),this.keystrokes.listenTo(this.element),Ou({view:this}),[this.labeledInput,this.saveButtonView,this.cancelButtonView].forEach(t=>{this._focusables.add(t),this.focusTracker.add(t.element)})}_createButton(t,e,i,n){const o=new El(this.locale);return o.set({label:t,icon:e,tooltip:!0}),o.extendTemplate({attributes:{class:i}}),n&&o.delegate("execute").to(this,n),o}_createLabeledInputView(){const t=this.locale.t,e=new Iu(this.locale,Nu);return e.label=t("cl"),e.inputView.placeholder=t("cl"),e}}i(56);const zu=ml("px"),ju=ts.document.body;class Vu extends rl{constructor(t){super(t);const e=this.bindTemplate;this.set("top",0),this.set("left",0),this.set("position","arrow_nw"),this.set("isVisible",!1),this.set("withArrow",!0),this.set("class"),this.content=this.createCollection(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-balloon-panel",e.to("position",t=>`ck-balloon-panel_${t}`),e.if("isVisible","ck-balloon-panel_visible"),e.if("withArrow","ck-balloon-panel_with-arrow"),e.to("class")],style:{top:e.to("top",zu),left:e.to("left",zu)}},children:this.content})}show(){this.isVisible=!0}hide(){this.isVisible=!1}attachTo(t){this.show();const e=Vu.defaultPositions,i=Object.assign({},{element:this.element,positions:[e.southArrowNorth,e.southArrowNorthWest,e.southArrowNorthEast,e.northArrowSouth,e.northArrowSouthWest,e.northArrowSouthEast],limiter:ju,fitInViewport:!0},t),n=Vu._getOptimalPosition(i),o=parseInt(n.left),s=parseInt(n.top),r=n.name;Object.assign(this,{top:s,left:o,position:r})}pin(t){this.unpin(),this._pinWhenIsVisibleCallback=()=>{this.isVisible?this._startPinning(t):this._stopPinning()},this._startPinning(t),this.listenTo(this,"change:isVisible",this._pinWhenIsVisibleCallback)}unpin(){this._pinWhenIsVisibleCallback&&(this._stopPinning(),this.stopListening(this,"change:isVisible",this._pinWhenIsVisibleCallback),this._pinWhenIsVisibleCallback=null,this.hide())}_startPinning(t){this.attachTo(t);const e=Bu(t.target),i=t.limiter?Bu(t.limiter):ju;this.listenTo(ts.document,"scroll",(n,o)=>{const s=o.target,r=e&&s.contains(e),a=i&&s.contains(i);!r&&!a&&e&&i||this.attachTo(t)},{useCapture:!0}),this.listenTo(ts.window,"resize",()=>{this.attachTo(t)})}_stopPinning(){this.stopListening(ts.document,"scroll"),this.stopListening(ts.window,"resize")}}function Bu(t){return ii(t)?t:Ks(t)?t.commonAncestorContainer:"function"==typeof t?Bu(t()):null}function Fu(t,e){return t.top-e.height-Vu.arrowVerticalOffset}function Hu(t){return t.bottom+Vu.arrowVerticalOffset}Vu.arrowHorizontalOffset=25,Vu.arrowVerticalOffset=10,Vu._getOptimalPosition=xl,Vu.defaultPositions={northArrowSouth:(t,e)=>({top:Fu(t,e),left:t.left+t.width/2-e.width/2,name:"arrow_s"}),northArrowSouthEast:(t,e)=>({top:Fu(t,e),left:t.left+t.width/2-e.width+Vu.arrowHorizontalOffset,name:"arrow_se"}),northArrowSouthWest:(t,e)=>({top:Fu(t,e),left:t.left+t.width/2-Vu.arrowHorizontalOffset,name:"arrow_sw"}),northWestArrowSouth:(t,e)=>({top:Fu(t,e),left:t.left-e.width/2,name:"arrow_s"}),northWestArrowSouthWest:(t,e)=>({top:Fu(t,e),left:t.left-Vu.arrowHorizontalOffset,name:"arrow_sw"}),northWestArrowSouthEast:(t,e)=>({top:Fu(t,e),left:t.left-e.width+Vu.arrowHorizontalOffset,name:"arrow_se"}),northEastArrowSouth:(t,e)=>({top:Fu(t,e),left:t.right-e.width/2,name:"arrow_s"}),northEastArrowSouthEast:(t,e)=>({top:Fu(t,e),left:t.right-e.width+Vu.arrowHorizontalOffset,name:"arrow_se"}),northEastArrowSouthWest:(t,e)=>({top:Fu(t,e),left:t.right-Vu.arrowHorizontalOffset,name:"arrow_sw"}),southArrowNorth:(t,e)=>({top:Hu(t),left:t.left+t.width/2-e.width/2,name:"arrow_n"}),southArrowNorthEast:(t,e)=>({top:Hu(t),left:t.left+t.width/2-e.width+Vu.arrowHorizontalOffset,name:"arrow_ne"}),southArrowNorthWest:(t,e)=>({top:Hu(t),left:t.left+t.width/2-Vu.arrowHorizontalOffset,name:"arrow_nw"}),southWestArrowNorth:(t,e)=>({top:Hu(t),left:t.left-e.width/2,name:"arrow_n"}),southWestArrowNorthWest:(t,e)=>({top:Hu(t),left:t.left-Vu.arrowHorizontalOffset,name:"arrow_nw"}),southWestArrowNorthEast:(t,e)=>({top:Hu(t),left:t.left-e.width+Vu.arrowHorizontalOffset,name:"arrow_ne"}),southEastArrowNorth:(t,e)=>({top:Hu(t),left:t.right-e.width/2,name:"arrow_n"}),southEastArrowNorthEast:(t,e)=>({top:Hu(t),left:t.right-e.width+Vu.arrowHorizontalOffset,name:"arrow_ne"}),southEastArrowNorthWest:(t,e)=>({top:Hu(t),left:t.right-Vu.arrowHorizontalOffset,name:"arrow_nw"})};i(58),i(60);const Uu=ml("px");class Wu extends ql{static get pluginName(){return"ContextualBalloon"}constructor(t){super(t),this.positionLimiter=()=>{const t=this.editor.editing.view,e=t.document.selection.editableElement;return e?t.domConverter.mapViewToDom(e.root):null},this.set("visibleView",null),this.view=new Vu(t.locale),t.ui.view.body.add(this.view),t.ui.focusTracker.add(this.view.element),this._viewToStack=new Map,this._idToStack=new Map,this.set("_numberOfStacks",0),this.set("_singleViewMode",!1),this._rotatorView=this._createRotatorView(),this._fakePanelsView=this._createFakePanelsView()}hasView(t){return Array.from(this._viewToStack.keys()).includes(t)}add(t){if(this.hasView(t.view))throw new hi.b("contextualballoon-add-view-exist: Cannot add configuration of the same view twice.",[this,t]);const e=t.stackId||"main";if(!this._idToStack.has(e))return this._idToStack.set(e,new Map([[t.view,t]])),this._viewToStack.set(t.view,this._idToStack.get(e)),this._numberOfStacks=this._idToStack.size,void(this._visibleStack&&!t.singleViewMode||this.showStack(e));const i=this._idToStack.get(e);t.singleViewMode&&this.showStack(e),i.set(t.view,t),this._viewToStack.set(t.view,i),i===this._visibleStack&&this._showView(t)}remove(t){if(!this.hasView(t))throw new hi.b("contextualballoon-remove-view-not-exist: Cannot remove the configuration of a non-existent view.",[this,t]);const e=this._viewToStack.get(t);this._singleViewMode&&this.visibleView===t&&(this._singleViewMode=!1),this.visibleView===t&&(1===e.size?this._idToStack.size>1?this._showNextStack():(this.view.hide(),this.visibleView=null,this._rotatorView.hideView()):this._showView(Array.from(e.values())[e.size-2])),1===e.size?(this._idToStack.delete(this._getStackId(e)),this._numberOfStacks=this._idToStack.size):e.delete(t),this._viewToStack.delete(t)}updatePosition(t){t&&(this._visibleStack.get(this.visibleView).position=t),this.view.pin(this._getBalloonPosition()),this._fakePanelsView.updatePosition()}showStack(t){this.visibleStack=t;const e=this._idToStack.get(t);if(!e)throw new hi.b("contextualballoon-showstack-stack-not-exist: Cannot show a stack that does not exist.",this);this._visibleStack!==e&&this._showView(Array.from(e.values()).pop())}get _visibleStack(){return this._viewToStack.get(this.visibleView)}_getStackId(t){return Array.from(this._idToStack.entries()).find(e=>e[1]===t)[0]}_showNextStack(){const t=Array.from(this._idToStack.values());let e=t.indexOf(this._visibleStack)+1;t[e]||(e=0),this.showStack(this._getStackId(t[e]))}_showPrevStack(){const t=Array.from(this._idToStack.values());let e=t.indexOf(this._visibleStack)-1;t[e]||(e=t.length-1),this.showStack(this._getStackId(t[e]))}_createRotatorView(){const t=new qu(this.editor.locale),e=this.editor.locale.t;return this.view.content.add(t),t.bind("isNavigationVisible").to(this,"_numberOfStacks",this,"_singleViewMode",(t,e)=>!e&&t>1),t.on("change:isNavigationVisible",()=>this.updatePosition(),{priority:"low"}),t.bind("counter").to(this,"visibleView",this,"_numberOfStacks",(t,i)=>{if(i<2)return"";const n=Array.from(this._idToStack.values()).indexOf(this._visibleStack)+1;return e("cm",[n,i])}),t.buttonNextView.on("execute",()=>{t.focusTracker.isFocused&&this.editor.editing.view.focus(),this._showNextStack()}),t.buttonPrevView.on("execute",()=>{t.focusTracker.isFocused&&this.editor.editing.view.focus(),this._showPrevStack()}),t}_createFakePanelsView(){const t=new $u(this.editor.locale,this.view);return t.bind("numberOfPanels").to(this,"_numberOfStacks",this,"_singleViewMode",(t,e)=>!e&&t>=2?Math.min(t-1,2):0),t.listenTo(this.view,"change:top",()=>t.updatePosition()),t.listenTo(this.view,"change:left",()=>t.updatePosition()),this.editor.ui.view.body.add(t),t}_showView({view:t,balloonClassName:e="",withArrow:i=!0,singleViewMode:n=!1}){this.view.class=e,this.view.withArrow=i,this._rotatorView.showView(t),this.visibleView=t,this.view.pin(this._getBalloonPosition()),this._fakePanelsView.updatePosition(),n&&(this._singleViewMode=!0)}_getBalloonPosition(){let t=Array.from(this._visibleStack.values()).pop().position;return t&&!t.limiter&&(t=Object.assign({},t,{limiter:this.positionLimiter})),t}}class qu extends rl{constructor(t){super(t);const e=t.t,i=this.bindTemplate;this.set("isNavigationVisible",!0),this.focusTracker=new Ic,this.buttonPrevView=this._createButtonView(e("cn"),'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.463 5.187a.888.888 0 111.254 1.255L9.16 10l3.557 3.557a.888.888 0 11-1.254 1.255L7.26 10.61a.888.888 0 01.16-1.382l4.043-4.042z"/></svg>'),this.buttonNextView=this._createButtonView(e("co"),'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M8.537 14.813a.888.888 0 11-1.254-1.255L10.84 10 7.283 6.442a.888.888 0 111.254-1.255L12.74 9.39a.888.888 0 01-.16 1.382l-4.043 4.042z"/></svg>'),this.content=this.createCollection(),this.setTemplate({tag:"div",attributes:{class:["ck","ck-balloon-rotator"],"z-index":"-1"},children:[{tag:"div",attributes:{class:["ck-balloon-rotator__navigation",i.to("isNavigationVisible",t=>t?"":"ck-hidden")]},children:[this.buttonPrevView,{tag:"span",attributes:{class:["ck-balloon-rotator__counter"]},children:[{text:i.to("counter")}]},this.buttonNextView]},{tag:"div",attributes:{class:"ck-balloon-rotator__content"},children:this.content}]})}render(){super.render(),this.focusTracker.add(this.element)}showView(t){this.hideView(),this.content.add(t)}hideView(){this.content.clear()}_createButtonView(t,e){const i=new El(this.locale);return i.set({label:t,icon:e,tooltip:!0}),i}}class $u extends rl{constructor(t,e){super(t);const i=this.bindTemplate;this.set("top",0),this.set("left",0),this.set("height",0),this.set("width",0),this.set("numberOfPanels",0),this.content=this.createCollection(),this._balloonPanelView=e,this.setTemplate({tag:"div",attributes:{class:["ck-fake-panel",i.to("numberOfPanels",t=>t?"":"ck-hidden")],style:{top:i.to("top",Uu),left:i.to("left",Uu),width:i.to("width",Uu),height:i.to("height",Uu)}},children:this.content}),this.on("change:numberOfPanels",(t,e,i,n)=>{i>n?this._addPanels(i-n):this._removePanels(n-i),this.updatePosition()})}_addPanels(t){for(;t--;){const t=new rl;t.setTemplate({tag:"div"}),this.content.add(t),this.registerChild(t)}}_removePanels(t){for(;t--;){const t=this.content.last;this.content.remove(t),this.deregisterChild(t),t.destroy()}}updatePosition(){if(this.numberOfPanels){const{top:t,left:e}=this._balloonPanelView,{width:i,height:n}=new Xs(this._balloonPanelView.element);Object.assign(this,{top:t,left:e,width:i,height:n})}}}function Yu(t){const e=t.editing.view,i=Vu.defaultPositions;return{target:e.domConverter.viewToDom(e.document.selection.getSelectedElement()),positions:[i.northArrowSouth,i.northArrowSouthWest,i.northArrowSouthEast,i.southArrowNorth,i.southArrowNorthWest,i.southArrowNorthEast]}}class Gu extends ql{static get requires(){return[Wu]}static get pluginName(){return"ImageTextAlternativeUI"}init(){this._createButton(),this._createForm()}destroy(){super.destroy(),this._form.destroy()}_createButton(){const t=this.editor,e=t.t;t.ui.componentFactory.add("imageTextAlternative",i=>{const n=t.commands.get("imageTextAlternative"),o=new El(i);return o.set({label:e("bi"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5.085 6.22L2.943 4.078a.75.75 0 111.06-1.06l2.592 2.59A11.094 11.094 0 0110 5.068c4.738 0 8.578 3.101 8.578 5.083 0 1.197-1.401 2.803-3.555 3.887l1.714 1.713a.75.75 0 01-.09 1.138.488.488 0 01-.15.084.75.75 0 01-.821-.16L6.17 7.304c-.258.11-.51.233-.757.365l6.239 6.24-.006.005.78.78c-.388.094-.78.166-1.174.215l-1.11-1.11h.011L4.55 8.197a7.2 7.2 0 00-.665.514l-.112.098 4.897 4.897-.005.006 1.276 1.276a10.164 10.164 0 01-1.477-.117l-.479-.479-.009.009-4.863-4.863-.022.031a2.563 2.563 0 00-.124.2c-.043.077-.08.158-.108.241a.534.534 0 00-.028.133.29.29 0 00.008.072.927.927 0 00.082.226c.067.133.145.26.234.379l3.242 3.365.025.01.59.623c-3.265-.918-5.59-3.155-5.59-4.668 0-1.194 1.448-2.838 3.663-3.93zm7.07.531a4.632 4.632 0 011.108 5.992l.345.344.046-.018a9.313 9.313 0 002-1.112c.256-.187.5-.392.727-.613.137-.134.27-.277.392-.431.072-.091.141-.185.203-.286.057-.093.107-.19.148-.292a.72.72 0 00.036-.12.29.29 0 00.008-.072.492.492 0 00-.028-.133.999.999 0 00-.036-.096 2.165 2.165 0 00-.071-.145 2.917 2.917 0 00-.125-.2 3.592 3.592 0 00-.263-.335 5.444 5.444 0 00-.53-.523 7.955 7.955 0 00-1.054-.768 9.766 9.766 0 00-1.879-.891c-.337-.118-.68-.219-1.027-.301zm-2.85.21l-.069.002a.508.508 0 00-.254.097.496.496 0 00-.104.679.498.498 0 00.326.199l.045.005c.091.003.181.003.272.012a2.45 2.45 0 012.017 1.513c.024.061.043.125.069.185a.494.494 0 00.45.287h.008a.496.496 0 00.35-.158.482.482 0 00.13-.335.638.638 0 00-.048-.219 3.379 3.379 0 00-.36-.723 3.438 3.438 0 00-2.791-1.543l-.028-.001h-.013z"/></svg>',tooltip:!0}),o.bind("isEnabled").to(n,"isEnabled"),this.listenTo(o,"execute",()=>{this._showForm()}),o})}_createForm(){const t=this.editor,e=t.editing.view.document;this._balloon=this.editor.plugins.get("ContextualBalloon"),this._form=new Du(t.locale),this._form.render(),this.listenTo(this._form,"submit",()=>{t.execute("imageTextAlternative",{newValue:this._form.labeledInput.inputView.element.value}),this._hideForm(!0)}),this.listenTo(this._form,"cancel",()=>{this._hideForm(!0)}),this._form.keystrokes.set("Esc",(t,e)=>{this._hideForm(!0),e()}),this.listenTo(t.ui,"update",()=>{Ch(e.selection)?this._isVisible&&function(t){const e=t.plugins.get("ContextualBalloon");if(Ch(t.editing.view.document.selection)){const i=Yu(t);e.updatePosition(i)}}(t):this._hideForm(!0)}),Ll({emitter:this._form,activator:()=>this._isVisible,contextElements:[this._balloon.view.element],callback:()=>this._hideForm()})}_showForm(){if(this._isVisible)return;const t=this.editor,e=t.commands.get("imageTextAlternative"),i=this._form.labeledInput;this._isInBalloon||this._balloon.add({view:this._form,position:Yu(t)}),i.value=i.inputView.element.value=e.value||"",this._form.labeledInput.select()}_hideForm(t){this._isInBalloon&&(this._form.focusTracker.isFocused&&this._form.saveButtonView.focus(),this._balloon.remove(this._form),t&&this.editor.editing.view.focus())}get _isVisible(){return this._balloon.visibleView===this._form}get _isInBalloon(){return this._balloon.hasView(this._form)}}class Qu extends ql{static get requires(){return[Mu,Gu]}static get pluginName(){return"ImageTextAlternative"}}i(62);class Ku extends ql{static get requires(){return[Mh,Pu,Qu]}static get pluginName(){return"Image"}}class Ju extends rl{constructor(t){super(t),this.buttonView=new El(t),this._fileInputView=new Zu(t),this._fileInputView.bind("acceptedType").to(this),this._fileInputView.bind("allowMultipleFiles").to(this),this._fileInputView.delegate("done").to(this),this.setTemplate({tag:"span",attributes:{class:"ck-file-dialog-button"},children:[this.buttonView,this._fileInputView]}),this.buttonView.on("execute",()=>{this._fileInputView.open()})}focus(){this.buttonView.focus()}}class Zu extends rl{constructor(t){super(t),this.set("acceptedType"),this.set("allowMultipleFiles",!1);const e=this.bindTemplate;this.setTemplate({tag:"input",attributes:{class:["ck-hidden"],type:"file",tabindex:"-1",accept:e.to("acceptedType"),multiple:e.to("allowMultipleFiles")},on:{change:e.to(()=>{this.element&&this.element.files&&this.element.files.length&&this.fire("done",this.element.files),this.element.value=""})}})}open(){this.element.click()}}function Xu(t){const e=t.map(t=>t.replace("+","\\+"));return new RegExp(`^image\\/(${e.join("|")})$`)}function tf(t){return new Promise((e,i)=>{const n=t.getAttribute("src");fetch(n).then(t=>t.blob()).then(t=>{const o=function(t,e){return t.type?t.type:e.match(/data:(image\/\w+);base64/)?e.match(/data:(image\/\w+);base64/)[1].toLowerCase():"image/jpeg"}(t,n),s=function(t,e,i){try{return new File([t],e,{type:i})}catch(t){return null}}(t,`image.${o.replace("image/","")}`,o);s?e(s):i()}).catch(i)})}class ef extends ql{init(){const t=this.editor,e=t.t;t.ui.componentFactory.add("imageUpload",i=>{const n=new Ju(i),o=t.commands.get("imageUpload"),s=t.config.get("image.upload.types"),r=Xu(s);return n.set({acceptedType:s.map(t=>`image/${t}`).join(","),allowMultipleFiles:!0}),n.buttonView.set({label:e("y"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.91 10.54c.26-.23.64-.21.88.03l3.36 3.14 2.23-2.06a.64.64 0 01.87 0l2.52 2.97V4.5H3.2v10.12l3.71-4.08zm10.27-7.51c.6 0 1.09.47 1.09 1.05v11.84c0 .59-.49 1.06-1.09 1.06H2.79c-.6 0-1.09-.47-1.09-1.06V4.08c0-.58.49-1.05 1.1-1.05h14.38zm-5.22 5.56a1.96 1.96 0 113.4-1.96 1.96 1.96 0 01-3.4 1.96z"/></svg>',tooltip:!0}),n.buttonView.bind("isEnabled").to(o),n.on("done",(e,i)=>{const n=Array.from(i).filter(t=>r.test(t.type));n.length&&t.execute("imageUpload",{file:n})}),n})}}i(64),i(66),i(68);class nf extends ql{constructor(t){super(t),this.placeholder="data:image/svg+xml;utf8,"+encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 250"><rect rx="4"/></svg>')}init(){this.editor.editing.downcastDispatcher.on("attribute:uploadStatus:image",(...t)=>this.uploadStatusChange(...t))}uploadStatusChange(t,e,i){const n=this.editor,o=e.item,s=o.getAttribute("uploadId");if(!i.consumable.consume(e.item,t.name))return;const r=n.plugins.get(qd),a=s?e.attributeNewValue:null,c=this.placeholder,l=n.editing.mapper.toViewElement(o),d=i.writer;if("reading"==a)return of(l,d),void sf(c,l,d);if("uploading"==a){const t=r.loaders.get(s);return of(l,d),void(t?(rf(l,d),function(t,e,i,n){const o=function(t){const e=t.createUIElement("div",{class:"ck-progress-bar"});return t.setCustomProperty("progressBar",!0,e),e}(e);e.insert(e.createPositionAt(t,"end"),o),i.on("change:uploadedPercent",(t,e,i)=>{n.change(t=>{t.setStyle("width",i+"%",o)})})}(l,d,t,n.editing.view),function(t,e,i){if(i.data){const n=t.getChild(0);e.setAttribute("src",i.data,n)}}(l,d,t)):sf(c,l,d))}"complete"==a&&r.loaders.get(s)&&!fo.isEdge&&function(t,e,i){const n=e.createUIElement("div",{class:"ck-image-upload-complete-icon"});e.insert(e.createPositionAt(t,"end"),n),setTimeout(()=>{i.change(t=>t.remove(t.createRangeOn(n)))},3e3)}(l,d,n.editing.view),function(t,e){cf(t,e,"progressBar")}(l,d),rf(l,d),function(t,e){e.removeClass("ck-appear",t)}(l,d)}}function of(t,e){t.hasClass("ck-appear")||e.addClass("ck-appear",t)}function sf(t,e,i){e.hasClass("ck-image-upload-placeholder")||i.addClass("ck-image-upload-placeholder",e);const n=e.getChild(0);n.getAttribute("src")!==t&&i.setAttribute("src",t,n),af(e,"placeholder")||i.insert(i.createPositionAfter(n),function(t){const e=t.createUIElement("div",{class:"ck-upload-placeholder-loader"});return t.setCustomProperty("placeholder",!0,e),e}(i))}function rf(t,e){t.hasClass("ck-image-upload-placeholder")&&e.removeClass("ck-image-upload-placeholder",t),cf(t,e,"placeholder")}function af(t,e){for(const i of t.getChildren())if(i.getCustomProperty(e))return i}function cf(t,e,i){const n=af(t,i);n&&e.remove(e.createRangeOn(n))}class lf{createDocumentFragment(t){return new Ao(t)}createElement(t,e,i){return new On(t,e,i)}createText(t){return new Ni(t)}clone(t,e=!1){return t._clone(e)}appendChild(t,e){return e._appendChild(t)}insertChild(t,e,i){return i._insertChild(t,e)}removeChildren(t,e,i){return i._removeChildren(t,e)}remove(t){const e=t.parent;return e?this.removeChildren(e.getChildIndex(t),1,e):[]}replace(t,e){const i=t.parent;if(i){const n=i.getChildIndex(t);return this.removeChildren(n,1,i),this.insertChild(n,e,i),!0}return!1}unwrapElement(t){const e=t.parent;if(e){const i=e.getChildIndex(t);this.remove(t),this.insertChild(i,t.getChildren(),e)}}rename(t,e){const i=new On(t,e.getAttributes(),e.getChildren());return this.replace(e,i)?i:null}setAttribute(t,e,i){i._setAttribute(t,e)}removeAttribute(t,e){e._removeAttribute(t)}addClass(t,e){e._addClass(t)}removeClass(t,e){e._removeClass(t)}setStyle(t,e,i){y(t)&&void 0===i&&(i=e),i._setStyle(t,e)}removeStyle(t,e){e._removeStyle(t)}setCustomProperty(t,e,i){i._setCustomProperty(t,e)}removeCustomProperty(t,e){return e._removeCustomProperty(t)}createPositionAt(t,e){return Xn._createAt(t,e)}createPositionAfter(t){return Xn._createAfter(t)}createPositionBefore(t){return Xn._createBefore(t)}createRange(t,e){return new to(t,e)}createRangeOn(t){return to._createOn(t)}createRangeIn(t){return to._createIn(t)}createSelection(t,e,i){return new no(t,e,i)}}class df extends Jl{refresh(){this.isEnabled=Sh(this.editor.model)}execute(t){const e=this.editor,i=e.model,n=e.plugins.get(qd);i.change(e=>{const o=Array.isArray(t.file)?t.file:[t.file];for(const t of o)hf(e,i,n,t)})}}function hf(t,e,i,n){const o=i.createLoader(n);o&&Ph(t,e,{uploadId:o.id})}class uf extends ql{static get requires(){return[qd,fu,Kl]}static get pluginName(){return"ImageUploadEditing"}constructor(t){super(t),t.config.define("image",{upload:{types:["jpeg","png","gif","bmp","webp","tiff"]}})}init(){const t=this.editor,e=t.model.document,i=t.model.schema,n=t.conversion,o=t.plugins.get(qd),s=Xu(t.config.get("image.upload.types"));i.extend("image",{allowAttributes:["uploadId","uploadStatus"]}),t.commands.add("imageUpload",new df(t)),n.for("upcast").attributeToAttribute({view:{name:"img",key:"uploadId"},model:"uploadId"}),this.listenTo(t.editing.view.document,"clipboardInput",(e,i)=>{if(n=i.dataTransfer,Array.from(n.types).includes("text/html")&&""!==n.getData("text/html"))return;var n;const o=Array.from(i.dataTransfer.files).filter(t=>!!t&&s.test(t.type)),r=i.targetRanges.map(e=>t.editing.mapper.toModelRange(e));t.model.change(i=>{i.setSelection(r),o.length&&(e.stop(),t.model.enqueueChange("default",()=>{t.execute("imageUpload",{file:o})}))})}),this.listenTo(t.plugins.get(Kl),"inputTransformation",(e,i)=>{const n=Array.from(t.editing.view.createRangeIn(i.content)).filter(t=>{return!(!(e=t.item).is("element","img")||!e.getAttribute("src"))&&(e.getAttribute("src").match(/^data:image\/\w+;base64,/g)||e.getAttribute("src").match(/^blob:/g))&&!t.item.getAttribute("uploadProcessed");var e}).map(t=>({promise:tf(t.item),imageElement:t.item}));if(!n.length)return;const s=new lf;for(const t of n){s.setAttribute("uploadProcessed",!0,t.imageElement);const e=o.createLoader(t.promise);e&&(s.setAttribute("src","",t.imageElement),s.setAttribute("uploadId",e.id,t.imageElement))}}),t.editing.view.document.on("dragover",(t,e)=>{e.preventDefault()}),e.on("change",()=>{const i=e.differ.getChanges({includeChangesInGraveyard:!0});for(const e of i)if("insert"==e.type&&"$text"!=e.name){const i=e.position.nodeAfter,n="$graveyard"==e.position.root.rootName;for(const e of ff(t,i)){const t=e.getAttribute("uploadId");if(!t)continue;const i=o.loaders.get(t);i&&(n?i.abort():"idle"==i.status&&this._readAndUpload(i,e))}}})}_readAndUpload(t,e){const i=this.editor,n=i.model,o=i.locale.t,s=i.plugins.get(qd),r=i.plugins.get(fu);return n.enqueueChange("transparent",t=>{t.setAttribute("uploadStatus","reading",e)}),t.read().then(()=>{const o=t.upload();if(fo.isSafari){const t=i.editing.mapper.toViewElement(e).getChild(0);i.editing.view.once("render",()=>{if(!t.parent)return;const e=i.editing.view.domConverter.mapViewToDom(t.parent);if(!e)return;const n=e.style.display;e.style.display="none",e._ckHack=e.offsetHeight,e.style.display=n})}return n.enqueueChange("transparent",t=>{t.setAttribute("uploadStatus","uploading",e)}),o}).then(t=>{n.enqueueChange("transparent",i=>{i.setAttributes({uploadStatus:"complete",src:t.default},e),this._parseAndSetSrcsetAttributeOnImage(t,e,i)}),a()}).catch(i=>{if("error"!==t.status&&"aborted"!==t.status)throw i;"error"==t.status&&i&&r.showWarning(i,{title:o("ag"),namespace:"upload"}),a(),n.enqueueChange("transparent",t=>{t.remove(e)})});function a(){n.enqueueChange("transparent",t=>{t.removeAttribute("uploadId",e),t.removeAttribute("uploadStatus",e)}),s.destroyLoader(t)}}_parseAndSetSrcsetAttributeOnImage(t,e,i){let n=0;const o=Object.keys(t).filter(t=>{const e=parseInt(t,10);if(!isNaN(e))return n=Math.max(n,e),!0}).map(e=>`${t[e]} ${e}w`).join(", ");""!=o&&i.setAttribute("srcset",{data:o,width:n},e)}}function ff(t,e){return Array.from(t.model.createRangeOn(e)).filter(t=>t.item.is("image")).map(t=>t.item)}class mf extends ql{static get pluginName(){return"ImageUpload"}static get requires(){return[uf,ef,nf]}}class gf extends Jl{refresh(){const t=this.editor.model,e=sh(t.document.selection.getSelectedBlocks());this.value=!!e&&e.is("paragraph"),this.isEnabled=!!e&&pf(e,t.schema)}execute(t={}){const e=this.editor.model,i=e.document;e.change(n=>{const o=(t.selection||i.selection).getSelectedBlocks();for(const t of o)!t.is("paragraph")&&pf(t,e.schema)&&n.rename(t,"paragraph")})}}function pf(t,e){return e.checkChild(t.parent,"paragraph")&&!e.isObject(t)}class bf extends ql{static get pluginName(){return"Paragraph"}init(){const t=this.editor,e=t.model,i=t.data;t.commands.add("paragraph",new gf(t)),e.schema.register("paragraph",{inheritAllFrom:"$block"}),t.conversion.elementToElement({model:"paragraph",view:"p"}),t.conversion.for("upcast").elementToElement({model:(t,e)=>bf.paragraphLikeElements.has(t.name)?t.isEmpty?null:e.createElement("paragraph"):null,converterPriority:"low"}),i.upcastDispatcher.on("element",(t,e,i)=>{i.consumable.test(e.viewItem,{name:e.viewItem.name})&&kf(e.viewItem,e.modelCursor,i.schema)&&Object.assign(e,wf(e.viewItem,e.modelCursor,i))},{priority:"low"}),i.upcastDispatcher.on("text",(t,e,i)=>{e.modelRange||kf(e.viewItem,e.modelCursor,i.schema)&&Object.assign(e,wf(e.viewItem,e.modelCursor,i))},{priority:"lowest"}),e.document.registerPostFixer(t=>this._autoparagraphEmptyRoots(t)),t.data.on("ready",()=>{e.enqueueChange("transparent",t=>this._autoparagraphEmptyRoots(t))},{priority:"lowest"})}_autoparagraphEmptyRoots(t){const e=this.editor.model;for(const i of e.document.getRootNames()){const n=e.document.getRoot(i);if(n.isEmpty&&"$graveyard"!=n.rootName&&e.schema.checkChild(n,"paragraph"))return t.insertElement("paragraph",n),!0}}}function wf(t,e,i){const n=i.writer.createElement("paragraph");return i.writer.insert(n,e),i.convertItem(t,i.writer.createPositionAt(n,0))}function kf(t,e,i){const n=i.createContext(e);return!!i.checkChild(n,"paragraph")&&!!i.checkChild(n.push("paragraph"),t)}bf.paragraphLikeElements=new Set(["blockquote","dd","div","dt","h1","h2","h3","h4","h5","h6","li","p","td"]);class _f extends Jl{constructor(t,e){super(t),this.modelElements=e}refresh(){const t=sh(this.editor.model.document.selection.getSelectedBlocks());this.value=!!t&&this.modelElements.includes(t.name)&&t.name,this.isEnabled=!!t&&this.modelElements.some(e=>vf(t,e,this.editor.model.schema))}execute(t){const e=this.editor.model,i=e.document,n=t.value;e.change(t=>{const o=Array.from(i.selection.getSelectedBlocks()).filter(t=>vf(t,n,e.schema));for(const e of o)e.is(n)||t.rename(e,n)})}}function vf(t,e,i){return i.checkChild(t.parent,e)&&!i.isObject(t)}class yf extends ql{static get pluginName(){return"HeadingEditing"}constructor(t){super(t),t.config.define("heading",{options:[{model:"paragraph",title:"Paragraph",class:"ck-heading_paragraph"},{model:"heading1",view:"h2",title:"Heading 1",class:"ck-heading_heading1"},{model:"heading2",view:"h3",title:"Heading 2",class:"ck-heading_heading2"},{model:"heading3",view:"h4",title:"Heading 3",class:"ck-heading_heading3"}]})}static get requires(){return[bf]}init(){const t=this.editor,e=t.config.get("heading.options"),i=[];for(const n of e)"paragraph"!==n.model&&(t.model.schema.register(n.model,{inheritAllFrom:"$block"}),t.conversion.elementToElement(n),i.push(n.model));this._addDefaultH1Conversion(t),t.commands.add("heading",new _f(t,i))}afterInit(){const t=this.editor,e=t.commands.get("enter"),i=t.config.get("heading.options");e&&this.listenTo(e,"afterExecute",(e,n)=>{const o=t.model.document.selection.getFirstPosition().parent;i.some(t=>o.is(t.model))&&!o.is("paragraph")&&0===o.childCount&&n.writer.rename(o,"paragraph")})}_addDefaultH1Conversion(t){t.conversion.for("upcast").elementToElement({model:"heading1",view:"h1",converterPriority:di.get("low")+1})}}class xf{constructor(t,e){e&&zn(this,e),t&&this.set(t)}}vi(xf,Hn);i(11);class Af extends ql{init(){const t=this.editor,e=t.t,i=function(t){const e=t.t,i={Paragraph:e("dk"),"Heading 1":e("dl"),"Heading 2":e("dm"),"Heading 3":e("dn"),"Heading 4":e("do"),"Heading 5":e("dp"),"Heading 6":e("dq")};return t.config.get("heading.options").map(t=>{const e=i[t.title];return e&&e!=t.title&&(t.title=e),t})}(t),n=e("l"),o=e("m");t.ui.componentFactory.add("heading",e=>{const s={},r=new yi,a=t.commands.get("heading"),c=t.commands.get("paragraph"),l=[a];for(const t of i){const e={type:"button",model:new xf({label:t.title,class:t.class,withText:!0})};"paragraph"===t.model?(e.model.bind("isOn").to(c,"value"),e.model.set("commandName","paragraph"),l.push(c)):(e.model.bind("isOn").to(a,"value",e=>e===t.model),e.model.set({commandName:"heading",commandValue:t.model})),r.add(e),s[t.model]=t.title}const d=Dl(e);return jl(d,r),d.buttonView.set({isOn:!1,withText:!0,tooltip:o}),d.extendTemplate({attributes:{class:["ck-heading-dropdown"]}}),d.bind("isEnabled").toMany(l,"isEnabled",(...t)=>t.some(t=>t)),d.buttonView.bind("label").to(a,"value",c,"value",(t,e)=>{const i=t||e&&"paragraph";return s[i]?s[i]:n}),this.listenTo(d,"execute",e=>{t.execute(e.source.commandName,e.source.commandValue?{value:e.source.commandValue}:void 0),t.editing.view.focus()}),d})}}function Cf(t){for(const e of t.getChildren())if(e&&e.is("caption"))return e;return null}function Tf(t){const e=t.parent;return"figcaption"==t.name&&e&&"figure"==e.name&&e.hasClass("image")?{name:!0}:null}class Pf extends ql{static get pluginName(){return"ImageCaptionEditing"}init(){const t=this.editor,e=t.editing.view,i=t.model.schema,n=t.data,o=t.editing,s=t.t;i.register("caption",{allowIn:"image",allowContentOf:"$block",isLimit:!0}),t.model.document.registerPostFixer(t=>this._insertMissingModelCaptionElement(t)),t.conversion.for("upcast").elementToElement({view:Tf,model:"caption"});n.downcastDispatcher.on("insert:caption",Sf(t=>t.createContainerElement("figcaption"),!1));const r=function(t,e){return i=>{const n=i.createEditableElement("figcaption");return i.setCustomProperty("imageCaption",!0,n),Rc({view:t,element:n,text:e}),yh(n,i)}}(e,s("z"));o.downcastDispatcher.on("insert:caption",Sf(r)),o.downcastDispatcher.on("insert",this._fixCaptionVisibility(t=>t.item),{priority:"high"}),o.downcastDispatcher.on("remove",this._fixCaptionVisibility(t=>t.position.parent),{priority:"high"}),e.document.registerPostFixer(t=>this._updateCaptionVisibility(t))}_updateCaptionVisibility(t){const e=this.editor.editing.mapper,i=this._lastSelectedCaption;let n;const o=this.editor.model.document.selection,s=o.getSelectedElement();if(s&&s.is("image")){const t=Cf(s);n=e.toViewElement(t)}const r=Ef(o.getFirstPosition().parent);if(r&&(n=e.toViewElement(r)),n)return i?(i===n||(Mf(i,t),this._lastSelectedCaption=n),If(n,t)):(this._lastSelectedCaption=n,If(n,t));if(i){const e=Mf(i,t);return this._lastSelectedCaption=null,e}return!1}_fixCaptionVisibility(t){return(e,i,n)=>{const o=Ef(t(i)),s=this.editor.editing.mapper,r=n.writer;if(o){const t=s.toViewElement(o);t&&(o.childCount?r.removeClass("ck-hidden",t):r.addClass("ck-hidden",t))}}}_insertMissingModelCaptionElement(t){const e=this.editor.model,i=e.document.differ.getChanges(),n=[];for(const t of i)if("insert"==t.type&&"$text"!=t.name){const i=t.position.nodeAfter;if(i.is("image")&&!Cf(i)&&n.push(i),!i.is("image")&&i.childCount)for(const t of e.createRangeIn(i).getItems())t.is("image")&&!Cf(t)&&n.push(t)}for(const e of n)t.appendElement("caption",e);return!!n.length}}function Sf(t,e=!0){return(i,n,o)=>{const s=n.item;if((s.childCount||e)&&Th(s.parent)){if(!o.consumable.consume(n.item,"insert"))return;const e=o.mapper.toViewElement(n.range.start.parent),i=t(o.writer),r=o.writer;s.childCount||r.addClass("ck-hidden",i),function(t,e,i,n){const o=n.writer.createPositionAt(i,"end");n.writer.insert(o,t),n.mapper.bindElements(e,t)}(i,n.item,e,o)}}}function Ef(t){const e=t.getAncestors({includeSelf:!0}).find(t=>"caption"==t.name);return e&&e.parent&&"image"==e.parent.name?e:null}function Mf(t,e){return!t.childCount&&!t.hasClass("ck-hidden")&&(e.addClass("ck-hidden",t),!0)}function If(t,e){return!!t.hasClass("ck-hidden")&&(e.removeClass("ck-hidden",t),!0)}i(71);class Nf extends Jl{constructor(t,e){super(t),this.defaultStyle=!1,this.styles=e.reduce((t,e)=>(t[e.name]=e,e.isDefault&&(this.defaultStyle=e.name),t),{})}refresh(){const t=this.editor.model.document.selection.getSelectedElement();if(this.isEnabled=Th(t),t)if(t.hasAttribute("imageStyle")){const e=t.getAttribute("imageStyle");this.value=!!this.styles[e]&&e}else this.value=this.defaultStyle;else this.value=!1}execute(t){const e=t.value,i=this.editor.model,n=i.document.selection.getSelectedElement();i.change(t=>{this.styles[e].isDefault?t.removeAttribute("imageStyle",n):t.setAttribute("imageStyle",e,n)})}}function Of(t,e){for(const i of e)if(i.name===t)return i}var Rf='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 4.5V3h16v1.5zm2.5 3V12h11V7.5h-11zM4.061 6H15.94c.586 0 1.061.407 1.061.91v5.68c0 .503-.475.91-1.061.91H4.06c-.585 0-1.06-.407-1.06-.91V6.91C3 6.406 3.475 6 4.061 6zM2 16.5V15h16v1.5z"/></svg>',Lf='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M18 4.5V3H2v1.5h16zm0 3V6h-5.674v1.5H18zm0 3V9h-5.674v1.5H18zm0 3V12h-5.674v1.5H18zm-8.5-6V12h-6V7.5h6zm.818-1.5H2.682C2.305 6 2 6.407 2 6.91v5.68c0 .503.305.91.682.91h7.636c.377 0 .682-.407.682-.91V6.91c0-.503-.305-.91-.682-.91zM18 16.5V15H2v1.5h16z"/></svg>',Df='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 4.5V3h16v1.5zm4.5 3V12h7V7.5h-7zM5.758 6h8.484c.419 0 .758.407.758.91v5.681c0 .502-.34.909-.758.909H5.758c-.419 0-.758-.407-.758-.91V6.91c0-.503.34-.91.758-.91zM2 16.5V15h16v1.5z"/></svg>',zf='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 4.5V3h16v1.5zm0 3V6h5.674v1.5zm0 3V9h5.674v1.5zm0 3V12h5.674v1.5zm8.5-6V12h6V7.5h-6zM9.682 6h7.636c.377 0 .682.407.682.91v5.68c0 .503-.305.91-.682.91H9.682c-.377 0-.682-.407-.682-.91V6.91c0-.503.305-.91.682-.91zM2 16.5V15h16v1.5z"/></svg>';const jf={full:{name:"full",title:"Full size image",icon:Rf,isDefault:!0},side:{name:"side",title:"Side image",icon:zf,className:"image-style-side"},alignLeft:{name:"alignLeft",title:"Left aligned image",icon:Lf,className:"image-style-align-left"},alignCenter:{name:"alignCenter",title:"Centered image",icon:Df,className:"image-style-align-center"},alignRight:{name:"alignRight",title:"Right aligned image",icon:zf,className:"image-style-align-right"}},Vf={full:Rf,left:Lf,right:zf,center:Df};function Bf(t=[]){return t.map(Ff)}function Ff(t){if("string"==typeof t){const e=t;jf[e]?t=Object.assign({},jf[e]):(console.warn(Object(hi.a)("image-style-not-found: There is no such image style of given name."),{name:e}),t={name:e})}else if(jf[t.name]){const e=jf[t.name],i=Object.assign({},t);for(const n in e)t.hasOwnProperty(n)||(i[n]=e[n]);t=i}return"string"==typeof t.icon&&Vf[t.icon]&&(t.icon=Vf[t.icon]),t}class Hf extends ql{static get pluginName(){return"ImageStyleEditing"}init(){const t=this.editor,e=t.model.schema,i=t.data,n=t.editing;t.config.define("image.styles",["full","side"]);const o=Bf(t.config.get("image.styles"));e.extend("image",{allowAttributes:"imageStyle"});const s=function(t){return(e,i,n)=>{if(!n.consumable.consume(i.item,e.name))return;const o=Of(i.attributeNewValue,t),s=Of(i.attributeOldValue,t),r=n.mapper.toViewElement(i.item),a=n.writer;s&&a.removeClass(s.className,r),o&&a.addClass(o.className,r)}}(o);n.downcastDispatcher.on("attribute:imageStyle:image",s),i.downcastDispatcher.on("attribute:imageStyle:image",s),i.upcastDispatcher.on("element:figure",function(t){const e=t.filter(t=>!t.isDefault);return(t,i,n)=>{if(!i.modelRange)return;const o=i.viewItem,s=sh(i.modelRange.getItems());if(n.schema.checkAttribute(s,"imageStyle"))for(const t of e)n.consumable.consume(o,{classes:t.className})&&n.writer.setAttribute("imageStyle",t.name,s)}}(o),{priority:"low"}),t.commands.add("imageStyle",new Nf(t,o))}}i(73);class Uf extends ql{static get pluginName(){return"ImageStyleUI"}get localizedDefaultStylesTitles(){const t=this.editor.t;return{"Full size image":t("n"),"Side image":t("o"),"Left aligned image":t("p"),"Centered image":t("q"),"Right aligned image":t("r")}}init(){const t=function(t,e){for(const i of t)e[i.title]&&(i.title=e[i.title]);return t}(Bf(this.editor.config.get("image.styles")),this.localizedDefaultStylesTitles);for(const e of t)this._createButton(e)}_createButton(t){const e=this.editor,i=`imageStyle:${t.name}`;e.ui.componentFactory.add(i,i=>{const n=e.commands.get("imageStyle"),o=new El(i);return o.set({label:t.title,icon:t.icon,tooltip:!0,isToggleable:!0}),o.bind("isEnabled").to(n,"isEnabled"),o.bind("isOn").to(n,"value",e=>e===t.name),this.listenTo(o,"execute",()=>{e.execute("imageStyle",{value:t.name}),e.editing.view.focus()}),o})}}class Wf extends ql{static get requires(){return[Wu]}static get pluginName(){return"WidgetToolbarRepository"}init(){const t=this.editor;if(t.plugins.has("BalloonToolbar")){const e=t.plugins.get("BalloonToolbar");this.listenTo(e,"show",e=>{(function(t){const e=t.getSelectedElement();return!(!e||!kh(e))})(t.editing.view.document.selection)&&e.stop()},{priority:"high"})}this._toolbarDefinitions=new Map,this._balloon=this.editor.plugins.get("ContextualBalloon"),this.on("change:isEnabled",()=>{this._updateToolbarsVisibility()}),this.listenTo(t.ui,"update",()=>{this._updateToolbarsVisibility()}),this.listenTo(t.ui.focusTracker,"change:isFocused",()=>{this._updateToolbarsVisibility()},{priority:"low"})}destroy(){super.destroy();for(const t of this._toolbarDefinitions.values())t.view.destroy()}register(t,{ariaLabel:e,items:i,getRelatedElement:n,balloonClassName:o="ck-toolbar-container"}){const s=this.editor,r=s.t,a=new Vl(s.locale);if(a.ariaLabel=e||r("aj"),this._toolbarDefinitions.has(t))throw new hi.b("widget-toolbar-duplicated: Toolbar with the given id was already added.",this,{toolbarId:t});a.fillFromConfig(i,s.ui.componentFactory),this._toolbarDefinitions.set(t,{view:a,getRelatedElement:n,balloonClassName:o})}_updateToolbarsVisibility(){let t=0,e=null,i=null;for(const n of this._toolbarDefinitions.values()){const o=n.getRelatedElement(this.editor.editing.view.document.selection);if(this.isEnabled&&o)if(this.editor.ui.focusTracker.isFocused){const s=o.getAncestors().length;s>t&&(t=s,e=o,i=n)}else this._isToolbarVisible(n)&&this._hideToolbar(n);else this._isToolbarInBalloon(n)&&this._hideToolbar(n)}i&&this._showToolbar(i,e)}_hideToolbar(t){this._balloon.remove(t.view),this.stopListening(this._balloon,"change:visibleView")}_showToolbar(t,e){this._isToolbarVisible(t)?qf(this.editor,e):this._isToolbarInBalloon(t)||(this._balloon.add({view:t.view,position:$f(this.editor,e),balloonClassName:t.balloonClassName}),this.listenTo(this._balloon,"change:visibleView",()=>{for(const t of this._toolbarDefinitions.values())if(this._isToolbarVisible(t)){const e=t.getRelatedElement(this.editor.editing.view.document.selection);qf(this.editor,e)}}))}_isToolbarVisible(t){return this._balloon.visibleView===t.view}_isToolbarInBalloon(t){return this._balloon.hasView(t.view)}}function qf(t,e){const i=t.plugins.get("ContextualBalloon"),n=$f(t,e);i.updatePosition(n)}function $f(t,e){const i=t.editing.view,n=Vu.defaultPositions;return{target:i.domConverter.mapViewToDom(e),positions:[n.northArrowSouth,n.northArrowSouthWest,n.northArrowSouthEast,n.southArrowNorth,n.southArrowNorthWest,n.southArrowNorthEast]}}class Yf extends Jl{constructor(t){super(t),this._childCommands=[]}refresh(){}execute(...t){this._getFirstEnabledCommand().execute(t)}registerChildCommand(t){this._childCommands.push(t),t.on("change:isEnabled",()=>this._checkEnabled()),this._checkEnabled()}_checkEnabled(){this.isEnabled=!!this._getFirstEnabledCommand()}_getFirstEnabledCommand(){return this._childCommands.find(t=>t.isEnabled)}}class Gf extends ql{static get pluginName(){return"IndentEditing"}init(){const t=this.editor;t.commands.add("indent",new Yf(t)),t.commands.add("outdent",new Yf(t))}}var Qf='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm5 6c0 .414.336.75.75.75h9.5a.75.75 0 100-1.5h-9.5a.75.75 0 00-.75.75zM2.75 16.5h14.5a.75.75 0 100-1.5H2.75a.75.75 0 100 1.5zM1.632 6.95L5.02 9.358a.4.4 0 01-.013.661l-3.39 2.207A.4.4 0 011 11.892V7.275a.4.4 0 01.632-.326z"/></svg>',Kf='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm5 6c0 .414.336.75.75.75h9.5a.75.75 0 100-1.5h-9.5a.75.75 0 00-.75.75zM2.75 16.5h14.5a.75.75 0 100-1.5H2.75a.75.75 0 100 1.5zM4.368 6.95L.98 9.358a.4.4 0 00.013.661l3.39 2.207A.4.4 0 005 11.892V7.275a.4.4 0 00-.632-.326z"/></svg>';class Jf extends ql{static get pluginName(){return"IndentUI"}init(){const t=this.editor,e=t.locale,i=t.t,n="ltr"==e.uiLanguageDirection?Qf:Kf,o="ltr"==e.uiLanguageDirection?Kf:Qf;this._defineButton("indent",i("u"),n),this._defineButton("outdent",i("v"),o)}_defineButton(t,e,i){const n=this.editor;n.ui.componentFactory.add(t,o=>{const s=n.commands.get(t),r=new El(o);return r.set({label:e,icon:i,tooltip:!0}),r.bind("isOn","isEnabled").to(s,"value","isEnabled"),this.listenTo(r,"execute",()=>{n.execute(t),n.editing.view.focus()}),r})}}class Zf extends Os{constructor(t){super(t),this.domEventType="click"}onDomEvent(t){this.fire(t.type,t)}}i(75);class Xf extends rl{constructor(t,e=[]){super(t);const i=t.t;this.focusTracker=new Ic,this.keystrokes=new yc,this.urlInputView=this._createUrlInput(),this.saveButtonView=this._createButton(i("cf"),Ru,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton(i("cg"),Lu,"ck-button-cancel","cancel"),this._manualDecoratorSwitches=this._createManualDecoratorSwitches(e),this.children=this._createFormChildren(e),this._focusables=new Bc,this._focusCycler=new bl({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}});const n=["ck","ck-link-form"];e.length&&n.push("ck-link-form_layout-vertical"),this.setTemplate({tag:"form",attributes:{class:n,tabindex:"-1"},children:this.children})}getDecoratorSwitchesState(){return Array.from(this._manualDecoratorSwitches).reduce((t,e)=>(t[e.name]=e.isOn,t),{})}render(){super.render(),Ou({view:this}),[this.urlInputView,...this._manualDecoratorSwitches,this.saveButtonView,this.cancelButtonView].forEach(t=>{this._focusables.add(t),this.focusTracker.add(t.element)}),this.keystrokes.listenTo(this.element)}focus(){this._focusCycler.focusFirst()}_createUrlInput(){const t=this.locale.t,e=new Iu(this.locale,Nu);return e.label=t("ck"),e.inputView.placeholder="https://example.com",e}_createButton(t,e,i,n){const o=new El(this.locale);return o.set({label:t,icon:e,tooltip:!0}),o.extendTemplate({attributes:{class:i}}),n&&o.delegate("execute").to(this,n),o}_createManualDecoratorSwitches(t){const e=this.createCollection();for(const i of t){const t=new Rl(this.locale);t.set({name:i.id,label:i.label,withText:!0}),t.bind("isOn").to(i,"value"),t.on("execute",()=>{i.set("value",!t.isOn)}),e.add(t)}return e}_createFormChildren(t){const e=this.createCollection();if(e.add(this.urlInputView),t.length){const t=new rl;t.setTemplate({tag:"ul",children:this._manualDecoratorSwitches.map(t=>({tag:"li",children:[t],attributes:{class:["ck","ck-list__item"]}})),attributes:{class:["ck","ck-reset","ck-list"]}}),e.add(t)}return e.add(this.saveButtonView),e.add(this.cancelButtonView),e}}i(77);class tm extends rl{constructor(t){super(t);const e=t.t;this.focusTracker=new Ic,this.keystrokes=new yc,this.previewButtonView=this._createPreviewButton(),this.unlinkButtonView=this._createButton(e("cb"),'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.077 15l.991-1.416a.75.75 0 111.229.86l-1.148 1.64a.748.748 0 01-.217.206 5.251 5.251 0 01-8.503-5.955.741.741 0 01.12-.274l1.147-1.639a.75.75 0 111.228.86L4.933 10.7l.006.003a3.75 3.75 0 006.132 4.294l.006.004zm5.494-5.335a.748.748 0 01-.12.274l-1.147 1.639a.75.75 0 11-1.228-.86l.86-1.23a3.75 3.75 0 00-6.144-4.301l-.86 1.229a.75.75 0 01-1.229-.86l1.148-1.64a.748.748 0 01.217-.206 5.251 5.251 0 018.503 5.955zm-4.563-2.532a.75.75 0 01.184 1.045l-3.155 4.505a.75.75 0 11-1.229-.86l3.155-4.506a.75.75 0 011.045-.184zm4.919 10.562l-1.414 1.414a.75.75 0 11-1.06-1.06l1.414-1.415-1.415-1.414a.75.75 0 011.061-1.06l1.414 1.414 1.414-1.415a.75.75 0 011.061 1.061l-1.414 1.414 1.414 1.415a.75.75 0 01-1.06 1.06l-1.415-1.414z"/></svg>',"unlink"),this.editButtonView=this._createButton(e("cc"),'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M7.3 17.37l-.061.088a1.518 1.518 0 01-.934.535l-4.178.663-.806-4.153a1.495 1.495 0 01.187-1.058l.056-.086L8.77 2.639c.958-1.351 2.803-1.076 4.296-.03 1.497 1.047 2.387 2.693 1.433 4.055L7.3 17.37zM9.14 4.728l-5.545 8.346 3.277 2.294 5.544-8.346L9.14 4.728zM6.07 16.512l-3.276-2.295.53 2.73 2.746-.435zM9.994 3.506L13.271 5.8c.316-.452-.16-1.333-1.065-1.966-.905-.634-1.895-.78-2.212-.328zM8 18.5L9.375 17H19v1.5H8z"/></svg>',"edit"),this.set("href"),this._focusables=new Bc,this._focusCycler=new bl({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this.setTemplate({tag:"div",attributes:{class:["ck","ck-link-actions"],tabindex:"-1"},children:[this.previewButtonView,this.editButtonView,this.unlinkButtonView]})}render(){super.render(),[this.previewButtonView,this.editButtonView,this.unlinkButtonView].forEach(t=>{this._focusables.add(t),this.focusTracker.add(t.element)}),this.keystrokes.listenTo(this.element)}focus(){this._focusCycler.focusFirst()}_createButton(t,e,i){const n=new El(this.locale);return n.set({label:t,icon:e,tooltip:!0}),n.delegate("execute").to(this,i),n}_createPreviewButton(){const t=new El(this.locale),e=this.bindTemplate,i=this.t;return t.set({withText:!0,tooltip:i("cd")}),t.extendTemplate({attributes:{class:["ck","ck-link-actions__preview"],href:e.to("href",t=>t&&iu(t)),target:"_blank",rel:"noopener noreferrer"}}),t.bind("label").to(this,"href",t=>t||i("ce")),t.bind("isEnabled").to(this,"href",t=>!!t),t.template.tag="a",t.template.eventListeners={},t}}class em extends ql{static get requires(){return[Wu]}static get pluginName(){return"LinkUI"}init(){const t=this.editor;t.editing.view.addObserver(Zf),this.actionsView=this._createActionsView(),this.formView=this._createFormView(),this._balloon=t.plugins.get(Wu),this._createToolbarLinkButton(),this._enableUserBalloonInteractions()}destroy(){super.destroy(),this.formView.destroy()}_createActionsView(){const t=this.editor,e=new tm(t.locale),i=t.commands.get("link"),n=t.commands.get("unlink");return e.bind("href").to(i,"value"),e.editButtonView.bind("isEnabled").to(i),e.unlinkButtonView.bind("isEnabled").to(n),this.listenTo(e,"edit",()=>{this._addFormView()}),this.listenTo(e,"unlink",()=>{t.execute("unlink"),this._hideUI()}),e.keystrokes.set("Esc",(t,e)=>{this._hideUI(),e()}),e.keystrokes.set("Ctrl+K",(t,e)=>{this._addFormView(),e()}),e}_createFormView(){const t=this.editor,e=t.commands.get("link"),i=new Xf(t.locale,e.manualDecorators);return i.urlInputView.bind("value").to(e,"value"),i.urlInputView.bind("isReadOnly").to(e,"isEnabled",t=>!t),i.saveButtonView.bind("isEnabled").to(e),this.listenTo(i,"submit",()=>{t.execute("link",i.urlInputView.inputView.element.value,i.getDecoratorSwitchesState()),this._closeFormView()}),this.listenTo(i,"cancel",()=>{this._closeFormView()}),i.keystrokes.set("Esc",(t,e)=>{this._closeFormView(),e()}),i}_createToolbarLinkButton(){const t=this.editor,e=t.commands.get("link"),i=t.t;t.keystrokes.set("Ctrl+K",(t,e)=>{e(),this._showUI(!0)}),t.ui.componentFactory.add("link",t=>{const n=new El(t);return n.isEnabled=!0,n.label=i("bh"),n.icon='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.077 15l.991-1.416a.75.75 0 111.229.86l-1.148 1.64a.748.748 0 01-.217.206 5.251 5.251 0 01-8.503-5.955.741.741 0 01.12-.274l1.147-1.639a.75.75 0 111.228.86L4.933 10.7l.006.003a3.75 3.75 0 006.132 4.294l.006.004zm5.494-5.335a.748.748 0 01-.12.274l-1.147 1.639a.75.75 0 11-1.228-.86l.86-1.23a3.75 3.75 0 00-6.144-4.301l-.86 1.229a.75.75 0 01-1.229-.86l1.148-1.64a.748.748 0 01.217-.206 5.251 5.251 0 018.503 5.955zm-4.563-2.532a.75.75 0 01.184 1.045l-3.155 4.505a.75.75 0 11-1.229-.86l3.155-4.506a.75.75 0 011.045-.184z"/></svg>',n.keystroke="Ctrl+K",n.tooltip=!0,n.isToggleable=!0,n.bind("isEnabled").to(e,"isEnabled"),n.bind("isOn").to(e,"value",t=>!!t),this.listenTo(n,"execute",()=>this._showUI(!0)),n})}_enableUserBalloonInteractions(){const t=this.editor.editing.view.document;this.listenTo(t,"click",()=>{this._getSelectedLinkElement()&&this._showUI()}),this.editor.keystrokes.set("Tab",(t,e)=>{this._areActionsVisible&&!this.actionsView.focusTracker.isFocused&&(this.actionsView.focus(),e())},{priority:"high"}),this.editor.keystrokes.set("Esc",(t,e)=>{this._isUIVisible&&(this._hideUI(),e())}),Ll({emitter:this.formView,activator:()=>this._isUIInPanel,contextElements:[this._balloon.view.element],callback:()=>this._hideUI()})}_addActionsView(){this._areActionsInPanel||this._balloon.add({view:this.actionsView,position:this._getBalloonPositionData()})}_addFormView(){if(this._isFormInPanel)return;const t=this.editor.commands.get("link");this._balloon.add({view:this.formView,position:this._getBalloonPositionData()}),this._balloon.visibleView===this.formView&&this.formView.urlInputView.select(),this.formView.urlInputView.inputView.element.value=t.value||""}_closeFormView(){const t=this.editor.commands.get("link");t.restoreManualDecoratorStates(),void 0!==t.value?this._removeFormView():this._hideUI()}_removeFormView(){this._isFormInPanel&&(this.formView.saveButtonView.focus(),this._balloon.remove(this.formView),this.editor.editing.view.focus())}_showUI(t=!1){this._getSelectedLinkElement()?(this._areActionsVisible?this._addFormView():this._addActionsView(),t&&this._balloon.showStack("main")):(this._addActionsView(),t&&this._balloon.showStack("main"),this._addFormView()),this._startUpdatingUI()}_hideUI(){if(!this._isUIInPanel)return;const t=this.editor;this.stopListening(t.ui,"update"),this.stopListening(this._balloon,"change:visibleView"),t.editing.view.focus(),this._removeFormView(),this._balloon.remove(this.actionsView)}_startUpdatingUI(){const t=this.editor,e=t.editing.view.document;let i=this._getSelectedLinkElement(),n=s();const o=()=>{const t=this._getSelectedLinkElement(),e=s();i&&!t||!i&&e!==n?this._hideUI():this._isUIVisible&&this._balloon.updatePosition(this._getBalloonPositionData()),i=t,n=e};function s(){return e.selection.focus.getAncestors().reverse().find(t=>t.is("element"))}this.listenTo(t.ui,"update",o),this.listenTo(this._balloon,"change:visibleView",o)}get _isFormInPanel(){return this._balloon.hasView(this.formView)}get _areActionsInPanel(){return this._balloon.hasView(this.actionsView)}get _areActionsVisible(){return this._balloon.visibleView===this.actionsView}get _isUIInPanel(){return this._isFormInPanel||this._areActionsInPanel}get _isUIVisible(){return this._balloon.visibleView==this.formView||this._areActionsVisible}_getBalloonPositionData(){const t=this.editor.editing.view,e=t.document,i=this._getSelectedLinkElement();return{target:i?t.domConverter.mapViewToDom(i):t.domConverter.viewRangeToDom(e.selection.getFirstRange())}}_getSelectedLinkElement(){const t=this.editor.editing.view,e=t.document.selection;if(e.isCollapsed)return im(e.getFirstPosition());{const i=e.getFirstRange().getTrimmed(),n=im(i.start),o=im(i.end);return n&&n==o&&t.createRangeIn(n).getTrimmed().isEqual(i)?n:null}}}function im(t){return t.getAncestors().find(t=>{return(e=t).is("attributeElement")&&!!e.getCustomProperty("link");var e})}class nm extends Jl{constructor(t,e){super(t),this.type=e}refresh(){this.value=this._getValue(),this.isEnabled=this._checkEnabled()}execute(){const t=this.editor.model,e=t.document,i=Array.from(e.selection.getSelectedBlocks()).filter(e=>sm(e,t.schema)),n=!0===this.value;t.change(t=>{if(n){let e=i[i.length-1].nextSibling,n=Number.POSITIVE_INFINITY,o=[];for(;e&&"listItem"==e.name&&0!==e.getAttribute("listIndent");){const t=e.getAttribute("listIndent");t<n&&(n=t);const i=t-n;o.push({element:e,listIndent:i}),e=e.nextSibling}o=o.reverse();for(const e of o)t.setAttribute("listIndent",e.listIndent,e.element)}if(!n){let t=Number.POSITIVE_INFINITY;for(const e of i)e.is("listItem")&&e.getAttribute("listIndent")<t&&(t=e.getAttribute("listIndent"));t=0===t?1:t,om(i,!0,t),om(i,!1,t)}for(const e of i.reverse())n&&"listItem"==e.name?t.rename(e,"paragraph"):n||"listItem"==e.name?n||"listItem"!=e.name||e.getAttribute("listType")==this.type||t.setAttribute("listType",this.type,e):(t.setAttributes({listType:this.type,listIndent:0},e),t.rename(e,"listItem"))})}_getValue(){const t=sh(this.editor.model.document.selection.getSelectedBlocks());return!!t&&t.is("listItem")&&t.getAttribute("listType")==this.type}_checkEnabled(){if(this.value)return!0;const t=this.editor.model.document.selection,e=this.editor.model.schema,i=sh(t.getSelectedBlocks());return!!i&&sm(i,e)}}function om(t,e,i){const n=e?t[0]:t[t.length-1];if(n.is("listItem")){let o=n[e?"previousSibling":"nextSibling"],s=n.getAttribute("listIndent");for(;o&&o.is("listItem")&&o.getAttribute("listIndent")>=i;)s>o.getAttribute("listIndent")&&(s=o.getAttribute("listIndent")),o.getAttribute("listIndent")==s&&t[e?"unshift":"push"](o),o=o[e?"previousSibling":"nextSibling"]}}function sm(t,e){return e.checkChild(t.parent,"listItem")&&!e.isObject(t)}class rm extends Jl{constructor(t,e){super(t),this._indentBy="forward"==e?1:-1}refresh(){this.isEnabled=this._checkEnabled()}execute(){const t=this.editor.model,e=t.document;let i=Array.from(e.selection.getSelectedBlocks());t.change(t=>{const e=i[i.length-1];let n=e.nextSibling;for(;n&&"listItem"==n.name&&n.getAttribute("listIndent")>e.getAttribute("listIndent");)i.push(n),n=n.nextSibling;this._indentBy<0&&(i=i.reverse());for(const e of i){const i=e.getAttribute("listIndent")+this._indentBy;i<0?t.rename(e,"paragraph"):t.setAttribute("listIndent",i,e)}})}_checkEnabled(){const t=sh(this.editor.model.document.selection.getSelectedBlocks());if(!t||!t.is("listItem"))return!1;if(this._indentBy>0){const e=t.getAttribute("listIndent"),i=t.getAttribute("listType");let n=t.previousSibling;for(;n&&n.is("listItem")&&n.getAttribute("listIndent")>=e;){if(n.getAttribute("listIndent")==e)return n.getAttribute("listType")==i;n=n.previousSibling}return!1}return!0}}function am(t,e){const i=e.mapper,n=e.writer,o="numbered"==t.getAttribute("listType")?"ol":"ul",s=function(t){const e=t.createContainerElement("li");return e.getFillerOffset=fm,e}(n),r=n.createContainerElement(o,null);return n.insert(n.createPositionAt(r,0),s),i.bindElements(t,s),s}function cm(t,e,i,n){const o=e.parent,s=i.mapper,r=i.writer;let a=s.toViewPosition(n.createPositionBefore(t));const c=hm(t.previousSibling,{sameIndent:!0,smallerIndent:!0,listIndent:t.getAttribute("listIndent")}),l=t.previousSibling;if(c&&c.getAttribute("listIndent")==t.getAttribute("listIndent")){const t=s.toViewElement(c);a=r.breakContainer(r.createPositionAfter(t))}else a=l&&"listItem"==l.name?s.toViewPosition(n.createPositionAt(l,"end")):s.toViewPosition(n.createPositionBefore(t));if(a=dm(a),r.insert(a,o),l&&"listItem"==l.name){const t=s.toViewElement(l),i=r.createRange(r.createPositionAt(t,0),a).getWalker({ignoreElementEnd:!0});for(const t of i)if(t.item.is("li")){const n=r.breakContainer(r.createPositionBefore(t.item)),o=t.item.parent,s=r.createPositionAt(e,"end");lm(r,s.nodeBefore,s.nodeAfter),r.move(r.createRangeOn(o),s),i.position=n}}else{const i=o.nextSibling;if(i&&(i.is("ul")||i.is("ol"))){let n=null;for(const e of i.getChildren()){const i=s.toModelElement(e);if(!(i&&i.getAttribute("listIndent")>t.getAttribute("listIndent")))break;n=e}n&&(r.breakContainer(r.createPositionAfter(n)),r.move(r.createRangeOn(n.parent),r.createPositionAt(e,"end")))}}lm(r,o,o.nextSibling),lm(r,o.previousSibling,o)}function lm(t,e,i){return!e||!i||"ul"!=e.name&&"ol"!=e.name||e.name!=i.name||e.getAttribute("class")!==i.getAttribute("class")?null:t.mergeContainers(t.createPositionAfter(e))}function dm(t){return t.getLastMatchingPosition(t=>t.item.is("uiElement"))}function hm(t,e){const i=!!e.sameIndent,n=!!e.smallerIndent,o=e.listIndent;let s=t;for(;s&&"listItem"==s.name;){const t=s.getAttribute("listIndent");if(i&&o==t||n&&o>t)return s;s=s.previousSibling}return null}function um(t,e,i,n){t.ui.componentFactory.add(e,o=>{const s=t.commands.get(e),r=new El(o);return r.set({label:i,icon:n,tooltip:!0,isToggleable:!0}),r.bind("isOn","isEnabled").to(s,"value","isEnabled"),r.on("execute",()=>{t.execute(e),t.editing.view.focus()}),r})}function fm(){const t=!this.isEmpty&&("ul"==this.getChild(0).name||"ol"==this.getChild(0).name);return this.isEmpty||t?0:Dn.call(this)}function mm(t){return(e,i,n)=>{const o=n.consumable;if(!o.test(i.item,"insert")||!o.test(i.item,"attribute:listType")||!o.test(i.item,"attribute:listIndent"))return;o.consume(i.item,"insert"),o.consume(i.item,"attribute:listType"),o.consume(i.item,"attribute:listIndent");const s=i.item;cm(s,am(s,n),n,t)}}function gm(t,e,i){if(!i.consumable.consume(e.item,"attribute:listType"))return;const n=i.mapper.toViewElement(e.item),o=i.writer;o.breakContainer(o.createPositionBefore(n)),o.breakContainer(o.createPositionAfter(n));const s=n.parent,r="numbered"==e.attributeNewValue?"ol":"ul";o.rename(r,s)}function pm(t,e,i){const n=i.mapper.toViewElement(e.item).parent,o=i.writer;lm(o,n,n.nextSibling),lm(o,n.previousSibling,n);for(const t of e.item.getChildren())i.consumable.consume(t,"insert")}function bm(t,e,i){if("listItem"!=e.item.name){let t=i.mapper.toViewPosition(e.range.start);const n=i.writer,o=[];for(;("ul"==t.parent.name||"ol"==t.parent.name)&&(t=n.breakContainer(t),"li"==t.parent.name);){const e=t,i=n.createPositionAt(t.parent,"end");if(!e.isEqual(i)){const t=n.remove(n.createRange(e,i));o.push(t)}t=n.createPositionAfter(t.parent)}if(o.length>0){for(let e=0;e<o.length;e++){const i=t.nodeBefore;if(t=n.insert(t,o[e]).end,e>0){const e=lm(n,i,i.nextSibling);e&&e.parent==i&&t.offset--}}lm(n,t.nodeBefore,t.nodeAfter)}}}function wm(t,e,i){const n=i.mapper.toViewPosition(e.position),o=n.nodeBefore,s=n.nodeAfter;lm(i.writer,o,s)}function km(t,e,i){if(i.consumable.consume(e.viewItem,{name:!0})){const t=i.writer,n=t.createElement("listItem"),o=function(t){let e=0,i=t.parent;for(;i;){if(i.is("li"))e++;else{const t=i.previousSibling;t&&t.is("li")&&e++}i=i.parent}return e}(e.viewItem);t.setAttribute("listIndent",o,n);const s=e.viewItem.parent&&"ol"==e.viewItem.parent.name?"numbered":"bulleted";t.setAttribute("listType",s,n);const r=i.splitToAllowedParent(n,e.modelCursor);if(!r)return;t.insert(n,r.position);const a=function(t,e,i){const{writer:n,schema:o}=i;let s=n.createPositionAfter(t);for(const r of e)if("ul"==r.name||"ol"==r.name)s=i.convertItem(r,s).modelCursor;else{const e=i.convertItem(r,n.createPositionAt(t,"end")),a=e.modelRange.start.nodeAfter;a&&a.is("element")&&!o.checkChild(t,a.name)&&(t=e.modelCursor.parent.is("listItem")?e.modelCursor.parent:Am(e.modelCursor),s=n.createPositionAfter(t))}return s}(n,e.viewItem.getChildren(),i);e.modelRange=t.createRange(e.modelCursor,a),r.cursorParent?e.modelCursor=t.createPositionAt(r.cursorParent,0):e.modelCursor=e.modelRange.end}}function _m(t,e,i){if(i.consumable.test(e.viewItem,{name:!0})){const t=Array.from(e.viewItem.getChildren());for(const e of t){!(e.is("li")||Tm(e))&&e._remove()}}}function vm(t,e,i){if(i.consumable.test(e.viewItem,{name:!0})){if(0===e.viewItem.childCount)return;const t=[...e.viewItem.getChildren()];let i=!1,n=!0;for(const e of t)i&&!Tm(e)&&e._remove(),e.is("text")?(n&&(e._data=e.data.replace(/^\s+/,"")),e.nextSibling&&!Tm(e.nextSibling)||(e._data=e.data.replace(/\s+$/,""))):Tm(e)&&(i=!0),n=!1}}function ym(t){return(e,i)=>{if(i.isPhantom)return;const n=i.modelPosition.nodeBefore;if(n&&n.is("listItem")){const e=i.mapper.toViewElement(n),o=e.getAncestors().find(Tm),s=t.createPositionAt(e,0).getWalker();for(const t of s){if("elementStart"==t.type&&t.item.is("li")){i.viewPosition=t.previousPosition;break}if("elementEnd"==t.type&&t.item==o){i.viewPosition=t.nextPosition;break}}}}}function xm(t,[e,i]){let n,o=e.is("documentFragment")?e.getChild(0):e;if(n=i?this.createSelection(i):this.document.selection,o&&o.is("listItem")){const t=n.getFirstPosition();let e=null;if(t.parent.is("listItem")?e=t.parent:t.nodeBefore&&t.nodeBefore.is("listItem")&&(e=t.nodeBefore),e){const t=e.getAttribute("listIndent");if(t>0)for(;o&&o.is("listItem");)o._setAttribute("listIndent",o.getAttribute("listIndent")+t),o=o.nextSibling}}}function Am(t){const e=new wr({startPosition:t});let i;do{i=e.next()}while(!i.value.item.is("listItem"));return i.value.item}function Cm(t,e,i,n,o,s){const r=hm(e.nodeBefore,{sameIndent:!0,smallerIndent:!0,listIndent:t,foo:"b"}),a=o.mapper,c=o.writer,l=r?r.getAttribute("listIndent"):null;let d;if(r)if(l==t){const t=a.toViewElement(r).parent;d=c.createPositionAfter(t)}else{const t=s.createPositionAt(r,"end");d=a.toViewPosition(t)}else d=i;d=dm(d);for(const t of[...n.getChildren()])Tm(t)&&(d=c.move(c.createRangeOn(t),d).end,lm(c,t,t.nextSibling),lm(c,t.previousSibling,t))}function Tm(t){return t.is("ol")||t.is("ul")}class Pm extends ql{static get pluginName(){return"ListEditing"}static get requires(){return[bf]}init(){const t=this.editor;t.model.schema.register("listItem",{inheritAllFrom:"$block",allowAttributes:["listType","listIndent"]});const e=t.data,i=t.editing;var n;t.model.document.registerPostFixer(e=>function(t,e){const i=t.document.differ.getChanges(),n=new Map;let o=!1;for(const n of i)if("insert"==n.type&&"listItem"==n.name)s(n.position);else if("insert"==n.type&&"listItem"!=n.name){if("$text"!=n.name){const i=n.position.nodeAfter;i.hasAttribute("listIndent")&&(e.removeAttribute("listIndent",i),o=!0),i.hasAttribute("listType")&&(e.removeAttribute("listType",i),o=!0);for(const e of Array.from(t.createRangeIn(i)).filter(t=>t.item.is("listItem")))s(e.previousPosition)}s(n.position.getShiftedBy(n.length))}else"remove"==n.type&&"listItem"==n.name?s(n.position):("attribute"==n.type&&"listIndent"==n.attributeKey||"attribute"==n.type&&"listType"==n.attributeKey)&&s(n.range.start);for(const t of n.values())r(t),a(t);return o;function s(t){const e=t.nodeBefore;if(e&&e.is("listItem")){let i=e;if(n.has(i))return;for(;i.previousSibling&&i.previousSibling.is("listItem");)if(i=i.previousSibling,n.has(i))return;n.set(t.nodeBefore,i)}else{const e=t.nodeAfter;e&&e.is("listItem")&&n.set(e,e)}}function r(t){let i=0,n=null;for(;t&&t.is("listItem");){const s=t.getAttribute("listIndent");if(s>i){let r;null===n?(n=s-i,r=i):(n>s&&(n=s),r=s-n),e.setAttribute("listIndent",r,t),o=!0}else n=null,i=t.getAttribute("listIndent")+1;t=t.nextSibling}}function a(t){let i=[],n=null;for(;t&&t.is("listItem");){const s=t.getAttribute("listIndent");if(n&&n.getAttribute("listIndent")>s&&(i=i.slice(0,s+1)),0!=s)if(i[s]){const n=i[s];t.getAttribute("listType")!=n&&(e.setAttribute("listType",n,t),o=!0)}else i[s]=t.getAttribute("listType");n=t,t=t.nextSibling}}}(t.model,e)),i.mapper.registerViewToModelLength("li",Sm),e.mapper.registerViewToModelLength("li",Sm),i.mapper.on("modelToViewPosition",ym(i.view)),i.mapper.on("viewToModelPosition",(n=t.model,(t,e)=>{const i=e.viewPosition,o=i.parent,s=e.mapper;if("ul"==o.name||"ol"==o.name){if(i.isAtEnd){const t=s.toModelElement(i.nodeBefore),o=s.getModelLength(i.nodeBefore);e.modelPosition=n.createPositionBefore(t).getShiftedBy(o)}else{const t=s.toModelElement(i.nodeAfter);e.modelPosition=n.createPositionBefore(t)}t.stop()}else if("li"==o.name&&i.nodeBefore&&("ul"==i.nodeBefore.name||"ol"==i.nodeBefore.name)){const r=s.toModelElement(o);let a=1,c=i.nodeBefore;for(;c&&Tm(c);)a+=s.getModelLength(c),c=c.previousSibling;e.modelPosition=n.createPositionBefore(r).getShiftedBy(a),t.stop()}})),e.mapper.on("modelToViewPosition",ym(i.view)),t.conversion.for("editingDowncast").add(e=>{e.on("insert",bm,{priority:"high"}),e.on("insert:listItem",mm(t.model)),e.on("attribute:listType:listItem",gm,{priority:"high"}),e.on("attribute:listType:listItem",pm,{priority:"low"}),e.on("attribute:listIndent:listItem",function(t){return(e,i,n)=>{if(!n.consumable.consume(i.item,"attribute:listIndent"))return;const o=n.mapper.toViewElement(i.item),s=n.writer;s.breakContainer(s.createPositionBefore(o)),s.breakContainer(s.createPositionAfter(o));const r=o.parent,a=r.previousSibling,c=s.createRangeOn(r);s.remove(c),a&&a.nextSibling&&lm(s,a,a.nextSibling),Cm(i.attributeOldValue+1,i.range.start,c.start,o,n,t),cm(i.item,o,n,t);for(const t of i.item.getChildren())n.consumable.consume(t,"insert")}}(t.model)),e.on("remove:listItem",function(t){return(e,i,n)=>{const o=n.mapper.toViewPosition(i.position).getLastMatchingPosition(t=>!t.item.is("li")).nodeAfter,s=n.writer;s.breakContainer(s.createPositionBefore(o)),s.breakContainer(s.createPositionAfter(o));const r=o.parent,a=r.previousSibling,c=s.createRangeOn(r),l=s.remove(c);a&&a.nextSibling&&lm(s,a,a.nextSibling),Cm(n.mapper.toModelElement(o).getAttribute("listIndent")+1,i.position,c.start,o,n,t);for(const t of s.createRangeIn(l).getItems())n.mapper.unbindViewElement(t);e.stop()}}(t.model)),e.on("remove",wm,{priority:"low"})}),t.conversion.for("dataDowncast").add(e=>{e.on("insert",bm,{priority:"high"}),e.on("insert:listItem",mm(t.model))}),t.conversion.for("upcast").add(t=>{t.on("element:ul",_m,{priority:"high"}),t.on("element:ol",_m,{priority:"high"}),t.on("element:li",vm,{priority:"high"}),t.on("element:li",km)}),t.model.on("insertContent",xm,{priority:"high"}),t.commands.add("numberedList",new nm(t,"numbered")),t.commands.add("bulletedList",new nm(t,"bulleted")),t.commands.add("indentList",new rm(t,"forward")),t.commands.add("outdentList",new rm(t,"backward"));const o=i.view.document;this.listenTo(o,"enter",(t,e)=>{const i=this.editor.model.document,n=i.selection.getLastPosition().parent;i.selection.isCollapsed&&"listItem"==n.name&&n.isEmpty&&(this.editor.execute("outdentList"),e.preventDefault(),t.stop())}),this.listenTo(o,"delete",(t,e)=>{if("backward"!==e.direction)return;const i=this.editor.model.document.selection;if(!i.isCollapsed)return;const n=i.getFirstPosition();if(!n.isAtStart)return;const o=n.parent;"listItem"===o.name&&(o.previousSibling&&"listItem"===o.previousSibling.name||(this.editor.execute("outdentList"),e.preventDefault(),t.stop()))},{priority:"high"});const s=t=>(e,i)=>{this.editor.commands.get(t).isEnabled&&(this.editor.execute(t),i())};t.keystrokes.set("Tab",s("indentList")),t.keystrokes.set("Shift+Tab",s("outdentList"))}afterInit(){const t=this.editor.commands,e=t.get("indent"),i=t.get("outdent");e&&e.registerChildCommand(t.get("indentList")),i&&i.registerChildCommand(t.get("outdentList"))}}function Sm(t){let e=1;for(const i of t.getChildren())if("ul"==i.name||"ol"==i.name)for(const t of i.getChildren())e+=Sm(t);return e}class Em extends ql{init(){const t=this.editor.t;um(this.editor,"numberedList",t("w"),'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M7 5.75c0 .414.336.75.75.75h9.5a.75.75 0 100-1.5h-9.5a.75.75 0 00-.75.75zM3.5 3v5H2V3.7H1v-1h2.5V3zM.343 17.857l2.59-3.257H2.92a.6.6 0 10-1.04 0H.302a2 2 0 113.995 0h-.001c-.048.405-.16.734-.333.988-.175.254-.59.692-1.244 1.312H4.3v1h-4l.043-.043zM7 14.75a.75.75 0 01.75-.75h9.5a.75.75 0 110 1.5h-9.5a.75.75 0 01-.75-.75z"/></svg>'),um(this.editor,"bulletedList",t("x"),'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M7 5.75c0 .414.336.75.75.75h9.5a.75.75 0 100-1.5h-9.5a.75.75 0 00-.75.75zm-6 0C1 4.784 1.777 4 2.75 4c.966 0 1.75.777 1.75 1.75 0 .966-.777 1.75-1.75 1.75C1.784 7.5 1 6.723 1 5.75zm6 9c0 .414.336.75.75.75h9.5a.75.75 0 100-1.5h-9.5a.75.75 0 00-.75.75zm-6 0c0-.966.777-1.75 1.75-1.75.966 0 1.75.777 1.75 1.75 0 .966-.777 1.75-1.75 1.75-.966 0-1.75-.777-1.75-1.75z"/></svg>')}}function Mm(t,e){return t=>{t.on("attribute:url:media",i)};function i(i,n,o){if(!o.consumable.consume(n.item,i.name))return;const s=n.attributeNewValue,r=o.writer,a=o.mapper.toViewElement(n.item);r.remove(r.createRangeIn(a));const c=t.getMediaViewElement(r,s,e);r.insert(r.createPositionAt(a,0),c)}}function Im(t,e,i,n){const o=t.createContainerElement("figure",{class:"media"});return o.getFillerOffset=Rm,t.insert(t.createPositionAt(o,0),e.getMediaViewElement(t,i,n)),o}function Nm(t){const e=t.getSelectedElement();return e&&e.is("media")?e:null}function Om(t,e,i){t.change(n=>{const o=n.createElement("media",{url:e});t.insertContent(o,i),n.setSelection(o,"on")})}function Rm(){return null}class Lm extends Jl{refresh(){const t=this.editor.model,e=t.document.selection,i=t.schema,n=e.getFirstPosition(),o=Nm(e);let s=n.parent;s!=s.root&&(s=s.parent),this.value=o?o.getAttribute("url"):null,this.isEnabled=i.checkChild(s,"media")}execute(t){const e=this.editor.model,i=e.document.selection,n=Nm(i);if(n)e.change(e=>{e.setAttribute("url",t,n)});else{const n=xh(i,e);Om(e,t,n)}}}class Dm{constructor(t,e){const i=e.providers,n=e.extraProviders||[],o=new Set(e.removeProviders),s=i.concat(n).filter(t=>{const e=t.name;return e?!o.has(e):(console.warn(Object(hi.a)("media-embed-no-provider-name: The configured media provider has no name and cannot be used."),{provider:t}),!1)});this.locale=t,this.providerDefinitions=s}hasMedia(t){return!!this._getMedia(t)}getMediaViewElement(t,e,i){return this._getMedia(e).getViewElement(t,i)}_getMedia(t){if(!t)return new zm(this.locale);t=t.trim();for(const e of this.providerDefinitions){const i=e.html;let n=e.url;Array.isArray(n)||(n=[n]);for(const e of n){const n=this._getUrlMatches(t,e);if(n)return new zm(this.locale,t,n,i)}}return null}_getUrlMatches(t,e){let i=t.match(e);if(i)return i;let n=t.replace(/^https?:\/\//,"");return i=n.match(e),i||(n=n.replace(/^www\./,""),i=n.match(e),i||null)}}class zm{constructor(t,e,i,n){this.url=this._getValidUrl(e),this._t=t.t,this._match=i,this._previewRenderer=n}getViewElement(t,e){const i={};if(e.renderForEditingView||e.renderMediaPreview&&this.url&&this._previewRenderer){this.url&&(i["data-oembed-url"]=this.url),e.renderForEditingView&&(i.class="ck-media__wrapper");const n=this._getPreviewHtml(e);return t.createUIElement("div",i,(function(t){const e=this.toDomElement(t);return e.innerHTML=n,e}))}return this.url&&(i.url=this.url),t.createEmptyElement("oembed",i)}_getPreviewHtml(t){return this._previewRenderer?this._previewRenderer(this._match):this.url&&t.renderForEditingView?this._getPlaceholderHtml():""}_getPlaceholderHtml(){const t=new Sl,e=new Pl;return t.text=this._t("Open media in new tab"),e.content='<svg viewBox="0 0 64 42" xmlns="http://www.w3.org/2000/svg"><path d="M47.426 17V3.713L63.102 0v19.389h-.001l.001.272c0 1.595-2.032 3.43-4.538 4.098-2.506.668-4.538-.083-4.538-1.678 0-1.594 2.032-3.43 4.538-4.098.914-.244 2.032-.565 2.888-.603V4.516L49.076 7.447v9.556A1.014 1.014 0 0049 17h-1.574zM29.5 17h-8.343a7.073 7.073 0 10-4.657 4.06v3.781H3.3a2.803 2.803 0 01-2.8-2.804V8.63a2.803 2.803 0 012.8-2.805h4.082L8.58 2.768A1.994 1.994 0 0110.435 1.5h8.985c.773 0 1.477.448 1.805 1.149l1.488 3.177H26.7c1.546 0 2.8 1.256 2.8 2.805V17zm-11.637 0H17.5a1 1 0 00-1 1v.05A4.244 4.244 0 1117.863 17zm29.684 2c.97 0 .953-.048.953.889v20.743c0 .953.016.905-.953.905H19.453c-.97 0-.953.048-.953-.905V19.89c0-.937-.016-.889.97-.889h28.077zm-4.701 19.338V22.183H24.154v16.155h18.692zM20.6 21.375v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616V37.53H20.6zm24.233-16.155v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615V37.53h-1.615zM29.485 25.283a.4.4 0 01.593-.35l9.05 4.977a.4.4 0 010 .701l-9.05 4.978a.4.4 0 01-.593-.35v-9.956z"/></svg>',e.viewBox="0 0 64 42",new Fc({tag:"div",attributes:{class:"ck ck-reset_all ck-media__placeholder"},children:[{tag:"div",attributes:{class:"ck-media__placeholder__icon"},children:[e]},{tag:"a",attributes:{class:"ck-media__placeholder__url",target:"_blank",rel:"noopener noreferrer",href:this.url},children:[{tag:"span",attributes:{class:"ck-media__placeholder__url__text"},children:[this.url]},t]}]}).render().outerHTML}_getValidUrl(t){return t?t.match(/^https?/)?t:"https://"+t:null}}i(79);class jm extends ql{static get pluginName(){return"MediaEmbedEditing"}constructor(t){super(t),t.config.define("mediaEmbed",{providers:[{name:"dailymotion",url:/^dailymotion\.com\/video\/(\w+)/,html:t=>'<div style="position: relative; padding-bottom: 100%; height: 0; ">'+`<iframe src="https://www.dailymotion.com/embed/video/${t[1]}" `+'style="position: absolute; width: 100%; height: 100%; top: 0; left: 0;" frameborder="0" width="480" height="270" allowfullscreen allow="autoplay"></iframe></div>'},{name:"spotify",url:[/^open\.spotify\.com\/(artist\/\w+)/,/^open\.spotify\.com\/(album\/\w+)/,/^open\.spotify\.com\/(track\/\w+)/],html:t=>'<div style="position: relative; padding-bottom: 100%; height: 0; padding-bottom: 126%;">'+`<iframe src="https://open.spotify.com/embed/${t[1]}" `+'style="position: absolute; width: 100%; height: 100%; top: 0; left: 0;" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe></div>'},{name:"youtube",url:[/^(?:m\.)?youtube\.com\/watch\?v=([\w-]+)/,/^(?:m\.)?youtube\.com\/v\/([\w-]+)/,/^youtube\.com\/embed\/([\w-]+)/,/^youtu\.be\/([\w-]+)/],html:t=>'<div style="position: relative; padding-bottom: 100%; height: 0; padding-bottom: 56.2493%;">'+`<iframe src="https://www.youtube.com/embed/${t[1]}" `+'style="position: absolute; width: 100%; height: 100%; top: 0; left: 0;" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe></div>'},{name:"vimeo",url:[/^vimeo\.com\/(\d+)/,/^vimeo\.com\/[^/]+\/[^/]+\/video\/(\d+)/,/^vimeo\.com\/album\/[^/]+\/video\/(\d+)/,/^vimeo\.com\/channels\/[^/]+\/(\d+)/,/^vimeo\.com\/groups\/[^/]+\/videos\/(\d+)/,/^vimeo\.com\/ondemand\/[^/]+\/(\d+)/,/^player\.vimeo\.com\/video\/(\d+)/],html:t=>'<div style="position: relative; padding-bottom: 100%; height: 0; padding-bottom: 56.2493%;">'+`<iframe src="https://player.vimeo.com/video/${t[1]}" `+'style="position: absolute; width: 100%; height: 100%; top: 0; left: 0;" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>'},{name:"instagram",url:/^instagram\.com\/p\/(\w+)/},{name:"twitter",url:/^twitter\.com/},{name:"googleMaps",url:/^google\.com\/maps/},{name:"flickr",url:/^flickr\.com/},{name:"facebook",url:/^facebook\.com/}]}),this.registry=new Dm(t.locale,t.config.get("mediaEmbed"))}init(){const t=this.editor,e=t.model.schema,i=t.t,n=t.conversion,o=t.config.get("mediaEmbed.previewsInData"),s=this.registry;t.commands.add("mediaEmbed",new Lm(t)),e.register("media",{isObject:!0,isBlock:!0,allowWhere:"$block",allowAttributes:["url"]}),n.for("dataDowncast").elementToElement({model:"media",view:(t,e)=>{const i=t.getAttribute("url");return Im(e,s,i,{renderMediaPreview:i&&o})}}),n.for("dataDowncast").add(Mm(s,{renderMediaPreview:o})),n.for("editingDowncast").elementToElement({model:"media",view:(t,e)=>{const n=t.getAttribute("url"),o=Im(e,s,n,{renderForEditingView:!0});return r=o,a=e,c=i("ah"),a.setCustomProperty("media",!0,r),_h(r,a,{label:c});var r,a,c}}),n.for("editingDowncast").add(Mm(s,{renderForEditingView:!0})),n.for("upcast").elementToElement({view:{name:"oembed",attributes:{url:!0}},model:(t,e)=>{const i=t.getAttribute("url");if(s.hasMedia(i))return e.createElement("media",{url:i})}}).elementToElement({view:{name:"div",attributes:{"data-oembed-url":!0}},model:(t,e)=>{const i=t.getAttribute("data-oembed-url");if(s.hasMedia(i))return e.createElement("media",{url:i})}})}}const Vm=/^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=]+$/;class Bm extends ql{static get requires(){return[Kl,Fd]}static get pluginName(){return"AutoMediaEmbed"}constructor(t){super(t),this._timeoutId=null,this._positionToInsert=null}init(){const t=this.editor,e=t.model.document;this.listenTo(t.plugins.get(Kl),"inputTransformation",()=>{const t=e.selection.getFirstRange(),i=sc.fromPosition(t.start);i.stickiness="toPrevious";const n=sc.fromPosition(t.end);n.stickiness="toNext",e.once("change:data",()=>{this._embedMediaBetweenPositions(i,n),i.detach(),n.detach()},{priority:"high"})}),t.commands.get("undo").on("execute",()=>{this._timeoutId&&(ts.window.clearTimeout(this._timeoutId),this._positionToInsert.detach(),this._timeoutId=null,this._positionToInsert=null)},{priority:"high"})}_embedMediaBetweenPositions(t,e){const i=this.editor,n=i.plugins.get(jm).registry,o=new Nr(t,e),s=o.getWalker({ignoreElementEnd:!0});let r="";for(const t of s)t.item.is("textProxy")&&(r+=t.item.data);if(r=r.trim(),!r.match(Vm))return;if(!n.hasMedia(r))return;i.commands.get("mediaEmbed").isEnabled&&(this._positionToInsert=sc.fromPosition(t),this._timeoutId=ts.window.setTimeout(()=>{i.model.change(t=>{let e;this._timeoutId=null,t.remove(o),"$graveyard"!==this._positionToInsert.root.rootName&&(e=this._positionToInsert),Om(i.model,r,e),this._positionToInsert.detach(),this._positionToInsert=null})},100))}}i(81);class Fm extends rl{constructor(t,e){super(e);const i=e.t;this.focusTracker=new Ic,this.keystrokes=new yc,this.urlInputView=this._createUrlInput(),this.saveButtonView=this._createButton(i("cf"),Ru,"ck-button-save"),this.saveButtonView.type="submit",this.cancelButtonView=this._createButton(i("cg"),Lu,"ck-button-cancel","cancel"),this._focusables=new Bc,this._focusCycler=new bl({focusables:this._focusables,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"shift + tab",focusNext:"tab"}}),this._validators=t,this.setTemplate({tag:"form",attributes:{class:["ck","ck-media-form"],tabindex:"-1"},children:[this.urlInputView,this.saveButtonView,this.cancelButtonView]})}render(){super.render(),Ou({view:this}),[this.urlInputView,this.saveButtonView,this.cancelButtonView].forEach(t=>{this._focusables.add(t),this.focusTracker.add(t.element)}),this.keystrokes.listenTo(this.element);const t=t=>t.stopPropagation();this.keystrokes.set("arrowright",t),this.keystrokes.set("arrowleft",t),this.keystrokes.set("arrowup",t),this.keystrokes.set("arrowdown",t),this.listenTo(this.urlInputView.element,"selectstart",(t,e)=>{e.stopPropagation()},{priority:"high"})}focus(){this._focusCycler.focusFirst()}get url(){return this.urlInputView.inputView.element.value.trim()}set url(t){this.urlInputView.inputView.element.value=t.trim()}isValid(){this.resetFormStatus();for(const t of this._validators){const e=t(this);if(e)return this.urlInputView.errorText=e,!1}return!0}resetFormStatus(){this.urlInputView.errorText=null,this.urlInputView.infoText=this._urlInputViewInfoDefault}_createUrlInput(){const t=this.locale.t,e=new Iu(this.locale,Nu),i=e.inputView;return this._urlInputViewInfoDefault=t("ch"),this._urlInputViewInfoTip=t("ci"),e.label=t("cj"),e.infoText=this._urlInputViewInfoDefault,i.placeholder="https://example.com",i.on("input",()=>{e.infoText=i.element.value?this._urlInputViewInfoTip:this._urlInputViewInfoDefault}),e}_createButton(t,e,i,n){const o=new El(this.locale);return o.set({label:t,icon:e,tooltip:!0}),o.extendTemplate({attributes:{class:i}}),n&&o.delegate("execute").to(this,n),o}}class Hm extends ql{static get requires(){return[jm]}static get pluginName(){return"MediaEmbedUI"}init(){const t=this.editor,e=t.commands.get("mediaEmbed"),i=t.plugins.get(jm).registry;this.form=new Fm(function(t,e){return[e=>{if(!e.url.length)return t("am")},i=>{if(!e.hasMedia(i.url))return t("an")}]}(t.t,i),t.locale),t.ui.componentFactory.add("mediaEmbed",i=>{const n=Dl(i);return this._setUpDropdown(n,this.form,e,t),this._setUpForm(this.form,n,e),n})}_setUpDropdown(t,e,i){const n=this.editor,o=n.t,s=t.buttonView;function r(){n.editing.view.focus(),t.isOpen=!1}t.bind("isEnabled").to(i),t.panelView.children.add(e),s.set({label:o("al"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M18.68 2.53c.6 0 .59-.03.59.55v12.84c0 .59.01.56-.59.56H1.29c-.6 0-.59.03-.59-.56V3.08c0-.58-.01-.55.6-.55h17.38zM15.77 14.5v-10H4.2v10h11.57zM2 4v1h1V4H2zm0 2v1h1V6H2zm0 2v1h1V8H2zm0 2v1h1v-1H2zm0 2v1h1v-1H2zm0 2v1h1v-1H2zM17 4v1h1V4h-1zm0 2v1h1V6h-1zm0 2v1h1V8h-1zm0 2v1h1v-1h-1zm0 2v1h1v-1h-1zm0 2v1h1v-1h-1zM7.5 6.677a.4.4 0 01.593-.351l5.133 2.824a.4.4 0 010 .7l-5.133 2.824a.4.4 0 01-.593-.35V6.676z"/></svg>',tooltip:!0}),s.on("open",()=>{e.url=i.value||"",e.urlInputView.select(),e.focus()},{priority:"low"}),t.on("submit",()=>{e.isValid()&&(n.execute("mediaEmbed",e.url),r())}),t.on("change:isOpen",()=>e.resetFormStatus()),t.on("cancel",()=>r())}_setUpForm(t,e,i){t.delegate("submit","cancel").to(e),t.urlInputView.bind("value").to(i,"value"),t.urlInputView.bind("isReadOnly").to(i,"isEnabled",t=>!t),t.saveButtonView.bind("isEnabled").to(i)}}i(83);function Um(t,e){if(!t.childCount)return;const i=new lf,n=function(t,e){const i=e.createRangeIn(t),n=new Di({name:/^p|h\d+$/,styles:{"mso-list":/.*/}}),o=[];for(const t of i)if("elementStart"===t.type&&n.match(t.item)){const e=Wm(t.item);o.push({element:t.item,id:e.id,order:e.order,indent:e.indent})}return o}(t,i);if(!n.length)return;let o=null;n.forEach((t,s)=>{if(!o||function(t,e){if(t.id!==e.id)return!0;const i=e.element.previousSibling;if(!i)return!0;return n=i,!(n.is("ol")||n.is("ul"));var n}(n[s-1],t)){const n=function(t,e){const i=new RegExp(`@list l${t.id}:level${t.indent}\\s*({[^}]*)`,"gi"),n=/mso-level-number-format:([^;]*);/gi,o=i.exec(e);let s="decimal";if(o&&o[1]){const t=n.exec(o[1]);t&&t[1]&&(s=t[1].trim())}return{type:"bullet"!==s&&"image"!==s?"ol":"ul",style:s}}(t,e);o=function(t,e,i){const n=new On(t.type),o=e.parent.getChildIndex(e);return i.insertChild(o,n,e.parent),n}(n,t.element,i)}const r=function(t,e){return function(t,e){const i=new Di({name:"span",styles:{"mso-list":"Ignore"}}),n=e.createRangeIn(t);for(const t of n)"elementStart"===t.type&&i.match(t.item)&&e.remove(t.item)}(t,e),e.rename("li",t)}(t.element,i);i.appendChild(r,o)})}function Wm(t){const e={},i=t.getStyle("mso-list");if(i){const t=i.match(/(^|\s+)l(\d+)/i),n=i.match(/\s*lfo(\d+)/i),o=i.match(/\s*level(\d+)/i);t&&n&&o&&(e.id=t[2],e.order=n[1],e.indent=o[1])}return e}const qm=/id=("|')docs-internal-guid-[-0-9a-f]+("|')/i;class $m{isActive(t){return qm.test(t)}execute(t){const e=new lf;!function(t,e){for(const i of t.getChildren())if(i.is("b")&&"normal"===i.getStyle("font-weight")){const n=t.getChildIndex(i);e.remove(i),e.insertChild(n,i.getChildren(),t)}}(t.content,e),function(t,e){for(const i of e.createRangeIn(t)){const t=i.item;if(t.is("li")){const i=t.getChild(0);i.is("p")&&e.unwrapElement(i)}}}(t.content,e)}}function Ym(t){return t.replace(/<span(?: class="Apple-converted-space"|)>(\s+)<\/span>/g,(t,e)=>1===e.length?" ":Array(e.length+1).join(" ").substr(0,e.length))}function Gm(t){const e=new DOMParser,i=function(t){return Ym(Ym(t)).replace(/(<span\s+style=['"]mso-spacerun:yes['"]>[\s]*?)[\r\n]+(\s*<\/span>)/g,"$1$2").replace(/<span\s+style=['"]mso-spacerun:yes['"]><\/span>/g,"").replace(/ <\//g," </").replace(/ <o:p><\/o:p>/g," <o:p></o:p>").replace(/<o:p>( |\u00A0)<\/o:p>/g,"").replace(/>(\s*[\r\n]\s*)</g,"><")}(function(t){const e=t.match(/<\/body>(.*?)(<\/html>|$)/);e&&e[1]&&(t=t.slice(0,e.index)+t.slice(e.index).replace(e[1],""));return t}(t=t.replace(/<!--\[if gte vml 1]>/g,""))),n=e.parseFromString(i,"text/html");!function(t){t.querySelectorAll("span[style*=spacerun]").forEach(t=>{const e=t.childNodes&&t.childNodes[0]&&t.childNodes[0].data&&t.childNodes[0].data.length||0;t.innerHTML=Array(e+1).join(" ").substr(0,e)})}(n);const o=n.body.innerHTML,s=function(t){const e=new os({blockFillerMode:"nbsp"}),i=t.createDocumentFragment(),n=t.body.childNodes;for(;n.length>0;)i.appendChild(n[0]);return e.domToView(i)}(n),r=function(t){const e=[],i=[],n=Array.from(t.getElementsByTagName("style"));for(const t of n)t.sheet&&t.sheet.cssRules&&t.sheet.cssRules.length&&(e.push(t.sheet),i.push(t.innerHTML));return{styles:e,stylesString:i.join(" ")}}(n);return{body:s,bodyString:o,styles:r.styles,stylesString:r.stylesString}}function Qm(t,e){if(!t.childCount)return;const i=new lf;!function(t,e,i){const n=i.createRangeIn(e),o=new Di({name:"img"}),s=[];for(const e of n)if(o.match(e.item)){const i=e.item,n=i.getAttribute("v:shapes")?i.getAttribute("v:shapes").split(" "):[];n.length&&n.every(e=>t.indexOf(e)>-1)?s.push(i):i.getAttribute("src")||s.push(i)}for(const t of s)i.remove(t)}(function(t,e){const i=e.createRangeIn(t),n=new Di({name:/v:(.+)/}),o=[];for(const t of i){const e=t.item,i=e.previousSibling&&e.previousSibling.name||null;n.match(e)&&e.getAttribute("o:gfxdata")&&"v:shapetype"!==i&&o.push(t.item.getAttribute("id"))}return o}(t,i),t,i),function(t,e){const i=e.createRangeIn(t),n=new Di({name:/v:(.+)/}),o=[];for(const t of i)n.match(t.item)&&o.push(t.item);for(const t of o)e.remove(t)}(t,i);const n=function(t,e){const i=e.createRangeIn(t),n=new Di({name:"img"}),o=[];for(const t of i)n.match(t.item)&&t.item.getAttribute("src").startsWith("file://")&&o.push(t.item);return o}(t,i);n.length&&function(t,e,i){if(t.length===e.length)for(let o=0;o<t.length;o++){const s=`data:${e[o].type};base64,${n=e[o].hex,btoa(n.match(/\w{2}/g).map(t=>String.fromCharCode(parseInt(t,16))).join(""))}`;i.setAttribute("src",s,t[o])}var n}(n,function(t){if(!t)return[];const e=/{\\pict[\s\S]+?\\bliptag-?\d+(\\blipupi-?\d+)?({\\\*\\blipuid\s?[\da-fA-F]+)?[\s}]*?/,i=new RegExp("(?:("+e.source+"))([\\da-fA-F\\s]+)\\}","g"),n=t.match(i),o=[];if(n)for(const t of n){let i=!1;t.includes("\\pngblip")?i="image/png":t.includes("\\jpegblip")&&(i="image/jpeg"),i&&o.push({hex:t.replace(e,"").replace(/[^\da-fA-F]/g,""),type:i})}return o}(e),i)}const Km=/<meta\s*name="?generator"?\s*content="?microsoft\s*word\s*\d+"?\/?>/i,Jm=/xmlns:o="urn:schemas-microsoft-com/i;class Zm{isActive(t){return Km.test(t)||Jm.test(t)}execute(t){const{body:e,stylesString:i}=Gm(t.dataTransfer.getData("text/html"));Um(e,i),Qm(e,t.dataTransfer.getData("text/rtf")),t.content=e}}function Xm(t,e){let i=e.parent;for(;i;){if(i.name===t)return i;i=i.parent}}function tg(t,e,i,n,o=1){e>o?n.setAttribute(t,e,i):n.removeAttribute(t,i)}function eg(t,e,i={}){const n=t.createElement("tableCell",i);t.insertElement("paragraph",n),t.insert(n,e)}function ig(){return t=>{t.on("element:table",(t,e,i)=>{const n=e.viewItem;if(!i.consumable.test(n,{name:!0}))return;const{rows:o,headingRows:s,headingColumns:r}=function(t){const e={headingRows:0,headingColumns:0},i=[],n=[];let o;for(const s of Array.from(t.getChildren()))if("tbody"===s.name||"thead"===s.name||"tfoot"===s.name){"thead"!==s.name||o||(o=s);const t=Array.from(s.getChildren()).filter(t=>t.is("element","tr"));for(const s of t)if("thead"===s.parent.name&&s.parent===o)e.headingRows++,i.push(s);else{n.push(s);const t=og(s);t>e.headingColumns&&(e.headingColumns=t)}}return e.rows=[...i,...n],e}(n),a={};r&&(a.headingColumns=r),s&&(a.headingRows=s);const c=i.writer.createElement("table",a),l=i.splitToAllowedParent(c,e.modelCursor);if(l){if(i.writer.insert(c,l.position),i.consumable.consume(n,{name:!0}),o.length)o.forEach(t=>i.convertItem(t,i.writer.createPositionAt(c,"end")));else{const t=i.writer.createElement("tableRow");i.writer.insert(t,i.writer.createPositionAt(c,"end")),eg(i.writer,i.writer.createPositionAt(t,"end"))}e.modelRange=i.writer.createRange(i.writer.createPositionBefore(c),i.writer.createPositionAfter(c)),l.cursorParent?e.modelCursor=i.writer.createPositionAt(l.cursorParent,0):e.modelCursor=e.modelRange.end}})}}function ng(t){return e=>{e.on(`element:${t}`,(t,e,i)=>{const n=e.viewItem;if(!i.consumable.test(n,{name:!0}))return;const o=i.writer.createElement("tableCell"),s=i.splitToAllowedParent(o,e.modelCursor);if(!s)return;i.writer.insert(o,s.position),i.consumable.consume(n,{name:!0});const r=i.writer.createPositionAt(o,0);i.convertChildren(n,r),o.childCount||i.writer.insertElement("paragraph",r),e.modelRange=i.writer.createRange(i.writer.createPositionBefore(o),i.writer.createPositionAfter(o)),e.modelCursor=e.modelRange.end})}}function og(t){let e=0,i=0;const n=Array.from(t.getChildren()).filter(t=>"th"===t.name||"td"===t.name);for(;i<n.length&&"th"===n[i].name;){const t=n[i];e+=parseInt(t.getAttribute("colspan")||1),i++}return e}class sg{constructor(t,e={}){this.table=t,this.startRow=e.startRow||0,this.endRow="number"==typeof e.endRow?e.endRow:void 0,this.includeSpanned=!!e.includeSpanned,this.column="number"==typeof e.column?e.column:void 0,this._skipRows=new Set,this._row=0,this._column=0,this._cellIndex=0,this._spannedCells=new Map,this._nextCellAtColumn=-1}[Symbol.iterator](){return this}next(){const t=this.table.getChild(this._row);if(!t||this._isOverEndRow())return{done:!0};let e,i,n;if(this._isSpanned(this._row,this._column))e=this._getSpanned(this._row,this._column),i=!this.includeSpanned||this._shouldSkipRow()||this._shouldSkipColumn(),n=this._formatOutValue(e,this._column,!0);else{if(e=t.getChild(this._cellIndex),!e)return this._row++,this._column=0,this._cellIndex=0,this._nextCellAtColumn=-1,this.next();const o=parseInt(e.getAttribute("colspan")||1),s=parseInt(e.getAttribute("rowspan")||1);(o>1||s>1)&&this._recordSpans(this._row,this._column,s,o,e),this._nextCellAtColumn=this._column+o,i=this._shouldSkipRow()||this._shouldSkipColumn(),n=this._formatOutValue(e,this._column,!1,s,o)}return this._column++,this._column==this._nextCellAtColumn&&this._cellIndex++,i?this.next():n}skipRow(t){this._skipRows.add(t)}_isOverEndRow(){return void 0!==this.endRow&&this._row>this.endRow}_formatOutValue(t,e,i,n=1,o=1){return{done:!1,value:{cell:t,row:this._row,column:e,isSpanned:i,rowspan:n,colspan:o,cellIndex:this._cellIndex}}}_shouldSkipRow(){const t=this._row<this.startRow,e=this._skipRows.has(this._row);return t||e}_shouldSkipColumn(){return void 0!==this.column&&this.column!=this._column}_isSpanned(t,e){if(!this._spannedCells.has(t))return!1;return this._spannedCells.get(t).has(e)}_getSpanned(t,e){return this._spannedCells.get(t).get(e)}_recordSpans(t,e,i,n,o){for(let i=e+1;i<=e+n-1;i++)this._markSpannedCell(t,i,o);for(let s=t+1;s<t+i;s++)for(let t=e;t<=e+n-1;t++)this._markSpannedCell(s,t,o)}_markSpannedCell(t,e,i){this._spannedCells.has(t)||this._spannedCells.set(t,new Map),this._spannedCells.get(t).set(e,i)}}function rg(t){return!!t.getCustomProperty("table")&&kh(t)}function ag(t){const e=t.getSelectedElement();return e&&rg(e)?e:null}function cg(t){const e=Xm("table",t.getFirstPosition());return e&&rg(e.parent)?e.parent:null}function lg(t={}){return e=>e.on("insert:table",(e,i,n)=>{const o=i.item;if(!n.consumable.consume(o,"insert"))return;n.consumable.consume(o,"attribute:headingRows:table"),n.consumable.consume(o,"attribute:headingColumns:table");const s=t&&t.asWidget,r=n.writer.createContainerElement("figure",{class:"table"}),a=n.writer.createContainerElement("table");let c;var l,d;n.writer.insert(n.writer.createPositionAt(r,0),a),s&&(l=r,(d=n.writer).setCustomProperty("table",!0,l),c=_h(l,d,{hasSelectionHandle:!0}));const h=new sg(o),u={headingRows:o.getAttribute("headingRows")||0,headingColumns:o.getAttribute("headingColumns")||0},f=new Map;for(const e of h){const{row:i,cell:s}=e,r=_g(kg(i,u),a,n),c=o.getChild(i),l=f.get(i)||bg(c,i,r,n);f.set(i,l),n.consumable.consume(s,"insert"),pg(e,u,n.writer.createPositionAt(l,"end"),n,t)}const m=n.mapper.toViewPosition(i.range.start);n.mapper.bindElements(o,s?c:r),n.writer.insert(m,s?c:r)})}function dg(t={}){return e=>e.on("insert:tableRow",(e,i,n)=>{const o=i.item;if(!n.consumable.consume(o,"insert"))return;const s=o.parent,r=Ag(n.mapper.toViewElement(s)),a=s.getChildIndex(o),c=new sg(s,{startRow:a,endRow:a}),l={headingRows:s.getAttribute("headingRows")||0,headingColumns:s.getAttribute("headingColumns")||0},d=new Map;for(const e of c){const i=_g(kg(a,l),r,n),s=d.get(a)||bg(o,a,i,n);d.set(a,s),n.consumable.consume(e.cell,"insert"),pg(e,l,n.writer.createPositionAt(s,"end"),n,t)}})}function hg(t={}){return e=>e.on("insert:tableCell",(e,i,n)=>{const o=i.item;if(!n.consumable.consume(o,"insert"))return;const s=o.parent,r=s.parent,a=r.getChildIndex(s),c=new sg(r,{startRow:a,endRow:a}),l={headingRows:r.getAttribute("headingRows")||0,headingColumns:r.getAttribute("headingColumns")||0};for(const e of c)if(e.cell===o){const i=n.mapper.toViewElement(s);return void pg(e,l,n.writer.createPositionAt(i,s.getChildIndex(o)),n,t)}})}function ug(t={}){const e=!!t.asWidget;return t=>t.on("attribute:headingRows:table",(t,i,n)=>{const o=i.item;if(!n.consumable.consume(i.item,t.name))return;const s=Ag(n.mapper.toViewElement(o)),r=i.attributeOldValue,a=i.attributeNewValue;if(a>r){const t=Array.from(o.getChildren()).filter(({index:t})=>c(t,r-1,a));xg(t,_g("thead",s,n),n,"end");for(const i of t)for(const t of i.getChildren())mg(t,"th",n,e);yg("tbody",s,n)}else{xg(Array.from(o.getChildren()).filter(({index:t})=>c(t,a-1,r)).reverse(),_g("tbody",s,n),n,0);const t=new sg(o,{startRow:a?a-1:a,endRow:r-1}),i={headingRows:o.getAttribute("headingRows")||0,headingColumns:o.getAttribute("headingColumns")||0};for(const o of t)gg(o,i,n,e);yg("thead",s,n)}function c(t,e,i){return t>e&&t<i}})}function fg(t={}){const e=!!t.asWidget;return t=>t.on("attribute:headingColumns:table",(t,i,n)=>{const o=i.item;if(!n.consumable.consume(i.item,t.name))return;const s={headingRows:o.getAttribute("headingRows")||0,headingColumns:o.getAttribute("headingColumns")||0},r=i.attributeOldValue,a=i.attributeNewValue,c=(r>a?r:a)-1;for(const t of new sg(o))t.column>c||gg(t,s,n,e)})}function mg(t,e,i,n){const o=i.writer,s=i.mapper.toViewElement(t);if(!s)return;let r;if(n){r=yh(o.createEditableElement(e,s.getAttributes()),o),o.insert(o.createPositionAfter(s),r),o.move(o.createRangeIn(s),o.createPositionAt(r,0)),o.remove(o.createRangeOn(s))}else r=o.rename(e,s);i.mapper.unbindViewElement(s),i.mapper.bindElements(t,r)}function gg(t,e,i,n){const{cell:o}=t,s=wg(t,e),r=i.mapper.toViewElement(o);r&&r.name!==s&&mg(o,s,i,n)}function pg(t,e,i,n,o){const s=o&&o.asWidget,r=wg(t,e),a=s?yh(n.writer.createEditableElement(r),n.writer):n.writer.createContainerElement(r),c=t.cell,l=c.getChild(0),d=1===c.childCount&&"paragraph"===l.name;if(n.writer.insert(i,a),d&&![...l.getAttributeKeys()].length){const t=c.getChild(0),e=n.writer.createPositionAt(a,"end");if(n.consumable.consume(t,"insert"),o.asWidget){const i=n.writer.createContainerElement("span",{style:"display:inline-block"});n.mapper.bindElements(t,i),n.writer.insert(e,i),n.mapper.bindElements(c,a)}else n.mapper.bindElements(c,a),n.mapper.bindElements(t,a)}else n.mapper.bindElements(c,a)}function bg(t,e,i,n){n.consumable.consume(t,"insert");const o=n.writer.createContainerElement("tr");n.mapper.bindElements(t,o);const s=t.parent.getAttribute("headingRows")||0,r=s>0&&e>=s?e-s:e,a=n.writer.createPositionAt(i,r);return n.writer.insert(a,o),o}function wg(t,e){const{row:i,column:n}=t,{headingColumns:o,headingRows:s}=e;return s&&s>i||o&&o>n?"th":"td"}function kg(t,e){return t<e.headingRows?"thead":"tbody"}function _g(t,e,i){const n=vg(t,e);return n||function(t,e,i){const n=i.writer.createContainerElement(t),o=i.writer.createPositionAt(e,"tbody"==t?"end":0);return i.writer.insert(o,n),n}(t,e,i)}function vg(t,e){for(const i of e.getChildren())if(i.name==t)return i}function yg(t,e,i){const n=vg(t,e);n&&0===n.childCount&&i.writer.remove(i.writer.createRangeOn(n))}function xg(t,e,i,n){for(const o of t){const t=i.mapper.toViewElement(o);t&&i.writer.move(i.writer.createRangeOn(t),i.writer.createPositionAt(e,n))}}function Ag(t){for(const e of t.getChildren())if("table"===e.name)return e}class Cg extends Jl{refresh(){const t=this.editor.model,e=t.document.selection,i=t.schema,n=function(t){const e=t.parent;return e===e.root?e:e.parent}(e.getFirstPosition());this.isEnabled=i.checkChild(n,"table")}execute(t={}){const e=this.editor.model,i=e.document.selection,n=this.editor.plugins.get("TableUtils"),o=parseInt(t.rows)||2,s=parseInt(t.columns)||2,r=xh(i,e);e.change(t=>{const i=n.createTable(t,o,s);e.insertContent(i,r),t.setSelection(t.createPositionAt(i.getNodeByPath([0,0,0]),0))})}}class Tg extends Jl{constructor(t,e={}){super(t),this.order=e.order||"below"}refresh(){const t=Xm("table",this.editor.model.document.selection.getFirstPosition());this.isEnabled=!!t}execute(){const t=this.editor,e=t.model.document.selection,i=t.plugins.get("TableUtils"),n=Xm("tableCell",e.getFirstPosition()).parent,o=n.parent,s=o.getChildIndex(n),r="below"===this.order?s+1:s;i.insertRows(o,{rows:1,at:r})}}class Pg extends Jl{constructor(t,e={}){super(t),this.order=e.order||"right"}refresh(){const t=Xm("table",this.editor.model.document.selection.getFirstPosition());this.isEnabled=!!t}execute(){const t=this.editor,e=t.model.document.selection,i=t.plugins.get("TableUtils"),n=Xm("tableCell",e.getFirstPosition()),o=n.parent.parent,{column:s}=i.getCellLocation(n),r="right"===this.order?s+1:s;i.insertColumns(o,{columns:1,at:r})}}class Sg extends Jl{constructor(t,e={}){super(t),this.direction=e.direction||"horizontally"}refresh(){const t=Xm("tableCell",this.editor.model.document.selection.getFirstPosition());this.isEnabled=!!t}execute(){const t=Xm("tableCell",this.editor.model.document.selection.getFirstPosition()),e="horizontally"===this.direction,i=this.editor.plugins.get("TableUtils");e?i.splitCellHorizontally(t,2):i.splitCellVertically(t,2)}}class Eg extends Jl{constructor(t,e){super(t),this.direction=e.direction,this.isHorizontal="right"==this.direction||"left"==this.direction}refresh(){const t=this._getMergeableCell();this.value=t,this.isEnabled=!!t}execute(){const t=this.editor.model,e=Xm("tableCell",t.document.selection.getFirstPosition()),i=this.value,n=this.direction;t.change(t=>{const o="right"==n||"down"==n,s=o?e:i,r=o?i:e,a=r.parent;!function(t,e,i){Mg(t)||(Mg(e)&&i.remove(i.createRangeIn(e)),i.move(i.createRangeIn(t),i.createPositionAt(e,"end")));i.remove(t)}(r,s,t);const c=this.isHorizontal?"colspan":"rowspan",l=parseInt(e.getAttribute(c)||1),d=parseInt(i.getAttribute(c)||1);t.setAttribute(c,l+d,s),t.setSelection(t.createRangeIn(s)),a.childCount||function(t,e){const i=t.parent,n=i.getChildIndex(t);for(const{cell:t,row:o,rowspan:s}of new sg(i,{endRow:n})){o+s-1>=n&&tg("rowspan",s-1,t,e)}e.remove(t)}(a,t)})}_getMergeableCell(){const t=Xm("tableCell",this.editor.model.document.selection.getFirstPosition());if(!t)return;const e=this.editor.plugins.get("TableUtils"),i=this.isHorizontal?function(t,e,i){const n=t.parent.parent,o="right"==e?t.nextSibling:t.previousSibling,s=n.getAttribute("headingColumns")||0;if(!o)return;const r="right"==e?t:o,a="right"==e?o:t,{column:c}=i.getCellLocation(r),{column:l}=i.getCellLocation(a),d=parseInt(r.getAttribute("colspan")||1),h=parseInt(a.getAttribute("colspan")||1),u="right"==e&&l+h>s,f="left"==e&&c+d>s-1;if(s&&(u||f))return;return c+d===l?o:void 0}(t,this.direction,e):function(t,e){const i=t.parent,n=i.parent,o=n.getChildIndex(i);if("down"==e&&o===n.childCount-1||"up"==e&&0===o)return;const s=parseInt(t.getAttribute("rowspan")||1),r=n.getAttribute("headingRows")||0,a="down"==e&&o+s===r,c="up"==e&&o===r;if(r&&(a||c))return;const l=parseInt(t.getAttribute("rowspan")||1),d="down"==e?o+l:o,h=[...new sg(n,{endRow:d})],u=h.find(e=>e.cell===t).column,f=h.find(({row:t,rowspan:i,column:n})=>n===u&&("down"==e?t===d:d===t+i));return f&&f.cell}(t,this.direction);if(!i)return;const n=this.isHorizontal?"rowspan":"colspan",o=parseInt(t.getAttribute(n)||1);return parseInt(i.getAttribute(n)||1)===o?i:void 0}}function Mg(t){return 1==t.childCount&&t.getChild(0).is("paragraph")&&t.getChild(0).isEmpty}class Ig extends Jl{refresh(){const t=Xm("tableCell",this.editor.model.document.selection.getFirstPosition());this.isEnabled=!!t&&t.parent.parent.childCount>1}execute(){const t=this.editor.model,e=Xm("tableCell",t.document.selection.getFirstPosition()).parent,i=e.parent,n=i.getChildIndex(e),o=i.getAttribute("headingRows")||0;t.change(t=>{o&&n<=o&&tg("headingRows",o-1,i,t,0);const s=[...new sg(i,{endRow:n})],r=new Map;s.filter(({row:t,rowspan:e})=>t===n&&e>1).forEach(({column:t,cell:e,rowspan:i})=>r.set(t,{cell:e,rowspanToSet:i-1})),s.filter(({row:t,rowspan:e})=>t<=n-1&&t+e>n).forEach(({cell:e,rowspan:i})=>tg("rowspan",i-1,e,t));const a=n+1,c=new sg(i,{includeSpanned:!0,startRow:a,endRow:a});let l;for(const{row:e,column:n,cell:o}of[...c])if(r.has(n)){const{cell:o,rowspanToSet:s}=r.get(n),a=l?t.createPositionAfter(l):t.createPositionAt(i.getChild(e),0);t.move(t.createRangeOn(o),a),tg("rowspan",s,o,t),l=o}else l=o;t.remove(e)})}}class Ng extends Jl{refresh(){const t=this.editor,e=t.model.document.selection,i=t.plugins.get("TableUtils"),n=Xm("tableCell",e.getFirstPosition());this.isEnabled=!!n&&i.getColumns(n.parent.parent)>1}execute(){const t=this.editor.model,e=Xm("tableCell",t.document.selection.getFirstPosition()),i=e.parent,n=i.parent,o=n.getAttribute("headingColumns")||0,s=n.getChildIndex(i),r=[...new sg(n)],a=r.find(t=>t.cell===e).column;t.change(t=>{o&&s<=o&&t.setAttribute("headingColumns",o-1,n);for(const{cell:e,column:i,colspan:n}of r)i<=a&&n>1&&i+n>a?tg("colspan",n-1,e,t):i===a&&t.remove(e)})}}class Og extends Jl{refresh(){const t=Xm("tableCell",this.editor.model.document.selection.getFirstPosition()),e=!!t;this.isEnabled=e,this.value=e&&this._isInHeading(t,t.parent.parent)}execute(t={}){const e=this.editor.model,i=Xm("tableCell",e.document.selection.getFirstPosition()).parent,n=i.parent,o=n.getAttribute("headingRows")||0,s=i.index;if(t.forceValue===this.value)return;const r=this.value?s:s+1;e.change(t=>{if(r){const e=function(t,e,i){const n=[],o=new sg(t,{startRow:e>i?i:0,endRow:e-1});for(const{row:t,rowspan:i,cell:s}of o)i>1&&t+i>e&&n.push(s);return n}(n,r,o);for(const i of e)Rg(i,r,t)}tg("headingRows",r,n,t,0)})}_isInHeading(t,e){const i=parseInt(e.getAttribute("headingRows")||0);return!!i&&t.parent.index<i}}function Rg(t,e,i){const n=t.parent,o=n.parent,s=e-n.index,r={},a=parseInt(t.getAttribute("rowspan"))-s;a>1&&(r.rowspan=a);const c=parseInt(t.getAttribute("colspan")||1);c>1&&(r.colspan=c);const l=o.getChildIndex(n),d=l+s,h=[...new sg(o,{startRow:l,endRow:d,includeSpanned:!0})];let u;for(const{row:e,column:n,cell:s,cellIndex:a}of h)if(s===t&&void 0===u&&(u=n),void 0!==u&&u===n&&e===d){const t=o.getChild(e),n=i.createPositionAt(t,a);eg(i,n,r)}tg("rowspan",s,t,i)}class Lg extends Jl{refresh(){const t=Xm("tableCell",this.editor.model.document.selection.getFirstPosition()),e=!!t;this.isEnabled=e,this.value=e&&this._isInHeading(t,t.parent.parent)}execute(t={}){const e=this.editor.model,i=e.document.selection,n=this.editor.plugins.get("TableUtils"),o=Xm("tableCell",i.getFirstPosition()),s=o.parent.parent,{column:r}=n.getCellLocation(o);if(t.forceValue===this.value)return;const a=this.value?r:r+1;e.change(t=>{tg("headingColumns",a,s,t,0)})}_isInHeading(t,e){const i=parseInt(e.getAttribute("headingColumns")||0),n=this.editor.plugins.get("TableUtils"),{column:o}=n.getCellLocation(t);return!!i&&o<i}}class Dg extends ql{static get pluginName(){return"TableUtils"}getCellLocation(t){const e=t.parent,i=e.parent,n=i.getChildIndex(e),o=new sg(i,{startRow:n,endRow:n});for(const{cell:e,row:i,column:n}of o)if(e===t)return{row:i,column:n}}createTable(t,e,i){const n=t.createElement("table");return zg(t,n,0,e,i),n}insertRows(t,e={}){const i=this.editor.model,n=e.at||0,o=e.rows||1;i.change(e=>{const i=t.getAttribute("headingRows")||0;if(i>n&&e.setAttribute("headingRows",i+o,t),0===n||n===t.childCount)return void zg(e,t,n,o,this.getColumns(t));const s=new sg(t,{endRow:n});let r=0;for(const{row:t,rowspan:i,colspan:a,cell:c}of s){const s=t+i>n;t<n&&s&&e.setAttribute("rowspan",i+o,c),t===n&&(r+=a)}zg(e,t,n,o,r)})}insertColumns(t,e={}){const i=this.editor.model,n=e.at||0,o=e.columns||1;i.change(e=>{const i=t.getAttribute("headingColumns");n<i&&e.setAttribute("headingColumns",i+o,t);const s=this.getColumns(t);if(0===n||s===n){for(const i of t.getChildren())jg(o,e,e.createPositionAt(i,n?"end":0));return}const r=new sg(t,{column:n,includeSpanned:!0});for(const{row:i,cell:s,cellIndex:a}of r){const c=parseInt(s.getAttribute("rowspan")||1),l=parseInt(s.getAttribute("colspan")||1);if(s.index!==n&&l>1){if(e.setAttribute("colspan",l+o,s),r.skipRow(i),c>1)for(let t=i+1;t<i+c;t++)r.skipRow(t)}else{const n=e.createPositionAt(t.getChild(i),a);jg(o,e,n)}}})}splitCellVertically(t,e=2){const i=this.editor.model,n=t.parent.parent,o=parseInt(t.getAttribute("rowspan")||1),s=parseInt(t.getAttribute("colspan")||1);i.change(i=>{if(s>1){const{newCellsSpan:n,updatedSpan:r}=Vg(s,e);tg("colspan",r,t,i);const a={};n>1&&(a.colspan=n),o>1&&(a.rowspan=o),jg(s>e?e-1:s-1,i,i.createPositionAfter(t),a)}if(s<e){const r=e-s,a=[...new sg(n)],{column:c}=a.find(({cell:e})=>e===t),l=a.filter(({cell:e,colspan:i,column:n})=>e!==t&&n===c||n<c&&n+i>c);for(const{cell:t,colspan:e}of l)i.setAttribute("colspan",e+r,t);const d={};o>1&&(d.rowspan=o),jg(r,i,i.createPositionAfter(t),d);const h=n.getAttribute("headingColumns")||0;h>c&&tg("headingColumns",h+r,n,i)}})}splitCellHorizontally(t,e=2){const i=this.editor.model,n=t.parent,o=n.parent,s=o.getChildIndex(n),r=parseInt(t.getAttribute("rowspan")||1),a=parseInt(t.getAttribute("colspan")||1);i.change(i=>{if(r>1){const n=[...new sg(o,{startRow:s,endRow:s+r-1,includeSpanned:!0})],{newCellsSpan:c,updatedSpan:l}=Vg(r,e);tg("rowspan",l,t,i);const{column:d}=n.find(({cell:e})=>e===t),h={};c>1&&(h.rowspan=c),a>1&&(h.colspan=a);for(const{column:t,row:e,cellIndex:r}of n){const n=t===d,a=(e+s+l)%c==0;if(e>=s+l&&n&&a){const t=i.createPositionAt(o.getChild(e),r);jg(1,i,t,h)}}}if(r<e){const n=e-r,c=[...new sg(o,{startRow:0,endRow:s})];for(const{cell:e,rowspan:o,row:r}of c)if(e!==t&&r+o>s){const t=o+n;i.setAttribute("rowspan",t,e)}const l={};a>1&&(l.colspan=a),zg(i,o,s+1,n,1,l);const d=o.getAttribute("headingRows")||0;d>s&&tg("headingRows",d+n,o,i)}})}getColumns(t){return[...t.getChild(0).getChildren()].reduce((t,e)=>t+parseInt(e.getAttribute("colspan")||1),0)}}function zg(t,e,i,n,o,s={}){for(let r=0;r<n;r++){const n=t.createElement("tableRow");t.insert(n,e,i),jg(o,t,t.createPositionAt(n,"end"),s)}}function jg(t,e,i,n={}){for(let o=0;o<t;o++)eg(e,i,n)}function Vg(t,e){if(t<e)return{newCellsSpan:1,updatedSpan:1};const i=Math.floor(t/e);return{newCellsSpan:i,updatedSpan:t-i*e+i}}function Bg(t){t.document.registerPostFixer(e=>function(t,e){const i=e.document.differ.getChanges();let n=!1;const o=new Set;for(const e of i){let i;"table"==e.name&&"insert"==e.type&&(i=e.position.nodeAfter),"tableRow"!=e.name&&"tableCell"!=e.name||(i=Xm("table",e.position)),Ug(e)&&(i=Xm("table",e.range.start)),i&&!o.has(i)&&(n=Fg(i,t)||n,n=Hg(i,t)||n,o.add(i))}return n}(e,t))}function Fg(t,e){let i=!1;const n=function(t){const e=parseInt(t.getAttribute("headingRows")||0),i=t.childCount,n=[];for(const{row:o,rowspan:s,cell:r}of new sg(t)){if(s<2)continue;const t=o<e?e:i;if(o+s>t){const e=t-o;n.push({cell:r,rowspan:e})}}return n}(t);if(n.length){i=!0;for(const t of n)tg("rowspan",t.rowspan,t.cell,e,1)}return i}function Hg(t,e){let i=!1;const n=function(t){const e={};for(const{row:i}of new sg(t,{includeSpanned:!0}))e[i]||(e[i]=0),e[i]+=1;return e}(t),o=n[0];if(!Object.values(n).every(t=>t===o)){const o=Object.values(n).reduce((t,e)=>e>t?e:t,0);for(const[s,r]of Object.entries(n)){const n=o-r;if(n){for(let i=0;i<n;i++)eg(e,e.createPositionAt(t.getChild(s),"end"));i=!0}}}return i}function Ug(t){const e="attribute"===t.type,i=t.attributeKey;return e&&("headingRows"===i||"colspan"===i||"rowspan"===i)}function Wg(t){t.document.registerPostFixer(e=>function(t,e){const i=e.document.differ.getChanges();let n=!1;for(const e of i)"insert"==e.type&&"table"==e.name&&(n=qg(e.position.nodeAfter,t)||n),"insert"==e.type&&"tableRow"==e.name&&(n=$g(e.position.nodeAfter,t)||n),"insert"==e.type&&"tableCell"==e.name&&(n=Yg(e.position.nodeAfter,t)||n),Gg(e)&&(n=Yg(e.position.parent,t)||n);return n}(e,t))}function qg(t,e){let i=!1;for(const n of t.getChildren())i=$g(n,e)||i;return i}function $g(t,e){let i=!1;for(const n of t.getChildren())i=Yg(n,e)||i;return i}function Yg(t,e){if(0==t.childCount)return e.insertElement("paragraph",t),!0;const i=Array.from(t.getChildren()).filter(t=>t.is("text"));for(const t of i)e.wrap(e.createRangeOn(t),"paragraph");return!!i.length}function Gg(t){return!(!t.position||!t.position.parent.is("tableCell"))&&("insert"==t.type&&"$text"==t.name||"remove"==t.type)}function Qg(t){t.document.registerPostFixer(()=>function(t){const e=t.document.differ,i=new Set;for(const t of e.getChanges()){const e="insert"==t.type||"remove"==t.type?t.position.parent:t.range.start.parent;e.is("tableCell")&&Kg(e,t.type)&&i.add(e)}if(i.size){for(const t of i.values())e.refreshItem(t);return!0}return!1}(t))}function Kg(t,e){if(!Array.from(t.getChildren()).some(t=>t.is("paragraph")))return!1;if("attribute"==e){const e=Array.from(t.getChild(0).getAttributeKeys()).length;return 1===t.childCount&&e<2}return t.childCount<=("insert"==e?2:1)}i(85);class Jg extends ql{static get pluginName(){return"TableEditing"}init(){const t=this.editor,e=t.model,i=e.schema,n=t.conversion;i.register("table",{allowWhere:"$block",allowAttributes:["headingRows","headingColumns"],isLimit:!0,isObject:!0,isBlock:!0}),i.register("tableRow",{allowIn:"table",isLimit:!0}),i.register("tableCell",{allowIn:"tableRow",allowAttributes:["colspan","rowspan"],isLimit:!0}),i.extend("$block",{allowIn:"tableCell"}),i.addChildCheck((t,e)=>{if("table"==e.name&&Array.from(t.getNames()).includes("table"))return!1}),n.for("upcast").add(ig()),n.for("editingDowncast").add(lg({asWidget:!0})),n.for("dataDowncast").add(lg()),n.for("upcast").elementToElement({model:"tableRow",view:"tr"}),n.for("editingDowncast").add(dg({asWidget:!0})),n.for("dataDowncast").add(dg()),n.for("downcast").add(t=>t.on("remove:tableRow",(t,e,i)=>{t.stop();const n=i.writer,o=i.mapper,s=o.toViewPosition(e.position).getLastMatchingPosition(t=>!t.item.is("tr")).nodeAfter,r=s.parent,a=n.createRangeOn(s),c=n.remove(a);for(const t of n.createRangeIn(c).getItems())o.unbindViewElement(t);r.childCount||n.remove(n.createRangeOn(r))},{priority:"higher"})),n.for("upcast").add(ng("td")),n.for("upcast").add(ng("th")),n.for("editingDowncast").add(hg({asWidget:!0})),n.for("dataDowncast").add(hg()),n.attributeToAttribute({model:"colspan",view:"colspan"}),n.attributeToAttribute({model:"rowspan",view:"rowspan"}),n.for("editingDowncast").add(fg({asWidget:!0})),n.for("dataDowncast").add(fg()),n.for("editingDowncast").add(ug({asWidget:!0})),n.for("dataDowncast").add(ug()),t.commands.add("insertTable",new Cg(t)),t.commands.add("insertTableRowAbove",new Tg(t,{order:"above"})),t.commands.add("insertTableRowBelow",new Tg(t,{order:"below"})),t.commands.add("insertTableColumnLeft",new Pg(t,{order:"left"})),t.commands.add("insertTableColumnRight",new Pg(t,{order:"right"})),t.commands.add("removeTableRow",new Ig(t)),t.commands.add("removeTableColumn",new Ng(t)),t.commands.add("splitTableCellVertically",new Sg(t,{direction:"vertically"})),t.commands.add("splitTableCellHorizontally",new Sg(t,{direction:"horizontally"})),t.commands.add("mergeTableCellRight",new Eg(t,{direction:"right"})),t.commands.add("mergeTableCellLeft",new Eg(t,{direction:"left"})),t.commands.add("mergeTableCellDown",new Eg(t,{direction:"down"})),t.commands.add("mergeTableCellUp",new Eg(t,{direction:"up"})),t.commands.add("setTableColumnHeader",new Lg(t)),t.commands.add("setTableRowHeader",new Og(t)),Bg(e),Qg(e),Wg(e),this.editor.keystrokes.set("Tab",(...t)=>this._handleTabOnSelectedTable(...t),{priority:"low"}),this.editor.keystrokes.set("Tab",this._getTabHandler(!0),{priority:"low"}),this.editor.keystrokes.set("Shift+Tab",this._getTabHandler(!1),{priority:"low"})}static get requires(){return[Dg]}_handleTabOnSelectedTable(t,e){const i=this.editor,n=i.model.document.selection;if(!n.isCollapsed&&1===n.rangeCount&&n.getFirstRange().isFlat){const t=n.getSelectedElement();if(!t||!t.is("table"))return;e(),i.model.change(e=>{e.setSelection(e.createRangeIn(t.getChild(0).getChild(0)))})}}_getTabHandler(t){const e=this.editor;return(i,n)=>{const o=Xm("tableCell",e.model.document.selection.getFirstPosition());if(!o)return;n();const s=o.parent,r=s.parent,a=r.getChildIndex(s),c=s.getChildIndex(o),l=0===c;if(!t&&l&&0===a)return;const d=c===s.childCount-1,h=a===r.childCount-1;if(t&&h&&d&&(e.execute("insertTableRowBelow"),a===r.childCount-1))return;let u;if(t&&d){const t=r.getChild(a+1);u=t.getChild(0)}else if(!t&&l){const t=r.getChild(a-1);u=t.getChild(t.childCount-1)}else u=s.getChild(c+(t?1:-1));e.model.change(t=>{t.setSelection(t.createRangeIn(u))})}}}i(87);class Zg extends rl{constructor(t){super(t);const e=this.bindTemplate;this.items=this.createCollection(),this.set("rows",0),this.set("columns",0),this.bind("label").to(this,"columns",this,"rows",(t,e)=>`${e} × ${t}`),this.setTemplate({tag:"div",attributes:{class:["ck"]},children:[{tag:"div",attributes:{class:["ck-insert-table-dropdown__grid"]},children:this.items},{tag:"div",attributes:{class:["ck-insert-table-dropdown__label"]},children:[{text:e.to("label")}]}],on:{mousedown:e.to(t=>{t.preventDefault()}),click:e.to(()=>{this.fire("execute")})}});for(let t=0;t<100;t++){const e=new Xg;e.on("over",()=>{const e=Math.floor(t/10),i=t%10;this.set("rows",e+1),this.set("columns",i+1)}),this.items.add(e)}this.on("change:columns",()=>{this._highlightGridBoxes()}),this.on("change:rows",()=>{this._highlightGridBoxes()})}focus(){}focusLast(){}_highlightGridBoxes(){const t=this.rows,e=this.columns;this.items.map((i,n)=>{const o=Math.floor(n/10)<t&&n%10<e;i.set("isOn",o)})}}class Xg extends rl{constructor(t){super(t);const e=this.bindTemplate;this.set("isOn",!1),this.setTemplate({tag:"div",attributes:{class:["ck-insert-table-dropdown-grid-box",e.if("isOn","ck-on")]},on:{mouseover:e.to("over")}})}}class tp extends ql{init(){const t=this.editor,e=this.editor.t,i="ltr"===t.locale.contentLanguageDirection;t.ui.componentFactory.add("insertTable",i=>{const n=t.commands.get("insertTable"),o=Dl(i);let s;return o.bind("isEnabled").to(n),o.buttonView.set({icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 6v3h4V6H3zm0 4v3h4v-3H3zm0 4v3h4v-3H3zm5 3h4v-3H8v3zm5 0h4v-3h-4v3zm4-4v-3h-4v3h4zm0-4V6h-4v3h4zm1.5 8a1.5 1.5 0 01-1.5 1.5H3A1.5 1.5 0 011.5 17V4c.222-.863 1.068-1.5 2-1.5h13c.932 0 1.778.637 2 1.5v13zM12 13v-3H8v3h4zm0-4V6H8v3h4z"/></svg>',label:e("ap"),tooltip:!0}),o.on("change:isOpen",()=>{s||(s=new Zg(i),o.panelView.children.add(s),s.delegate("execute").to(o),o.buttonView.on("open",()=>{s.rows=0,s.columns=0}),o.on("execute",()=>{t.execute("insertTable",{rows:s.rows,columns:s.columns}),t.editing.view.focus()}))}),o}),t.ui.componentFactory.add("tableColumn",t=>{const n=[{type:"switchbutton",model:{commandName:"setTableColumnHeader",label:e("aq"),bindIsOn:!0}},{type:"separator"},{type:"button",model:{commandName:i?"insertTableColumnLeft":"insertTableColumnRight",label:e("ar")}},{type:"button",model:{commandName:i?"insertTableColumnRight":"insertTableColumnLeft",label:e("as")}},{type:"button",model:{commandName:"removeTableColumn",label:e("at")}}];return this._prepareDropdown(e("au"),'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.5 1h15A1.5 1.5 0 0119 2.5v15a1.5 1.5 0 01-1.5 1.5h-15A1.5 1.5 0 011 17.5v-15A1.5 1.5 0 012.5 1zM2 2v16h16V2H2z" opacity=".6"/><path d="M18 7v1H2V7h16zm0 5v1H2v-1h16z" opacity=".6"/><path d="M14 1v18a1 1 0 01-1 1H7a1 1 0 01-1-1V1a1 1 0 011-1h6a1 1 0 011 1zm-2 1H8v4h4V2zm0 6H8v4h4V8zm0 6H8v4h4v-4z"/></svg>',n,t)}),t.ui.componentFactory.add("tableRow",t=>{const i=[{type:"switchbutton",model:{commandName:"setTableRowHeader",label:e("av"),bindIsOn:!0}},{type:"separator"},{type:"button",model:{commandName:"insertTableRowBelow",label:e("aw")}},{type:"button",model:{commandName:"insertTableRowAbove",label:e("ax")}},{type:"button",model:{commandName:"removeTableRow",label:e("ay")}}];return this._prepareDropdown(e("az"),'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.5 1h15A1.5 1.5 0 0119 2.5v15a1.5 1.5 0 01-1.5 1.5h-15A1.5 1.5 0 011 17.5v-15A1.5 1.5 0 012.5 1zM2 2v16h16V2H2z" opacity=".6"/><path d="M7 2h1v16H7V2zm5 0h1v16h-1V2z" opacity=".6"/><path d="M1 6h18a1 1 0 011 1v6a1 1 0 01-1 1H1a1 1 0 01-1-1V7a1 1 0 011-1zm1 2v4h4V8H2zm6 0v4h4V8H8zm6 0v4h4V8h-4z"/></svg>',i,t)}),t.ui.componentFactory.add("mergeTableCells",t=>{const n=[{type:"button",model:{commandName:"mergeTableCellUp",label:e("ba")}},{type:"button",model:{commandName:i?"mergeTableCellRight":"mergeTableCellLeft",label:e("bb")}},{type:"button",model:{commandName:"mergeTableCellDown",label:e("bc")}},{type:"button",model:{commandName:i?"mergeTableCellLeft":"mergeTableCellRight",label:e("bd")}},{type:"separator"},{type:"button",model:{commandName:"splitTableCellVertically",label:e("be")}},{type:"button",model:{commandName:"splitTableCellHorizontally",label:e("bf")}}];return this._prepareDropdown(e("bg"),'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.5 1h15A1.5 1.5 0 0119 2.5v15a1.5 1.5 0 01-1.5 1.5h-15A1.5 1.5 0 011 17.5v-15A1.5 1.5 0 012.5 1zM2 2v16h16V2H2z" opacity=".6"/><path d="M7 2h1v16H7V2zm5 0h1v7h-1V2zm6 5v1H2V7h16zM8 12v1H2v-1h6z" opacity=".6"/><path d="M7 7h12a1 1 0 011 1v11a1 1 0 01-1 1H7a1 1 0 01-1-1V8a1 1 0 011-1zm1 2v9h10V9H8z"/></svg>',n,t)})}_prepareDropdown(t,e,i,n){const o=this.editor,s=Dl(n),r=[],a=new yi;for(const t of i)ep(t,o,r,a);return jl(s,a,o.ui.componentFactory),s.buttonView.set({label:t,icon:e,tooltip:!0}),s.bind("isEnabled").toMany(r,"isEnabled",(...t)=>t.some(t=>t)),this.listenTo(s,"execute",t=>{o.execute(t.source.commandName),o.editing.view.focus()}),s}}function ep(t,e,i,n){const o=t.model=new xf(t.model),{commandName:s,bindIsOn:r}=t.model;if("button"===t.type||"switchbutton"===t.type){const t=e.commands.get(s);i.push(t),o.set({commandName:s}),o.bind("isEnabled").to(t),r&&o.bind("isOn").to(t,"value")}o.set({withText:!0}),n.add(t)}i(89);class ip extends ql{static get pluginName(){return"UnderlineEditing"}init(){const t=this.editor;t.model.schema.extend("$text",{allowAttributes:"underline"}),t.model.schema.setAttributeProperties("underline",{isFormatting:!0,copyOnEnter:!0}),t.conversion.attributeToElement({model:"underline",view:"u",upcastAlso:{styles:{"text-decoration":"underline"}}}),t.commands.add("underline",new th(t,"underline")),t.keystrokes.set("CTRL+U","underline")}}class np extends ql{init(){const t=this.editor,e=t.t;t.ui.componentFactory.add("underline",i=>{const n=t.commands.get("underline"),o=new El(i);return o.set({label:e("f"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 18v-1.5h14V18zm2.2-8V3.6c0-.4.4-.6.8-.6.3 0 .7.2.7.6v6.2c0 2 1.3 2.8 3.2 2.8 1.9 0 3.4-.9 3.4-2.9V3.6c0-.3.4-.5.8-.5.3 0 .7.2.7.5V10c0 2.7-2.2 4-4.9 4-2.6 0-4.7-1.2-4.7-4z"/></svg>',keystroke:"CTRL+U",tooltip:!0,isToggleable:!0}),o.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(o,"execute",()=>{t.execute("underline"),t.editing.view.focus()}),o})}}class op extends ql{static get pluginName(){return"StrikethroughEditing"}init(){const t=this.editor;t.model.schema.extend("$text",{allowAttributes:"strikethrough"}),t.model.schema.setAttributeProperties("strikethrough",{isFormatting:!0,copyOnEnter:!0}),t.conversion.attributeToElement({model:"strikethrough",view:"s",upcastAlso:["del","strike",{styles:{"text-decoration":"line-through"}}]}),t.commands.add("strikethrough",new th(t,"strikethrough")),t.keystrokes.set("CTRL+SHIFT+X","strikethrough")}}class sp extends ql{init(){const t=this.editor,e=t.t;t.ui.componentFactory.add("strikethrough",i=>{const n=t.commands.get("strikethrough"),o=new El(i);return o.set({label:e("e"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M7 16.4c-.8-.4-1.5-.9-2.2-1.5a.6.6 0 01-.2-.5l.3-.6h1c1 1.2 2.1 1.7 3.7 1.7 1 0 1.8-.3 2.3-.6.6-.4.6-1.2.6-1.3.2-1.2-.9-2.1-.9-2.1h2.1c.3.7.4 1.2.4 1.7v.8l-.6 1.2c-.6.8-1.1 1-1.6 1.2a6 6 0 01-2.4.6c-1 0-1.8-.3-2.5-.6zM6.8 9L6 8.3c-.4-.5-.5-.8-.5-1.6 0-.7.1-1.3.5-1.8.4-.6 1-1 1.6-1.3a6.3 6.3 0 014.7 0 4 4 0 011.7 1l.3.7c0 .1.2.4-.2.7-.4.2-.9.1-1 0a3 3 0 00-1.2-1c-.4-.2-1-.3-2-.4-.7 0-1.4.2-2 .6-.8.6-1 .8-1 1.5 0 .8.5 1 1.2 1.5.6.4 1.1.7 1.9 1H6.8z"/><path d="M3 10.5V9h14v1.5z"/></svg>',keystroke:"CTRL+SHIFT+X",tooltip:!0,isToggleable:!0}),o.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(o,"execute",()=>{t.execute("strikethrough"),t.editing.view.focus()}),o})}}class rp extends ql{static get pluginName(){return"CodeEditing"}init(){const t=this.editor;t.model.schema.extend("$text",{allowAttributes:"code"}),t.model.schema.setAttributeProperties("code",{isFormatting:!0,copyOnEnter:!0}),t.conversion.attributeToElement({model:"code",view:"code",upcastAlso:{styles:{"word-wrap":"break-word"}}}),t.commands.add("code",new th(t,"code"))}}i(12);class ap extends ql{init(){const t=this.editor,e=t.t;t.ui.componentFactory.add("code",i=>{const n=t.commands.get("code"),o=new El(i);return o.set({label:e("i"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M12.5 5.7l5.2 3.9v1.3l-5.6 4c-.1.2-.3.2-.5.2-.3-.1-.6-.7-.6-1l.3-.4 4.7-3.5L11.5 7l-.2-.2c-.1-.3-.1-.6 0-.8.2-.2.5-.4.8-.4a.8.8 0 01.4.1zm-5.2 0L2 9.6v1.3l5.6 4c.1.2.3.2.5.2.3-.1.7-.7.6-1 0-.1 0-.3-.2-.4l-5-3.5L8.2 7l.2-.2c.1-.3.1-.6 0-.8-.2-.2-.5-.4-.8-.4a.8.8 0 00-.3.1z"/></svg>',tooltip:!0,isToggleable:!0}),o.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(o,"execute",()=>{t.execute("code"),t.editing.view.focus()}),o})}}class cp extends ql{static get pluginName(){return"SubscriptEditing"}init(){const t=this.editor;t.model.schema.extend("$text",{allowAttributes:"subscript"}),t.model.schema.setAttributeProperties("subscript",{isFormatting:!0,copyOnEnter:!0}),t.conversion.attributeToElement({model:"subscript",view:"sub",upcastAlso:[{styles:{"vertical-align":"sub"}}]}),t.commands.add("subscript",new th(t,"subscript"))}}class lp extends ql{init(){const t=this.editor,e=t.t;t.ui.componentFactory.add("subscript",i=>{const n=t.commands.get("subscript"),o=new El(i);return o.set({label:e("h"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M7.03 10.349l3.818-3.819a.8.8 0 111.132 1.132L8.16 11.48l3.819 3.818a.8.8 0 11-1.132 1.132L7.03 12.61l-3.818 3.82a.8.8 0 11-1.132-1.132L5.9 11.48 2.08 7.662A.8.8 0 113.212 6.53l3.818 3.82zm8.147 7.829h2.549c.254 0 .447.05.58.152a.49.49 0 01.201.413.54.54 0 01-.159.393c-.105.108-.266.162-.48.162h-3.594c-.245 0-.435-.066-.572-.197a.621.621 0 01-.205-.463c0-.114.044-.265.132-.453a1.62 1.62 0 01.288-.444c.433-.436.824-.81 1.172-1.122.348-.312.597-.517.747-.615.267-.183.49-.368.667-.553.177-.185.312-.375.405-.57.093-.194.139-.384.139-.57a1.008 1.008 0 00-.554-.917 1.197 1.197 0 00-.56-.133c-.426 0-.761.182-1.005.546a2.332 2.332 0 00-.164.39 1.609 1.609 0 01-.258.488c-.096.114-.237.17-.423.17a.558.558 0 01-.405-.156.568.568 0 01-.161-.427c0-.218.05-.446.151-.683.101-.238.252-.453.452-.646s.454-.349.762-.467a2.998 2.998 0 011.081-.178c.498 0 .923.076 1.274.228a1.916 1.916 0 011.004 1.032 1.984 1.984 0 01-.156 1.794c-.2.32-.405.572-.613.754-.208.182-.558.468-1.048.857-.49.39-.826.691-1.008.906a2.703 2.703 0 00-.24.309z"/></svg>',tooltip:!0,isToggleable:!0}),o.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(o,"execute",()=>{t.execute("subscript"),t.editing.view.focus()}),o})}}class dp extends ql{static get pluginName(){return"SuperscriptEditing"}init(){const t=this.editor;t.model.schema.extend("$text",{allowAttributes:"superscript"}),t.model.schema.setAttributeProperties("superscript",{isFormatting:!0,copyOnEnter:!0}),t.conversion.attributeToElement({model:"superscript",view:"sup",upcastAlso:[{styles:{"vertical-align":"super"}}]}),t.commands.add("superscript",new th(t,"superscript"))}}class hp extends ql{init(){const t=this.editor,e=t.t;t.ui.componentFactory.add("superscript",i=>{const n=t.commands.get("superscript"),o=new El(i);return o.set({label:e("j"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M15.677 8.678h2.549c.254 0 .447.05.58.152a.49.49 0 01.201.413.54.54 0 01-.159.393c-.105.108-.266.162-.48.162h-3.594c-.245 0-.435-.066-.572-.197a.621.621 0 01-.205-.463c0-.114.044-.265.132-.453a1.62 1.62 0 01.288-.444c.433-.436.824-.81 1.172-1.122.348-.312.597-.517.747-.615.267-.183.49-.368.667-.553.177-.185.312-.375.405-.57.093-.194.139-.384.139-.57a1.008 1.008 0 00-.554-.917 1.197 1.197 0 00-.56-.133c-.426 0-.761.182-1.005.546a2.332 2.332 0 00-.164.39 1.609 1.609 0 01-.258.488c-.096.114-.237.17-.423.17a.558.558 0 01-.405-.156.568.568 0 01-.161-.427c0-.218.05-.446.151-.683.101-.238.252-.453.452-.646s.454-.349.762-.467a2.998 2.998 0 011.081-.178c.498 0 .923.076 1.274.228a1.916 1.916 0 011.004 1.032 1.984 1.984 0 01-.156 1.794c-.2.32-.405.572-.613.754-.208.182-.558.468-1.048.857-.49.39-.826.691-1.008.906a2.703 2.703 0 00-.24.309zM7.03 10.349l3.818-3.819a.8.8 0 111.132 1.132L8.16 11.48l3.819 3.818a.8.8 0 11-1.132 1.132L7.03 12.61l-3.818 3.82a.8.8 0 11-1.132-1.132L5.9 11.48 2.08 7.662A.8.8 0 113.212 6.53l3.818 3.82z"/></svg>',tooltip:!0,isToggleable:!0}),o.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(o,"execute",()=>{t.execute("superscript"),t.editing.view.focus()}),o})}}class up extends ql{static get pluginName(){return"RemoveFormatUI"}init(){const t=this.editor,e=t.t;t.ui.componentFactory.add("removeFormat",i=>{const n=t.commands.get("removeFormat"),o=new El(i);return o.set({label:e("ao"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M8.69 14.915c.053.052.173.083.36.093a.366.366 0 01.345.485l-.003.01a.738.738 0 01-.697.497h-2.67a.374.374 0 01-.353-.496l.013-.038a.681.681 0 01.644-.458c.197-.012.325-.043.386-.093a.28.28 0 00.072-.11L9.592 4.5H6.269c-.359-.017-.609.013-.75.09-.142.078-.289.265-.442.563-.192.29-.516.464-.864.464H4.17a.43.43 0 01-.407-.569L4.46 3h13.08l-.62 2.043a.81.81 0 01-.775.574h-.114a.486.486 0 01-.486-.486c.001-.284-.054-.464-.167-.54-.112-.076-.367-.106-.766-.091h-3.28l-2.68 10.257c-.006.074.007.127.038.158zM3 17h8a.5.5 0 110 1H3a.5.5 0 110-1zm11.299 1.17a.75.75 0 11-1.06-1.06l1.414-1.415-1.415-1.414a.75.75 0 011.06-1.06l1.415 1.414 1.414-1.415a.75.75 0 111.06 1.06l-1.413 1.415 1.414 1.415a.75.75 0 01-1.06 1.06l-1.415-1.414-1.414 1.414z"/></svg>',tooltip:!0}),o.bind("isOn","isEnabled").to(n,"value","isEnabled"),this.listenTo(o,"execute",()=>{t.execute("removeFormat"),t.editing.view.focus()}),o})}}class fp extends Jl{refresh(){const t=this.editor.model;this.isEnabled=!!sh(this._getFormattingItems(t.document.selection,t.schema))}execute(){const t=this.editor.model,e=t.schema;t.change(i=>{for(const n of this._getFormattingItems(t.document.selection,e))if(n.is("selection"))for(const t of this._getFormattingAttributes(n,e))i.removeSelectionAttribute(t);else{const t=i.createRangeOn(n);for(const o of this._getFormattingAttributes(n,e))i.removeAttribute(o,t)}})}*_getFormattingItems(t,e){const i=t=>!!sh(this._getFormattingAttributes(t,e));for(const e of t.getRanges())for(const t of e.getItems())i(t)&&(yield t);i(t)&&(yield t)}*_getFormattingAttributes(t,e){for(const[i]of t.getAttributes()){const t=e.getAttributeProperties(i);t&&t.isFormatting&&(yield i)}}}class mp extends ql{static get pluginName(){return"RemoveFormatEditing"}init(){const t=this.editor;t.commands.add("removeFormat",new fp(t))}}class gp extends Jl{refresh(){this.isEnabled=function(t){const e=t.schema,i=t.document.selection;return function(t,e,i){const n=function(t,e){const i=xh(t,e).parent;if(i.isEmpty&&!i.is("$root"))return i.parent;return i}(t,i);return e.checkChild(n,"horizontalLine")}(i,e,t)&&!function(t,e){const i=t.getSelectedElement();return i&&e.isObject(i)}(i,e)}(this.editor.model)}execute(){const t=this.editor.model;t.change(e=>{const i=e.createElement("horizontalLine");t.insertContent(i);let n=i.nextSibling;!(n&&t.schema.checkChild(n,"$text"))&&t.schema.checkChild(i.parent,"paragraph")&&(n=e.createElement("paragraph"),t.insertContent(n,e.createPositionAfter(i))),n&&e.setSelection(n,0)})}}i(92);class pp extends ql{static get pluginName(){return"HorizontalLineEditing"}init(){const t=this.editor,e=t.model.schema,i=t.t,n=t.conversion;e.register("horizontalLine",{isObject:!0,allowWhere:"$block"}),n.for("dataDowncast").elementToElement({model:"horizontalLine",view:(t,e)=>e.createEmptyElement("hr")}),n.for("editingDowncast").elementToElement({model:"horizontalLine",view:(t,e)=>{const n=i("ak"),o=e.createContainerElement("div"),s=e.createEmptyElement("hr");return e.addClass("ck-horizontal-line",o),e.setCustomProperty("hr",!0,o),e.insert(e.createPositionAt(o,0),s),function(t,e,i){return e.setCustomProperty("horizontalLine",!0,t),_h(t,e,{label:i})}(o,e,n)}}),n.for("upcast").elementToElement({view:"hr",model:"horizontalLine"}),t.commands.add("horizontalLine",new gp(t))}}class bp extends ql{init(){const t=this.editor,e=t.t;t.ui.componentFactory.add("horizontalLine",i=>{const n=t.commands.get("horizontalLine"),o=new El(i);return o.set({label:e("ak"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 9h16v2H2z"/></svg>',tooltip:!0}),o.bind("isEnabled").to(n,"isEnabled"),this.listenTo(o,"execute",()=>{t.execute("horizontalLine"),t.editing.view.focus()}),o})}}class wp{constructor(t){this.loader=t}upload(){return new Promise((t,e)=>{const i=this.reader=new window.FileReader;i.addEventListener("load",()=>{t({default:i.result})}),i.addEventListener("error",t=>{e(t)}),i.addEventListener("abort",()=>{e()}),this.loader.file.then(t=>{i.readAsDataURL(t)})})}abort(){this.reader.abort()}}const kp=["left","right","center","justify"];function _p(t){return kp.includes(t)}function vp(t,e){return"rtl"==e.contentLanguageDirection?"right"===t:"left"===t}class yp extends Jl{refresh(){const t=this.editor.locale,e=sh(this.editor.model.document.selection.getSelectedBlocks());this.isEnabled=!!e&&this._canBeAligned(e),this.isEnabled&&e.hasAttribute("alignment")?this.value=e.getAttribute("alignment"):this.value="rtl"===t.contentLanguageDirection?"right":"left"}execute(t={}){const e=this.editor,i=e.locale,n=e.model,o=n.document,s=t.value;n.change(t=>{const e=Array.from(o.selection.getSelectedBlocks()).filter(t=>this._canBeAligned(t)),n=e[0].getAttribute("alignment");vp(s,i)||n===s||!s?function(t,e){for(const i of t)e.removeAttribute("alignment",i)}(e,t):function(t,e,i){for(const n of t)e.setAttribute("alignment",i,n)}(e,t,s)})}_canBeAligned(t){return this.editor.model.schema.checkAttribute(t,"alignment")}}class xp extends ql{static get pluginName(){return"AlignmentEditing"}constructor(t){super(t),t.config.define("alignment",{options:[...kp]})}init(){const t=this.editor,e=t.locale,i=t.model.schema,n=t.config.get("alignment.options").filter(_p);i.extend("$block",{allowAttributes:"alignment"}),t.model.schema.setAttributeProperties("alignment",{isFormatting:!0});const o=function(t){const e={model:{key:"alignment",values:t.slice()},view:{}};for(const i of t)e.view[i]={key:"style",value:{"text-align":i}};return e}(n.filter(t=>!vp(t,e)));t.conversion.attributeToAttribute(o),t.commands.add("alignment",new yp(t))}}var Ap='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0-8c0 .414.336.75.75.75h9.929a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75z"/></svg>',Cp='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M18 3.75a.75.75 0 01-.75.75H2.75a.75.75 0 110-1.5h14.5a.75.75 0 01.75.75zm0 8a.75.75 0 01-.75.75H2.75a.75.75 0 110-1.5h14.5a.75.75 0 01.75.75zm0 4a.75.75 0 01-.75.75H7.321a.75.75 0 110-1.5h9.929a.75.75 0 01.75.75zm0-8a.75.75 0 01-.75.75H7.321a.75.75 0 110-1.5h9.929a.75.75 0 01.75.75z"/></svg>';const Tp=new Map([["left",Ap],["right",Cp],["center",'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm2.286 4c0 .414.336.75.75.75h9.928a.75.75 0 100-1.5H5.036a.75.75 0 00-.75.75zm0-8c0 .414.336.75.75.75h9.928a.75.75 0 100-1.5H5.036a.75.75 0 00-.75.75z"/></svg>'],["justify",'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0-8c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75z"/></svg>']]);class Pp extends ql{get localizedOptionTitles(){const t=this.editor.t;return{left:t("aa"),right:t("ab"),center:t("ac"),justify:t("ad")}}static get pluginName(){return"AlignmentUI"}init(){const t=this.editor,e=t.ui.componentFactory,i=t.t,n=t.config.get("alignment.options");n.filter(_p).forEach(t=>this._addButton(t)),e.add("alignment",t=>{const o=Dl(t),s=n.map(t=>e.create(`alignment:${t}`));zl(o,s),o.buttonView.set({label:i("ae"),tooltip:!0}),o.toolbarView.isVertical=!0,o.toolbarView.ariaLabel=i("af"),o.extendTemplate({attributes:{class:"ck-alignment-dropdown"}});const r="rtl"===t.contentLanguageDirection?Cp:Ap;return o.buttonView.bind("icon").toMany(s,"isOn",(...t)=>{const e=t.findIndex(t=>t);return e<0?r:s[e].icon}),o.bind("isEnabled").toMany(s,"isEnabled",(...t)=>t.some(t=>t)),o})}_addButton(t){const e=this.editor;e.ui.componentFactory.add(`alignment:${t}`,i=>{const n=e.commands.get("alignment"),o=new El(i);return o.set({label:this.localizedOptionTitles[t],icon:Tp.get(t),tooltip:!0,isToggleable:!0}),o.bind("isEnabled").to(n),o.bind("isOn").to(n,"value",e=>e===t),this.listenTo(o,"execute",()=>{e.execute("alignment",{value:t}),e.editing.view.focus()}),o})}}class Sp{constructor(t){this.set("activeHandlePosition",null),this.set("proposedWidthPercents",null),this.set("proposedWidth",null),this.set("proposedHeight",null),this.set("proposedHandleHostWidth",null),this.set("proposedHandleHostHeight",null),this._options=t,this._referenceCoordinates=null}begin(t,e,i){const n=new Xs(e);this.activeHandlePosition=function(t){const e=["top-left","top-right","bottom-right","bottom-left"];for(const i of e)if(t.classList.contains(`ck-widget__resizer__handle-${i}`))return i}(t),this._referenceCoordinates=function(t,e){const i=new Xs(t),n=e.split("-"),o={x:"right"==n[1]?i.right:i.left,y:"bottom"==n[0]?i.bottom:i.top};return o.x+=t.ownerDocument.defaultView.scrollX,o.y+=t.ownerDocument.defaultView.scrollY,o}(e,function(t){const e=t.split("-"),i={top:"bottom",bottom:"top",left:"right",right:"left"};return`${i[e[0]]}-${i[e[1]]}`}(this.activeHandlePosition)),this.originalWidth=n.width,this.originalHeight=n.height,this.aspectRatio=n.width/n.height;const o=i.style.width;o&&o.match(/^\d+\.?\d*%$/)?this.originalWidthPercents=parseFloat(o):this.originalWidthPercents=function(t,e){const i=t.parentElement,n=parseFloat(i.ownerDocument.defaultView.getComputedStyle(i).width);return e.width/n*100}(i,n)}update(t){this.proposedWidth=t.width,this.proposedHeight=t.height,this.proposedWidthPercents=t.widthPercents,this.proposedHandleHostWidth=t.handleHostWidth,this.proposedHandleHostHeight=t.handleHostHeight}}vi(Sp,Hn);class Ep{constructor(t){this._options=t,this._domResizerWrapper=null,this._viewResizerWrapper=null,this.set("isEnabled",!0),this.decorate("begin"),this.decorate("cancel"),this.decorate("commit"),this.decorate("updateSize"),this.on("commit",t=>{this.state.proposedWidth||(this._cleanup(),t.stop())},{priority:"high"})}attach(){const t=this,e=this._options.viewElement;this._options.editor.editing.view.change(i=>{const n=i.createUIElement("div",{class:"ck ck-reset_all ck-widget__resizer"},(function(e){const i=this.toDomElement(e);return t._appendHandles(i),t._appendSizeUI(i),t._domResizerWrapper=i,t.on("change:isEnabled",(t,e,n)=>{i.style.display=n?"":"none"}),i.style.display=t.isEnabled?"":"none",i}));i.insert(i.createPositionAt(e,"end"),n),i.addClass("ck-widget_with-resizer",e),this._viewResizerWrapper=n})}begin(t){this.state=new Sp(this._options),this._sizeUI.bindToState(this._options,this.state),this.state.begin(t,this._getHandleHost(),this._getResizeHost())}updateSize(t){const e=this._proposeNewSize(t);this._options.editor.editing.view.change(t=>{const i=this._options.unit,n=("%"===i?e.widthPercents:e.width)+i;t.setStyle("width",n,this._options.viewElement)});const i=this._getHandleHost(),n=new Xs(i);e.handleHostWidth=Math.round(n.width),e.handleHostHeight=Math.round(n.height);const o=new Xs(i);e.width=Math.round(o.width),e.height=Math.round(o.height),this.redraw(n),this.state.update(e)}commit(){const t=("%"===this._options.unit?this.state.proposedWidthPercents:this.state.proposedWidth)+this._options.unit;this._options.onCommit(t),this._cleanup()}cancel(){this._cleanup()}destroy(){this.cancel()}redraw(t){const e=this._domResizerWrapper;var i;(i=e)&&i.ownerDocument&&i.ownerDocument.contains(i)&&this._options.editor.editing.view.change(i=>{const n=e.parentElement,o=this._getHandleHost(),s=t||new Xs(o);i.setStyle("width",s.width+"px",this._viewResizerWrapper),i.setStyle("height",s.height+"px",this._viewResizerWrapper);const r=o.offsetLeft,a=o.offsetTop,c=o.offsetHeight,l=o.offsetWidth;n.isSameNode(o)||(i.setStyle("left",r+"px",this._viewResizerWrapper),i.setStyle("top",a+"px",this._viewResizerWrapper),i.setStyle("height",c+"px",this._viewResizerWrapper),i.setStyle("width",l+"px",this._viewResizerWrapper))})}containsHandle(t){return this._domResizerWrapper.contains(t)}static isResizeHandle(t){return t.classList.contains("ck-widget__resizer__handle")}_cleanup(){this._sizeUI.dismiss(),this._sizeUI.isVisible=!1}_proposeNewSize(t){const e=this.state,i={x:(n=t).pageX,y:n.pageY};var n;const o=!this._options.isCentered||this._options.isCentered(this),s={x:e._referenceCoordinates.x-(i.x+e.originalWidth),y:i.y-e.originalHeight-e._referenceCoordinates.y};o&&e.activeHandlePosition.endsWith("-right")&&(s.x=i.x-(e._referenceCoordinates.x+e.originalWidth)),o&&(s.x*=2);const r={width:Math.abs(e.originalWidth+s.x),height:Math.abs(e.originalHeight+s.y)};r.dominant=r.width/e.aspectRatio>r.height?"width":"height",r.max=r[r.dominant];const a={width:r.width,height:r.height};return"width"==r.dominant?a.height=a.width/e.aspectRatio:a.width=a.height*e.aspectRatio,{width:Math.round(a.width),height:Math.round(a.height),widthPercents:Math.min(Math.round(e.originalWidthPercents/e.originalWidth*a.width*100)/100,100)}}_getResizeHost(){const t=this._domResizerWrapper.parentElement;return this._options.getResizeHost(t)}_getHandleHost(){const t=this._domResizerWrapper.parentElement;return this._options.getHandleHost(t)}_appendHandles(t){const e=["top-left","top-right","bottom-right","bottom-left"];for(const i of e)t.appendChild(new Fc({tag:"div",attributes:{class:`ck-widget__resizer__handle ${Ip(i)}`}}).render())}_appendSizeUI(t){const e=new Mp;e.render(),this._sizeUI=e,t.appendChild(e.element)}_getHandlePosition(t){const e=["top-left","top-right","bottom-right","bottom-left"];for(const i of e)if(t.classList.contains(Ip(i)))return i}}vi(Ep,Hn);class Mp extends rl{constructor(){super();const t=this.bindTemplate;this.setTemplate({tag:"div",attributes:{class:["ck","ck-size-view",t.to("activeHandlePosition",t=>t?`ck-orientation-${t}`:"")],style:{display:t.if("isVisible","none",t=>!t)}},children:[{text:t.to("label")}]})}bindToState(t,e){this.bind("isVisible").to(e,"proposedWidth",e,"proposedHeight",(t,e)=>null!==t&&null!==e),this.bind("label").to(e,"proposedHandleHostWidth",e,"proposedHandleHostHeight",e,"proposedWidthPercents",(e,i,n)=>"px"===t.unit?`${e}×${i}`:`${n}%`),this.bind("activeHandlePosition").to(e)}dismiss(){this.unbind(),this.isVisible=!1}}function Ip(t){return`ck-widget__resizer__handle-${t}`}var Np=function(t,e,i){var n=!0,o=!0;if("function"!=typeof t)throw new TypeError("Expected a function");return z(i)&&(n="leading"in i?!!i.leading:n,o="trailing"in i?!!i.trailing:o),Ws(t,e,{leading:n,maxWait:e,trailing:o})};i(94);class Op extends ql{static get pluginName(){return"WidgetResize"}init(){this.set("_visibleResizer",null),this.set("_activeResizer",null),this._resizers=new Map;const t=ts.window.document;this.editor.model.schema.setAttributeProperties("width",{isFormatting:!0}),this._observer=Object.create(ls),this._observer.listenTo(t,"mousedown",(t,e)=>{if(!Ep.isResizeHandle(e.target))return;const i=e.target;this._activeResizer=this._getResizerByHandle(i),this._activeResizer&&this._activeResizer.begin(i)}),this._observer.listenTo(t,"mousemove",(t,e)=>{this._activeResizer&&this._activeResizer.updateSize(e)}),this._observer.listenTo(t,"mouseup",()=>{this._activeResizer&&(this._activeResizer.commit(),this._activeResizer=null)});const e=()=>{this._visibleResizer&&this._visibleResizer.redraw()},i=Np(e,200);this.on("change:_visibleResizer",e),this.editor.ui.on("update",i),this._observer.listenTo(ts.window,"resize",i);const n=this.editor.editing.view.document.selection;n.on("change",()=>{const t=n.getSelectedElement();this._visibleResizer=this._getResizerByViewElement(t)||null})}destroy(){this._observer.stopListening()}attachTo(t){const e=new Ep(t),i=this.editor.plugins;if(e.attach(),i.has("WidgetToolbarRepository")){const t=i.get("WidgetToolbarRepository");e.on("begin",()=>{t.forceDisabled("resize")},{priority:"lowest"}),e.on("cancel",()=>{t.clearForceDisabled("resize")},{priority:"highest"}),e.on("commit",()=>{t.clearForceDisabled("resize")},{priority:"highest"})}return this._resizers.set(t.viewElement,e),e}_getResizerByHandle(t){for(const e of this._resizers.values())if(e.containsHandle(t))return e}_getResizerByViewElement(t){return this._resizers.get(t)}}vi(Op,Hn);class Rp extends Jl{refresh(){const t=this.editor.model.document.selection.getSelectedElement();this.isEnabled=Th(t),t&&t.hasAttribute("width")?this.value={width:t.getAttribute("width"),height:null}:this.value=null}execute(t){const e=this.editor.model,i=e.document.selection.getSelectedElement();e.change(e=>{e.setAttribute("width",t.width,i)})}}i(96);class Lp extends Jl{constructor(t,e){super(t),this.attributeKey=e}refresh(){const t=this.editor.model,e=t.document;this.value=e.selection.getAttribute(this.attributeKey),this.isEnabled=t.schema.checkAttributeInSelection(e.selection,this.attributeKey)}execute(t={}){const e=this.editor.model,i=e.document.selection,n=t.value;e.change(t=>{if(i.isCollapsed)n?t.setSelectionAttribute(this.attributeKey,n):t.removeSelectionAttribute(this.attributeKey);else{const o=e.schema.getValidRanges(i.getRanges(),this.attributeKey);for(const e of o)n?t.setAttribute(this.attributeKey,n,e):t.removeAttribute(this.attributeKey,e)}})}}class Dp extends El{constructor(t){super(t);const e=this.bindTemplate;this.set("color"),this.set("hasBorder"),this.icon='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path class="ck-icon__fill" d="M16.935 5.328a2 2 0 010 2.829l-7.778 7.778a2 2 0 01-2.829 0L3.5 13.107a1.999 1.999 0 112.828-2.829l.707.707a1 1 0 001.414 0l5.658-5.657a2 2 0 012.828 0z"/><path d="M14.814 6.035L8.448 12.4a1 1 0 01-1.414 0l-1.413-1.415A1 1 0 104.207 12.4l2.829 2.829a1 1 0 001.414 0l7.778-7.778a1 1 0 10-1.414-1.415z"/></svg>',this.extendTemplate({attributes:{style:{backgroundColor:e.to("color")},class:["ck","ck-color-grid__tile",e.if("hasBorder","ck-color-table__color-tile_bordered")]}})}render(){super.render(),this.iconView.fillColor="hsl(0, 0%, 100%)"}}i(98);class zp extends rl{constructor(t,e){super(t);const i=e&&e.colorDefinitions||[],n={};e&&e.columns&&(n.gridTemplateColumns=`repeat( ${e.columns}, 1fr)`),this.set("selectedColor"),this.items=this.createCollection(),this.focusTracker=new Ic,this.keystrokes=new yc,this._focusCycler=new bl({focusables:this.items,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"arrowleft",focusNext:"arrowright"}}),this.items.on("add",(t,e)=>{e.isOn=e.color===this.selectedColor}),i.forEach(t=>{const e=new Dp;e.set({color:t.color,label:t.label,tooltip:!0,hasBorder:t.options.hasBorder}),e.on("execute",()=>{this.fire("execute",{value:t.color,hasBorder:t.options.hasBorder,label:t.label})}),this.items.add(e)}),this.setTemplate({tag:"div",children:this.items,attributes:{class:["ck","ck-color-grid"],style:n}}),this.on("change:selectedColor",(t,e,i)=>{for(const t of this.items)t.isOn=t.color===i})}focus(){this.items.length&&this.items.first.focus()}focusLast(){this.items.length&&this.items.last.focus()}render(){super.render();for(const t of this.items)this.focusTracker.add(t.element);this.items.on("add",(t,e)=>{this.focusTracker.add(e.element)}),this.items.on("remove",(t,e)=>{this.focusTracker.remove(e.element)}),this.keystrokes.listenTo(this.element)}}class jp extends yi{constructor(t){super(t),this.set("isEmpty",!0)}add(t,e){this.find(e=>e.color===t.color)||(super.add(t,e),this.set("isEmpty",!1))}remove(t){const e=super.remove(t);return 0===this.length&&this.set("isEmpty",!0),e}hasColor(t){return!!this.find(e=>e.color===t)}}vi(jp,Hn);i(100);class Vp extends rl{constructor(t,{colors:e,columns:i,removeButtonLabel:n,documentColorsLabel:o,documentColorsCount:s}){super(t),this.items=this.createCollection(),this.colorDefinitions=e,this.focusTracker=new Ic,this.keystrokes=new yc,this.set("selectedColor"),this.removeButtonLabel=n,this.columns=i,this.documentColors=new jp,this.documentColorsCount=s,this._focusCycler=new bl({focusables:this.items,focusTracker:this.focusTracker,keystrokeHandler:this.keystrokes,actions:{focusPrevious:"arrowup",focusNext:"arrowdown"}}),this._documentColorsLabel=o,this.setTemplate({tag:"div",attributes:{class:["ck","ck-color-table"]},children:this.items}),this.items.add(this._removeColorButton())}updateDocumentColors(t,e){const i=t.document,n=this.documentColorsCount;this.documentColors.clear();for(const o of i.getRootNames()){const s=i.getRoot(o),r=t.createRangeIn(s);for(const t of r.getItems())if(t.is("textProxy")&&t.hasAttribute(e)&&(this._addColorToDocumentColors(t.getAttribute(e)),this.documentColors.length>=n))return}}updateSelectedColors(){const t=this.documentColorsGrid,e=this.staticColorsGrid,i=this.selectedColor;e.selectedColor=i,t&&(t.selectedColor=i)}render(){super.render();for(const t of this.items)this.focusTracker.add(t.element);this.keystrokes.listenTo(this.element)}appendGrids(){if(!this.staticColorsGrid&&(this.staticColorsGrid=this._createStaticColorsGrid(),this.items.add(this.staticColorsGrid),this.documentColorsCount)){const t=Fc.bind(this.documentColors,this.documentColors),e=new dl(this.locale);e.text=this._documentColorsLabel,e.extendTemplate({attributes:{class:["ck","ck-color-grid__label",t.if("isEmpty","ck-hidden")]}}),this.items.add(e),this.documentColorsGrid=this._createDocumentColorsGrid(),this.items.add(this.documentColorsGrid)}}focus(){this._focusCycler.focusFirst()}focusLast(){this._focusCycler.focusLast()}_removeColorButton(){const t=new El;return t.set({withText:!0,icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M8.636 9.531l-2.758 3.94a.5.5 0 00.122.696l3.224 2.284h1.314l2.636-3.736L8.636 9.53zm.288 8.451L5.14 15.396a2 2 0 01-.491-2.786l6.673-9.53a2 2 0 012.785-.49l3.742 2.62a2 2 0 01.491 2.785l-7.269 10.053-2.147-.066z"/><path d="M4 18h5.523v-1H4zm-2 0h1v-1H2z"/></svg>',tooltip:!0,label:this.removeButtonLabel}),t.class="ck-color-table__remove-color",t.on("execute",()=>{this.fire("execute",{value:null})}),t}_createStaticColorsGrid(){const t=new zp(this.locale,{colorDefinitions:this.colorDefinitions,columns:this.columns});return t.delegate("execute").to(this),t}_createDocumentColorsGrid(){const t=Fc.bind(this.documentColors,this.documentColors),e=new zp(this.locale,{columns:this.columns});return e.delegate("execute").to(this),e.extendTemplate({attributes:{class:t.if("isEmpty","ck-hidden")}}),e.items.bindTo(this.documentColors).using(t=>{const e=new Dp;return e.set({color:t.color,hasBorder:t.options&&t.options.hasBorder}),t.label&&e.set({label:t.label,tooltip:!0}),e.on("execute",()=>{this.fire("execute",{value:t.color})}),e}),this.documentColors.on("change:isEmpty",(t,i,n)=>{n&&(e.selectedColor=null)}),e}_addColorToDocumentColors(t){const e=this.colorDefinitions.find(e=>e.color===t);e?this.documentColors.add(Object.assign({},e)):this.documentColors.add({color:t,label:t,options:{hasBorder:!1}})}}function Bp(t,e){const i={model:{key:t,values:[]},view:{},upcastAlso:{}};for(const t of e)i.model.values.push(t.model),i.view[t.model]=t.view,t.upcastAlso&&(i.upcastAlso[t.model]=t.upcastAlso);return i}function Fp(t){return e=>e.getStyle(t).replace(/\s/g,"")}function Hp(t){return(e,i)=>i.createAttributeElement("span",{style:`${t}:${e}`},{priority:7})}class Up extends Lp{constructor(t){super(t,"fontFamily")}}function Wp(t){return t.map(qp).filter(t=>!!t)}function qp(t){return"object"==typeof t?t:"default"===t?{title:"Default",model:void 0}:"string"==typeof t?function(t){const e=t.replace(/"|'/g,"").split(","),i=e[0],n=e.map($p).join(", ");return{title:i,model:i,view:{name:"span",styles:{"font-family":n},priority:7}}}(t):void 0}function $p(t){return(t=t.trim()).indexOf(" ")>0&&(t=`'${t}'`),t}class Yp extends ql{static get pluginName(){return"FontFamilyEditing"}constructor(t){super(t),t.config.define("fontFamily",{options:["default","Arial, Helvetica, sans-serif","Courier New, Courier, monospace","Georgia, serif","Lucida Sans Unicode, Lucida Grande, sans-serif","Tahoma, Geneva, sans-serif","Times New Roman, Times, serif","Trebuchet MS, Helvetica, sans-serif","Verdana, Geneva, sans-serif"]})}init(){const t=this.editor;t.model.schema.extend("$text",{allowAttributes:"fontFamily"}),t.model.schema.setAttributeProperties("fontFamily",{isFormatting:!0,copyOnEnter:!0});const e=Bp("fontFamily",Wp(t.config.get("fontFamily.options")).filter(t=>t.model));t.conversion.attributeToElement(e),t.commands.add("fontFamily",new Up(t))}}class Gp extends ql{init(){const t=this.editor,e=t.t,i=this._getLocalizedOptions(),n=t.commands.get("fontFamily");t.ui.componentFactory.add("fontFamily",o=>{const s=Dl(o);return jl(s,function(t,e){const i=new yi;for(const n of t){const t={type:"button",model:new xf({commandName:"fontFamily",commandParam:n.model,label:n.title,withText:!0})};t.model.bind("isOn").to(e,"value",t=>t===n.model),n.view&&n.view.styles&&t.model.set("labelStyle",`font-family: ${n.view.styles["font-family"]}`),i.add(t)}return i}(i,n)),s.buttonView.set({label:e("br"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.03 3h6.149a.75.75 0 110 1.5h-5.514L11.03 3zm1.27 3h4.879a.75.75 0 110 1.5h-4.244L12.3 6zm1.27 3h3.609a.75.75 0 110 1.5h-2.973L13.57 9zm-2.754 2.5L8.038 4.785 5.261 11.5h5.555zm.62 1.5H4.641l-1.666 4.028H1.312l5.789-14h1.875l5.789 14h-1.663L11.436 13z"/></svg>',tooltip:!0}),s.extendTemplate({attributes:{class:"ck-font-family-dropdown"}}),s.bind("isEnabled").to(n),this.listenTo(s,"execute",e=>{t.execute(e.source.commandName,{value:e.source.commandParam}),t.editing.view.focus()}),s})}_getLocalizedOptions(){const t=this.editor,e=t.t;return Wp(t.config.get("fontFamily").options).map(t=>("Default"===t.title&&(t.title=e("bs")),t))}}class Qp extends ql{static get requires(){return[Yp,Gp]}static get pluginName(){return"FontFamily"}}class Kp extends Lp{constructor(t){super(t,"fontSize")}}function Jp(t){return t.map(Xp).filter(t=>!!t)}const Zp={tiny:{title:"Tiny",model:"tiny",view:{name:"span",classes:"text-tiny",priority:7}},small:{title:"Small",model:"small",view:{name:"span",classes:"text-small",priority:7}},big:{title:"Big",model:"big",view:{name:"span",classes:"text-big",priority:7}},huge:{title:"Huge",model:"huge",view:{name:"span",classes:"text-huge",priority:7}}};function Xp(t){if("object"==typeof t)return t;if(Zp[t])return Zp[t];if("default"===t)return{model:void 0,title:"Default"};const e=parseFloat(t);var i;return isNaN(e)?void 0:(i=e,{title:String(i),model:i,view:{name:"span",styles:{"font-size":`${i}px`},priority:7}})}class tb extends ql{static get pluginName(){return"FontSizeEditing"}constructor(t){super(t),t.config.define("fontSize",{options:["tiny","small","default","big","huge"]});const e=Bp("fontSize",Jp(this.editor.config.get("fontSize.options")).filter(t=>t.model));t.conversion.attributeToElement(e),t.commands.add("fontSize",new Kp(t))}init(){const t=this.editor;t.model.schema.extend("$text",{allowAttributes:"fontSize"}),t.model.schema.setAttributeProperties("fontSize",{isFormatting:!0,copyOnEnter:!0})}}i(102);class eb extends ql{init(){const t=this.editor,e=t.t,i=this._getLocalizedOptions(),n=t.commands.get("fontSize");t.ui.componentFactory.add("fontSize",o=>{const s=Dl(o);return jl(s,function(t,e){const i=new yi;for(const n of t){const t={type:"button",model:new xf({commandName:"fontSize",commandParam:n.model,label:n.title,class:"ck-fontsize-option",withText:!0})};n.view&&n.view.styles&&t.model.set("labelStyle",`font-size:${n.view.styles["font-size"]}`),n.view&&n.view.classes&&t.model.set("class",`${t.model.class} ${n.view.classes}`),t.model.bind("isOn").to(e,"value",t=>t===n.model),i.add(t)}return i}(i,n)),s.buttonView.set({label:e("bt"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.816 11.5L7.038 4.785 4.261 11.5h5.555zm.62 1.5H3.641l-1.666 4.028H.312l5.789-14h1.875l5.789 14h-1.663L10.436 13zm7.55 2.279l.779-.779.707.707-2.265 2.265-2.193-2.265.707-.707.765.765V4.825c0-.042 0-.083.002-.123l-.77.77-.707-.707L17.207 2.5l2.265 2.265-.707.707-.782-.782c.002.043.003.089.003.135v10.454z"/></svg>',tooltip:!0}),s.extendTemplate({attributes:{class:["ck-font-size-dropdown"]}}),s.bind("isEnabled").to(n),this.listenTo(s,"execute",e=>{t.execute(e.source.commandName,{value:e.source.commandParam}),t.editing.view.focus()}),s})}_getLocalizedOptions(){const t=this.editor,e=t.t,i={Default:e("bs"),Tiny:e("bu"),Small:e("bv"),Big:e("bw"),Huge:e("bx")};return Jp(t.config.get("fontSize").options).map(t=>{const e=i[t.title];return e&&e!=t.title&&(t=Object.assign({},t,{title:e})),t})}}class ib extends ql{static get requires(){return[tb,eb]}static get pluginName(){return"FontSize"}}class nb extends Lp{constructor(t){super(t,"fontColor")}}class ob extends ql{static get pluginName(){return"FontColorEditing"}constructor(t){super(t),t.config.define("fontColor",{colors:[{color:"hsl(0, 0%, 0%)",label:"Black"},{color:"hsl(0, 0%, 30%)",label:"Dim grey"},{color:"hsl(0, 0%, 60%)",label:"Grey"},{color:"hsl(0, 0%, 90%)",label:"Light grey"},{color:"hsl(0, 0%, 100%)",label:"White",hasBorder:!0},{color:"hsl(0, 75%, 60%)",label:"Red"},{color:"hsl(30, 75%, 60%)",label:"Orange"},{color:"hsl(60, 75%, 60%)",label:"Yellow"},{color:"hsl(90, 75%, 60%)",label:"Light green"},{color:"hsl(120, 75%, 60%)",label:"Green"},{color:"hsl(150, 75%, 60%)",label:"Aquamarine"},{color:"hsl(180, 75%, 60%)",label:"Turquoise"},{color:"hsl(210, 75%, 60%)",label:"Light blue"},{color:"hsl(240, 75%, 60%)",label:"Blue"},{color:"hsl(270, 75%, 60%)",label:"Purple"}],columns:5}),t.conversion.for("upcast").elementToAttribute({view:{name:"span",styles:{color:/[\s\S]+/}},model:{key:"fontColor",value:Fp("color")}}),t.conversion.for("downcast").attributeToElement({model:"fontColor",view:Hp("color")}),t.commands.add("fontColor",new nb(t)),t.model.schema.extend("$text",{allowAttributes:"fontColor"}),t.model.schema.setAttributeProperties("fontColor",{isFormatting:!0,copyOnEnter:!0})}}function sb(t){return"string"==typeof t?{model:t.replace(/ /g,""),label:t,hasBorder:!1,view:{name:"span",styles:{color:t}}}:{model:t.color.replace(/ /g,""),label:t.label||t.color,hasBorder:void 0!==t.hasBorder&&t.hasBorder,view:{name:"span",styles:{color:`${t.color}`}}}}class rb extends ql{constructor(t,{commandName:e,icon:i,componentName:n,dropdownLabel:o}){super(t),this.commandName=e,this.componentName=n,this.icon=i,this.dropdownLabel=o,this.columns=t.config.get(`${this.componentName}.columns`),this.colorTableView}init(){const t=this.editor,e=t.locale,i=e.t,n=t.commands.get(this.commandName);const o=function(t,e){const i=t.t,n={Black:i("cr"),"Dim grey":i("cs"),Grey:i("ct"),"Light grey":i("cu"),White:i("cv"),Red:i("cw"),Orange:i("cx"),Yellow:i("cy"),"Light green":i("cz"),Green:i("da"),Aquamarine:i("db"),Turquoise:i("dc"),"Light blue":i("dd"),Blue:i("de"),Purple:i("df")};return e.map(t=>{const e=n[t.label];return e&&e!=t.label&&(t.label=e),t})}(e,t.config.get(this.componentName).colors.map(sb).filter(t=>!!t)),s=t.config.get(`${this.componentName}.documentColors`);t.ui.componentFactory.add(this.componentName,e=>{const r=Dl(e);return this.colorTableView=function({dropdownView:t,colors:e,columns:i,removeButtonLabel:n,documentColorsLabel:o,documentColorsCount:s}){const r=t.locale,a=new Vp(r,{colors:e,columns:i,removeButtonLabel:n,documentColorsLabel:o,documentColorsCount:s});return t.colorTableView=a,t.panelView.children.add(a),a.delegate("execute").to(t,"execute"),a}({dropdownView:r,colors:o.map(t=>({label:t.label,color:t.model,options:{hasBorder:t.hasBorder}})),columns:this.columns,removeButtonLabel:i("cp"),documentColorsLabel:0!==s?i("cq"):void 0,documentColorsCount:void 0===s?this.columns:s}),this.colorTableView.bind("selectedColor").to(n,"value"),r.buttonView.set({label:this.dropdownLabel,icon:this.icon,tooltip:!0}),r.extendTemplate({attributes:{class:"ck-color-ui-dropdown"}}),r.bind("isEnabled").to(n),r.on("execute",(e,i)=>{t.execute(this.commandName,i),t.editing.view.focus()}),r.on("change:isOpen",(e,i,n)=>{r.colorTableView.appendGrids(),n&&(0!==s&&this.colorTableView.updateDocumentColors(t.model,this.componentName),this.colorTableView.updateSelectedColors())}),r})}}class ab extends rb{constructor(t){super(t,{commandName:"fontColor",componentName:"fontColor",icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M12.4 10.3L10 4.5l-2.4 5.8h4.8zm.5 1.2H7.1L5.7 15H4.2l5-12h1.6l5 12h-1.5L13 11.5zm3.1 7H4a1 1 0 010-2h12a1 1 0 010 2z"/></svg>',dropdownLabel:(0,t.locale.t)("bq")})}static get pluginName(){return"FontColorUI"}}class cb extends ql{static get requires(){return[ob,ab]}static get pluginName(){return"FontColor"}}class lb extends Lp{constructor(t){super(t,"fontBackgroundColor")}}class db extends ql{static get pluginName(){return"FontBackgroundColorEditing"}constructor(t){super(t),t.config.define("fontBackgroundColor",{colors:[{color:"hsl(0, 0%, 0%)",label:"Black"},{color:"hsl(0, 0%, 30%)",label:"Dim grey"},{color:"hsl(0, 0%, 60%)",label:"Grey"},{color:"hsl(0, 0%, 90%)",label:"Light grey"},{color:"hsl(0, 0%, 100%)",label:"White",hasBorder:!0},{color:"hsl(0, 75%, 60%)",label:"Red"},{color:"hsl(30, 75%, 60%)",label:"Orange"},{color:"hsl(60, 75%, 60%)",label:"Yellow"},{color:"hsl(90, 75%, 60%)",label:"Light green"},{color:"hsl(120, 75%, 60%)",label:"Green"},{color:"hsl(150, 75%, 60%)",label:"Aquamarine"},{color:"hsl(180, 75%, 60%)",label:"Turquoise"},{color:"hsl(210, 75%, 60%)",label:"Light blue"},{color:"hsl(240, 75%, 60%)",label:"Blue"},{color:"hsl(270, 75%, 60%)",label:"Purple"}],columns:5}),t.conversion.for("upcast").elementToAttribute({view:{name:"span",styles:{"background-color":/[\s\S]+/}},model:{key:"fontBackgroundColor",value:Fp("background-color")}}),t.conversion.for("downcast").attributeToElement({model:"fontBackgroundColor",view:Hp("background-color")}),t.commands.add("fontBackgroundColor",new lb(t)),t.model.schema.extend("$text",{allowAttributes:"fontBackgroundColor"}),t.model.schema.setAttributeProperties("fontBackgroundColor",{isFormatting:!0,copyOnEnter:!0})}}class hb extends rb{constructor(t){super(t,{commandName:"fontBackgroundColor",componentName:"fontBackgroundColor",icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M4 2h12a2 2 0 012 2v12a2 2 0 01-2 2H4a2 2 0 01-2-2V4a2 2 0 012-2zm8.38 9.262H7.62L10 5.506l2.38 5.756zm.532 1.285L14.34 16h1.426L10.804 4H9.196L4.234 16H5.66l1.428-3.453h5.824z"/></svg>',dropdownLabel:(0,t.locale.t)("bp")})}static get pluginName(){return"FontBackgroundColorUI"}}class ub extends ql{static get requires(){return[db,hb]}static get pluginName(){return"FontBackgroundColor"}}i.d(e,"default",(function(){return fb}));class fb extends Wl{}fb.builtinPlugins=[class extends ql{static get requires(){return[Kl,nd,ad,vd,Fd]}static get pluginName(){return"Essentials"}},Gd,class extends ql{static get pluginName(){return"Autoformat"}afterInit(){this._addListAutoformats(),this._addBasicStylesAutoformats(),this._addHeadingAutoformats(),this._addBlockQuoteAutoformats(),this._addCodeBlockAutoformats()}_addListAutoformats(){const t=this.editor.commands;t.get("bulletedList")&&new Kd(this.editor,/^[*-]\s$/,"bulletedList"),t.get("numberedList")&&new Kd(this.editor,/^1[.|)]\s$/,"numberedList")}_addBasicStylesAutoformats(){const t=this.editor.commands;if(t.get("bold")){const t=Xd(this.editor,"bold");new Jd(this.editor,/(\*\*)([^*]+)(\*\*)$/g,t),new Jd(this.editor,/(__)([^_]+)(__)$/g,t)}if(t.get("italic")){const t=Xd(this.editor,"italic");new Jd(this.editor,/(?:^|[^*])(\*)([^*_]+)(\*)$/g,t),new Jd(this.editor,/(?:^|[^_])(_)([^_]+)(_)$/g,t)}if(t.get("code")){const t=Xd(this.editor,"code");new Jd(this.editor,/(`)([^`]+)(`)$/g,t)}}_addHeadingAutoformats(){const t=this.editor.commands.get("heading");t&&t.modelElements.filter(t=>t.match(/^heading[1-6]$/)).forEach(e=>{const i=e[7],n=new RegExp(`^(#{${i}})\\s$`);new Kd(this.editor,n,()=>{if(!t.isEnabled)return!1;this.editor.execute("heading",{value:e})})})}_addBlockQuoteAutoformats(){this.editor.commands.get("blockQuote")&&new Kd(this.editor,/^>\s$/,"blockQuote")}_addCodeBlockAutoformats(){this.editor.commands.get("codeBlock")&&new Kd(this.editor,/^```$/,"codeBlock")}},class extends ql{static get requires(){return[eh,ih]}static get pluginName(){return"Bold"}},class extends ql{static get requires(){return[nh,oh]}static get pluginName(){return"Italic"}},class extends ql{static get requires(){return[dh,hh]}static get pluginName(){return"BlockQuote"}},class extends ql{static get pluginName(){return"CKFinder"}static get requires(){return[pu,uh,Gd]}},class extends ql{static get requires(){return[xu,Ku,mf]}static get pluginName(){return"EasyImage"}},class extends ql{static get requires(){return[yf,Af]}static get pluginName(){return"Heading"}},Ku,class extends ql{static get requires(){return[Pf]}static get pluginName(){return"ImageCaption"}},class extends ql{static get requires(){return[Hf,Uf]}static get pluginName(){return"ImageStyle"}},class extends ql{static get requires(){return[Wf]}static get pluginName(){return"ImageToolbar"}afterInit(){const t=this.editor,e=t.t;t.plugins.get(Wf).register("image",{ariaLabel:e("b"),items:t.config.get("image.toolbar")||[],getRelatedElement:Ch})}},mf,class extends ql{static get pluginName(){return"Indent"}static get requires(){return[Gf,Jf]}},class extends ql{static get requires(){return[uu,em]}static get pluginName(){return"Link"}},class extends ql{static get requires(){return[Pm,Em]}static get pluginName(){return"List"}},class extends ql{static get requires(){return[jm,Hm,Bm,Pu]}static get pluginName(){return"MediaEmbed"}},bf,class extends ql{static get pluginName(){return"PasteFromOffice"}static get requires(){return[Kl]}init(){const t=this.editor,e=[];e.push(new Zm),e.push(new $m),t.plugins.get("Clipboard").on("inputTransformation",(t,i)=>{if(i.isTransformedWithPasteFromOffice)return;const n=i.dataTransfer.getData("text/html"),o=e.find(t=>t.isActive(n));o&&(o.execute(i),i.isTransformedWithPasteFromOffice=!0)},{priority:"high"})}},class extends ql{static get requires(){return[Jg,tp,Pu]}static get pluginName(){return"Table"}},class extends ql{static get requires(){return[Wf]}static get pluginName(){return"TableToolbar"}afterInit(){const t=this.editor,e=t.t,i=t.plugins.get(Wf),n=t.config.get("table.contentToolbar"),o=t.config.get("table.tableToolbar");n&&i.register("tableContent",{ariaLabel:e("c"),items:n,getRelatedElement:cg}),o&&i.register("table",{ariaLabel:e("c"),items:o,getRelatedElement:ag})}},class extends ql{static get requires(){return[ip,np]}static get pluginName(){return"Underline"}},class extends ql{static get requires(){return[op,sp]}static get pluginName(){return"Strikethrough"}},class extends ql{static get requires(){return[rp,ap]}static get pluginName(){return"Code"}},class extends ql{static get requires(){return[cp,lp]}static get pluginName(){return"Subscript"}},class extends ql{static get requires(){return[dp,hp]}static get pluginName(){return"Superscript"}},class extends ql{static get requires(){return[mp,up]}static get pluginName(){return"RemoveFormat"}},class extends ql{static get requires(){return[pp,bp]}static get pluginName(){return"HorizontalLine"}},class extends ql{static get requires(){return[qd]}static get pluginName(){return"Base64UploadAdapter"}init(){this.editor.plugins.get(qd).createUploadAdapter=t=>new wp(t)}},class extends ql{static get requires(){return[xp,Pp]}static get pluginName(){return"Alignment"}},class extends ql{static get requires(){return[Op]}static get pluginName(){return"ImageResize"}init(){const t=this.editor,e=new Rp(t);this._registerSchema(),this._registerConverters(),t.commands.add("imageResize",e),t.editing.downcastDispatcher.on("insert:image",(i,n,o)=>{const s=o.mapper.toViewElement(n.item),r=t.plugins.get(Op).attachTo({unit:t.config.get("image.resizeUnit")||"%",modelElement:n.item,viewElement:s,editor:t,getHandleHost:t=>t.querySelector("img"),getResizeHost:t=>t,isCentered(){const t=n.item.getAttribute("imageStyle");return!t||"full"==t||"alignCenter"==t},onCommit(e){t.execute("imageResize",{width:e})}});r.on("updateSize",()=>{s.hasClass("image_resized")||t.editing.view.change(t=>{t.addClass("image_resized",s)})}),r.bind("isEnabled").to(e)},{priority:"low"})}_registerSchema(){this.editor.model.schema.extend("image",{allowAttributes:"width"})}_registerConverters(){const t=this.editor;t.conversion.for("downcast").add(t=>t.on("attribute:width:image",(t,e,i)=>{if(!i.consumable.consume(e.item,t.name))return;const n=i.writer,o=i.mapper.toViewElement(e.item);null!==e.attributeNewValue?(n.setStyle("width",e.attributeNewValue,o),n.addClass("image_resized",o)):(n.removeStyle("width",o),n.removeClass("image_resized",o))})),t.conversion.for("upcast").attributeToAttribute({view:{name:"figure",styles:{width:/.+/}},model:{key:"width",value:t=>t.getStyle("width")}})}},class extends ql{static get requires(){return[Qp,ib,cb,ub]}static get pluginName(){return"Font"}}],fb.defaultConfig={toolbar:{items:["heading","|","bold","italic","link","bulletedList","numberedList","|","indent","outdent","|","imageUpload","blockQuote","insertTable","mediaEmbed","undo","redo"]},image:{toolbar:["imageStyle:full","imageStyle:side","|","imageTextAlternative"]},table:{contentToolbar:["tableColumn","tableRow","mergeTableCells"]},language:"en"}}]).default})); +//# sourceMappingURL=editor.js.map
\ No newline at end of file diff --git a/assets/editor/editor.js.map b/assets/editor/editor.js.map new file mode 100644 index 0000000..5307487 --- /dev/null +++ b/assets/editor/editor.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack://ClassicEditor/webpack/universalModuleDefinition","webpack://ClassicEditor/webpack/bootstrap","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/ckeditorerror.js","webpack://ClassicEditor/./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js","webpack://ClassicEditor/./node_modules/lodash-es/_root.js","webpack://ClassicEditor/./node_modules/lodash-es/isBuffer.js","webpack://ClassicEditor/./node_modules/lodash-es/_nodeUtil.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/version.js","webpack://ClassicEditor/./node_modules/lodash-es/_freeGlobal.js","webpack://ClassicEditor/./node_modules/lodash-es/_cloneBuffer.js","webpack://ClassicEditor/(webpack)/buildin/harmony-module.js","webpack://ClassicEditor/(webpack)/buildin/global.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-heading/theme/heading.css?e8ec","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/theme/code.css?2e73","webpack://ClassicEditor/./node_modules/lodash-es/stubFalse.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/theme/placeholder.css?ed1e","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/theme/placeholder.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/globals/globals.css?f805","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/globals/globals.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/editorui/editorui.css?827c","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/editorui/editorui.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/label/label.css?cb8d","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/label/label.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/panel/stickypanel.css?9589","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/panel/stickypanel.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/dropdown/dropdown.css?76f2","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/dropdown/dropdown.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/icon/icon.css?8738","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/icon/icon.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/tooltip/tooltip.css?fee2","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/tooltip/tooltip.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/button/button.css?375d","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/button/button.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/list/list.css?5e57","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/list/list.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/button/switchbutton.css?2d12","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/button/switchbutton.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/dropdown/toolbardropdown.css?4f42","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/dropdown/toolbardropdown.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/dropdown/listdropdown.css?b0a0","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/dropdown/listdropdown.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/toolbar/toolbar.css?174a","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/toolbar/toolbar.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-editor-classic/theme/classiceditor.css?f024","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-editor-classic/theme/classiceditor.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-block-quote/theme/blockquote.css?a3d1","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-block-quote/theme/blockquote.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/theme/link.css?1514","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/theme/link.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-widget/theme/widget.css?5f00","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-widget/theme/widget.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/labeledinput/labeledinput.css?3b7d","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/labeledinput/labeledinput.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/inputtext/inputtext.css?c337","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/inputtext/inputtext.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/textalternativeform.css?78ca","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/textalternativeform.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/panel/balloonpanel.css?7c60","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/panel/balloonpanel.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/panel/balloonrotator.css?6f91","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/panel/balloonrotator.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/panel/fakepanel.css?2560","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/panel/fakepanel.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/image.css?0d33","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/image.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/imageuploadprogress.css?e2d1","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/imageuploadprogress.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/imageuploadicon.css?34f9","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/imageuploadicon.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/imageuploadloader.css?3fc7","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/imageuploadloader.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-heading/theme/heading.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/imagecaption.css?e945","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/imagecaption.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/imagestyle.css?394b","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/imagestyle.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/theme/linkform.css?5619","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/theme/linkform.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/theme/linkactions.css?d014","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/theme/linkactions.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/theme/mediaembedediting.css?db1f","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/theme/mediaembedediting.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/theme/mediaform.css?cdd5","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/theme/mediaform.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/theme/mediaembed.css?587d","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/theme/mediaembed.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/theme/tableediting.css?c1e2","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/theme/tableediting.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/theme/inserttable.css?5a30","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/theme/inserttable.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/theme/table.css?f6ef","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/theme/table.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/theme/code.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-horizontal-line/theme/horizontalline.css?b116","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-horizontal-line/theme/horizontalline.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-widget/theme/widgetresize.css?f9eb","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-widget/theme/widgetresize.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/imageresize.css?877c","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/imageresize.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/colorgrid/colorgrid.css?ae8b","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/components/colorgrid/colorgrid.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/theme/fontcolor.css?8bb2","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/theme/fontcolor.css","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/theme/fontsize.css?5e8a","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/theme/fontsize.css","webpack://ClassicEditor/./node_modules/lodash-es/_Symbol.js","webpack://ClassicEditor/./node_modules/lodash-es/_getRawTag.js","webpack://ClassicEditor/./node_modules/lodash-es/_objectToString.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseGetTag.js","webpack://ClassicEditor/./node_modules/lodash-es/_overArg.js","webpack://ClassicEditor/./node_modules/lodash-es/_getPrototype.js","webpack://ClassicEditor/./node_modules/lodash-es/isObjectLike.js","webpack://ClassicEditor/./node_modules/lodash-es/isPlainObject.js","webpack://ClassicEditor/./node_modules/lodash-es/_listCacheClear.js","webpack://ClassicEditor/./node_modules/lodash-es/eq.js","webpack://ClassicEditor/./node_modules/lodash-es/_assocIndexOf.js","webpack://ClassicEditor/./node_modules/lodash-es/_listCacheDelete.js","webpack://ClassicEditor/./node_modules/lodash-es/_listCacheGet.js","webpack://ClassicEditor/./node_modules/lodash-es/_listCacheHas.js","webpack://ClassicEditor/./node_modules/lodash-es/_listCacheSet.js","webpack://ClassicEditor/./node_modules/lodash-es/_ListCache.js","webpack://ClassicEditor/./node_modules/lodash-es/_stackClear.js","webpack://ClassicEditor/./node_modules/lodash-es/_stackDelete.js","webpack://ClassicEditor/./node_modules/lodash-es/_stackGet.js","webpack://ClassicEditor/./node_modules/lodash-es/_stackHas.js","webpack://ClassicEditor/./node_modules/lodash-es/isObject.js","webpack://ClassicEditor/./node_modules/lodash-es/isFunction.js","webpack://ClassicEditor/./node_modules/lodash-es/_isMasked.js","webpack://ClassicEditor/./node_modules/lodash-es/_coreJsData.js","webpack://ClassicEditor/./node_modules/lodash-es/_toSource.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseIsNative.js","webpack://ClassicEditor/./node_modules/lodash-es/_getValue.js","webpack://ClassicEditor/./node_modules/lodash-es/_getNative.js","webpack://ClassicEditor/./node_modules/lodash-es/_Map.js","webpack://ClassicEditor/./node_modules/lodash-es/_nativeCreate.js","webpack://ClassicEditor/./node_modules/lodash-es/_hashClear.js","webpack://ClassicEditor/./node_modules/lodash-es/_hashDelete.js","webpack://ClassicEditor/./node_modules/lodash-es/_hashGet.js","webpack://ClassicEditor/./node_modules/lodash-es/_hashHas.js","webpack://ClassicEditor/./node_modules/lodash-es/_hashSet.js","webpack://ClassicEditor/./node_modules/lodash-es/_Hash.js","webpack://ClassicEditor/./node_modules/lodash-es/_mapCacheClear.js","webpack://ClassicEditor/./node_modules/lodash-es/_isKeyable.js","webpack://ClassicEditor/./node_modules/lodash-es/_getMapData.js","webpack://ClassicEditor/./node_modules/lodash-es/_mapCacheDelete.js","webpack://ClassicEditor/./node_modules/lodash-es/_mapCacheGet.js","webpack://ClassicEditor/./node_modules/lodash-es/_mapCacheHas.js","webpack://ClassicEditor/./node_modules/lodash-es/_mapCacheSet.js","webpack://ClassicEditor/./node_modules/lodash-es/_MapCache.js","webpack://ClassicEditor/./node_modules/lodash-es/_stackSet.js","webpack://ClassicEditor/./node_modules/lodash-es/_Stack.js","webpack://ClassicEditor/./node_modules/lodash-es/_arrayEach.js","webpack://ClassicEditor/./node_modules/lodash-es/_defineProperty.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseAssignValue.js","webpack://ClassicEditor/./node_modules/lodash-es/_assignValue.js","webpack://ClassicEditor/./node_modules/lodash-es/_copyObject.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseTimes.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseIsArguments.js","webpack://ClassicEditor/./node_modules/lodash-es/isArguments.js","webpack://ClassicEditor/./node_modules/lodash-es/isArray.js","webpack://ClassicEditor/./node_modules/lodash-es/_isIndex.js","webpack://ClassicEditor/./node_modules/lodash-es/isLength.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseIsTypedArray.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseUnary.js","webpack://ClassicEditor/./node_modules/lodash-es/isTypedArray.js","webpack://ClassicEditor/./node_modules/lodash-es/_arrayLikeKeys.js","webpack://ClassicEditor/./node_modules/lodash-es/_isPrototype.js","webpack://ClassicEditor/./node_modules/lodash-es/_nativeKeys.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseKeys.js","webpack://ClassicEditor/./node_modules/lodash-es/isArrayLike.js","webpack://ClassicEditor/./node_modules/lodash-es/keys.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseAssign.js","webpack://ClassicEditor/./node_modules/lodash-es/_nativeKeysIn.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseKeysIn.js","webpack://ClassicEditor/./node_modules/lodash-es/keysIn.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseAssignIn.js","webpack://ClassicEditor/./node_modules/lodash-es/_copyArray.js","webpack://ClassicEditor/./node_modules/lodash-es/_arrayFilter.js","webpack://ClassicEditor/./node_modules/lodash-es/stubArray.js","webpack://ClassicEditor/./node_modules/lodash-es/_getSymbols.js","webpack://ClassicEditor/./node_modules/lodash-es/_copySymbols.js","webpack://ClassicEditor/./node_modules/lodash-es/_arrayPush.js","webpack://ClassicEditor/./node_modules/lodash-es/_getSymbolsIn.js","webpack://ClassicEditor/./node_modules/lodash-es/_copySymbolsIn.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseGetAllKeys.js","webpack://ClassicEditor/./node_modules/lodash-es/_getAllKeys.js","webpack://ClassicEditor/./node_modules/lodash-es/_getAllKeysIn.js","webpack://ClassicEditor/./node_modules/lodash-es/_DataView.js","webpack://ClassicEditor/./node_modules/lodash-es/_Promise.js","webpack://ClassicEditor/./node_modules/lodash-es/_Set.js","webpack://ClassicEditor/./node_modules/lodash-es/_WeakMap.js","webpack://ClassicEditor/./node_modules/lodash-es/_getTag.js","webpack://ClassicEditor/./node_modules/lodash-es/_initCloneArray.js","webpack://ClassicEditor/./node_modules/lodash-es/_Uint8Array.js","webpack://ClassicEditor/./node_modules/lodash-es/_cloneArrayBuffer.js","webpack://ClassicEditor/./node_modules/lodash-es/_cloneDataView.js","webpack://ClassicEditor/./node_modules/lodash-es/_cloneRegExp.js","webpack://ClassicEditor/./node_modules/lodash-es/_cloneSymbol.js","webpack://ClassicEditor/./node_modules/lodash-es/_cloneTypedArray.js","webpack://ClassicEditor/./node_modules/lodash-es/_initCloneByTag.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseCreate.js","webpack://ClassicEditor/./node_modules/lodash-es/_initCloneObject.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseIsMap.js","webpack://ClassicEditor/./node_modules/lodash-es/isMap.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseIsSet.js","webpack://ClassicEditor/./node_modules/lodash-es/isSet.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseClone.js","webpack://ClassicEditor/./node_modules/lodash-es/cloneDeepWith.js","webpack://ClassicEditor/./node_modules/lodash-es/isElement.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/config.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/spy.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/eventinfo.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/uid.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/priorities.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/emittermixin.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/mix.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/collection.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/plugincollection.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/translation-service.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/locale.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/context.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/comparearrays.js","webpack://ClassicEditor/./node_modules/lodash-es/clone.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/node.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/text.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/textproxy.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/isiterable.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/tomap.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/objecttomap.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/matcher.js","webpack://ClassicEditor/./node_modules/lodash-es/isSymbol.js","webpack://ClassicEditor/./node_modules/lodash-es/_isKey.js","webpack://ClassicEditor/./node_modules/lodash-es/memoize.js","webpack://ClassicEditor/./node_modules/lodash-es/_memoizeCapped.js","webpack://ClassicEditor/./node_modules/lodash-es/_stringToPath.js","webpack://ClassicEditor/./node_modules/lodash-es/_arrayMap.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseToString.js","webpack://ClassicEditor/./node_modules/lodash-es/toString.js","webpack://ClassicEditor/./node_modules/lodash-es/_castPath.js","webpack://ClassicEditor/./node_modules/lodash-es/last.js","webpack://ClassicEditor/./node_modules/lodash-es/_toKey.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseGet.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseSlice.js","webpack://ClassicEditor/./node_modules/lodash-es/_parent.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseUnset.js","webpack://ClassicEditor/./node_modules/lodash-es/unset.js","webpack://ClassicEditor/./node_modules/lodash-es/get.js","webpack://ClassicEditor/./node_modules/lodash-es/_assignMergeValue.js","webpack://ClassicEditor/./node_modules/lodash-es/_createBaseFor.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseFor.js","webpack://ClassicEditor/./node_modules/lodash-es/isArrayLikeObject.js","webpack://ClassicEditor/./node_modules/lodash-es/_safeGet.js","webpack://ClassicEditor/./node_modules/lodash-es/toPlainObject.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseMergeDeep.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseMerge.js","webpack://ClassicEditor/./node_modules/lodash-es/identity.js","webpack://ClassicEditor/./node_modules/lodash-es/_apply.js","webpack://ClassicEditor/./node_modules/lodash-es/_overRest.js","webpack://ClassicEditor/./node_modules/lodash-es/constant.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseSetToString.js","webpack://ClassicEditor/./node_modules/lodash-es/_shortOut.js","webpack://ClassicEditor/./node_modules/lodash-es/_setToString.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseRest.js","webpack://ClassicEditor/./node_modules/lodash-es/_isIterateeCall.js","webpack://ClassicEditor/./node_modules/lodash-es/_createAssigner.js","webpack://ClassicEditor/./node_modules/lodash-es/merge.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseSet.js","webpack://ClassicEditor/./node_modules/lodash-es/set.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/stylesmap.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/element.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/containerelement.js","webpack://ClassicEditor/./node_modules/lodash-es/assignIn.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/observablemixin.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/editableelement.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/rooteditableelement.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/treewalker.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/position.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/range.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/count.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/selection.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/documentselection.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/document.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/attributeelement.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/emptyelement.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/env.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/keyboard.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/uielement.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/documentfragment.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/downcastwriter.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/istext.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/filler.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/fastdiff.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/diff.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/insertat.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/remove.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/isnode.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/renderer.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/global.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/indexof.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/getancestors.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/domconverter.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/getcommonancestor.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/iswindow.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/emittermixin.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/observer/observer.js","webpack://ClassicEditor/./node_modules/lodash-es/_setCacheAdd.js","webpack://ClassicEditor/./node_modules/lodash-es/_setCacheHas.js","webpack://ClassicEditor/./node_modules/lodash-es/_SetCache.js","webpack://ClassicEditor/./node_modules/lodash-es/_arraySome.js","webpack://ClassicEditor/./node_modules/lodash-es/_cacheHas.js","webpack://ClassicEditor/./node_modules/lodash-es/_equalArrays.js","webpack://ClassicEditor/./node_modules/lodash-es/_mapToArray.js","webpack://ClassicEditor/./node_modules/lodash-es/_setToArray.js","webpack://ClassicEditor/./node_modules/lodash-es/_equalByTag.js","webpack://ClassicEditor/./node_modules/lodash-es/_equalObjects.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseIsEqualDeep.js","webpack://ClassicEditor/./node_modules/lodash-es/_baseIsEqual.js","webpack://ClassicEditor/./node_modules/lodash-es/isEqualWith.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/observer/mutationobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/observer/domeventdata.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/observer/domeventobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/observer/keyobserver.js","webpack://ClassicEditor/./node_modules/lodash-es/now.js","webpack://ClassicEditor/./node_modules/lodash-es/toNumber.js","webpack://ClassicEditor/./node_modules/lodash-es/debounce.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/observer/fakeselectionobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/observer/selectionobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/observer/focusobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/observer/compositionobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/observer/inputobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/isrange.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/getborderwidths.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/rect.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/scroll.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/view.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/node.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/text.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/textproxy.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/nodelist.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/element.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/treewalker.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/position.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/range.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/conversion/mapper.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/conversion/modelconsumable.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/conversion/downcastdispatcher.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/selection.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/liverange.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/documentselection.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/conversion/conversionhelpers.js","webpack://ClassicEditor/./node_modules/lodash-es/cloneDeep.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/conversion/downcasthelpers.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/conversion/upcasthelpers.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/controller/editingcontroller.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/commandcollection.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/conversion/viewconsumable.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/schema.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/conversion/upcastdispatcher.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/controller/datacontroller.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/conversion/conversion.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/batch.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/operation.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/documentfragment.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/utils.js","webpack://ClassicEditor/./node_modules/lodash-es/isEqual.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/attributeoperation.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/detachoperation.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/moveoperation.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/insertoperation.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/markeroperation.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/renameoperation.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/rootattributeoperation.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/mergeoperation.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/splitoperation.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/rootelement.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/writer.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/differ.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/history.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/unicode.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/document.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/markercollection.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/nooperation.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/operationfactory.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/liveposition.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/insertcontent.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/deletecontent.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/modifyselection.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/getselectedcontent.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/selection-post-fixer.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/model.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/keystrokehandler.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/editingkeystrokehandler.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/editor/editor.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/editor/utils/dataapimixin.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/editor/utils/elementapimixin.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/setdatainelement.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/dataprocessor/basichtmlwriter.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/componentfactory.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/focustracker.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/editor/editorui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/placeholder.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/elementreplacer.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-editor-classic/src/classiceditorui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/toolbar/normalizetoolbarconfig.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/toolbar/enabletoolbarkeyboardfocus.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/viewcollection.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/template.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/view.js","webpack://ClassicEditor/./node_modules/lodash-es/isString.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/editorui/bodycollection.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/createelement.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/editorui/editoruiview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/label/labelview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/editorui/boxed/boxededitoruiview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/editableui/editableuiview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/editableui/inline/inlineeditableuiview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/tounit.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/panel/sticky/stickypanelview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/focuscycler.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/toolbar/toolbarseparatorview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/resizeobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/dropdown/dropdownpanelview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/position.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/getpositionedancestor.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/dropdown/dropdownview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/icon/iconview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/tooltip/tooltipview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/button/buttonview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/dropdown/button/dropdownbuttonview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/assets/icons/dropdown-arrow.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/list/listview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/list/listitemview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/list/listseparatorview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/button/switchbuttonview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/dropdown/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/toolbar/toolbarview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/bindings/preventdefault.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/three-vertical-dots.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-editor-classic/src/classiceditoruiview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-editor-classic/src/classiceditor.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/editor/utils/attachtoform.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/dom/getdatafromelement.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/plugin.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-clipboard/src/datatransfer.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboardobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-clipboard/src/utils/viewtoplaintext.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-clipboard/src/clipboard.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-clipboard/src/utils/plaintexttohtml.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-clipboard/src/utils/normalizeclipboarddata.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/command.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-enter/src/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-enter/src/entercommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-enter/src/enterobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-enter/src/enter.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-enter/src/shiftentercommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-enter/src/shiftenter.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-typing/src/utils/changebuffer.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-typing/src/inputcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-typing/src/utils/injectunsafekeystrokeshandling.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-typing/src/utils/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/difftochanges.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-typing/src/utils/injecttypingmutationshandling.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-typing/src/input.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-typing/src/deletecommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-typing/src/deleteobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-typing/src/delete.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-typing/src/typing.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/transform.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-undo/src/basecommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-undo/src/undocommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-undo/src/redocommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-undo/src/undoediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-undo/theme/assets/icons/undo.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-undo/theme/assets/icons/redo.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-undo/src/undoui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-undo/src/undo.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/contextplugin.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/pendingactions.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-upload/src/filereader.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-upload/src/filerepository.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-autoformat/src/blockautoformatediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-autoformat/src/inlineautoformatediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-typing/src/utils/getlasttextline.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-autoformat/src/autoformat.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/attributecommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold/boldediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold/boldui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/theme/assets/icons/bold.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/theme/assets/icons/italic.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-utils/src/first.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquotecommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquoteediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquoteui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/quote.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ckfinder/src/ckfinderui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ckfinder/theme/assets/icons/browse-files.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/image/imageloadobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/image/converters.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-widget/src/highlightstack.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-widget/src/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-widget/theme/assets/icons/drag-handle.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/image/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/image/imageinsertcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/image/imageediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/src/findlinkrange.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/src/linkcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/src/unlinkcommand.js","webpack://ClassicEditor/./node_modules/lodash-es/_castSlice.js","webpack://ClassicEditor/./node_modules/lodash-es/_hasUnicode.js","webpack://ClassicEditor/./node_modules/lodash-es/_asciiToArray.js","webpack://ClassicEditor/./node_modules/lodash-es/_unicodeToArray.js","webpack://ClassicEditor/./node_modules/lodash-es/_stringToArray.js","webpack://ClassicEditor/./node_modules/lodash-es/_createCaseFirst.js","webpack://ClassicEditor/./node_modules/lodash-es/upperFirst.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/src/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/src/utils/automaticdecorators.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/src/utils/manualdecorator.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/utils/bindtwostepcarettoattribute.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/src/linkediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/notification/notification.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ckfinder/src/ckfindercommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ckfinder/src/ckfinderediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor-cloud-services-core/src/uploadgateway/fileuploader.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor-cloud-services-core/src/token/token.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-cloud-services/src/cloudservices.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-easy-image/src/cloudservicesuploadadapter.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor-cloud-services-core/src/uploadgateway/uploadgateway.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/observer/mouseobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-widget/src/widget.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagetextalternative/imagetextalternativecommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagetextalternative/imagetextalternativeediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/labeledinput/labeledinputview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/inputtext/inputtextview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/bindings/submithandler.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/check.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/cancel.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagetextalternative/ui/textalternativeformview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/assets/icons/previous-arrow.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/assets/icons/next-arrow.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/image/ui/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagetextalternative/imagetextalternativeui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/low-vision.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagetextalternative.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/image.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-upload/src/ui/filedialogbuttonview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imageupload/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imageupload/imageuploadui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/image.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imageupload/imageuploadprogress.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/theme/assets/icons/image_placeholder.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/upcastwriter.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imageupload/imageuploadcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imageupload/imageuploadediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imageupload.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-paragraph/src/paragraphcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-paragraph/src/paragraph.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-heading/src/headingcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-heading/src/headingediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/model.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-heading/src/headingui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-heading/src/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagecaption/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagecaption/imagecaptionediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagestyle/imagestylecommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagestyle/converters.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/object-full-width.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/object-left.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/object-center.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/object-right.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagestyle/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagestyle/imagestyleediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagestyle/imagestyleui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-widget/src/widgettoolbarrepository.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/src/multicommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-indent/src/indentediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-indent/theme/assets/icons/indent.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-indent/theme/assets/icons/outdent.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-indent/src/indentui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-engine/src/view/observer/clickobserver.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/src/ui/linkformview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/src/ui/linkactionsview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/theme/assets/icons/unlink.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/pencil.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/src/linkui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/theme/assets/icons/link.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-list/src/listcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-list/src/indentcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-list/src/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-list/src/converters.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-list/src/listediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-list/src/listui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-list/theme/assets/icons/numberedlist.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-list/theme/assets/icons/bulletedlist.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/src/converters.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/src/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/src/mediaembedcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/src/mediaregistry.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/theme/assets/icons/media-placeholder.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/src/mediaembedediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/src/automediaembed.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/src/ui/mediaformview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/src/mediaembedui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/theme/assets/icons/media.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-paste-from-office/src/filters/list.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-paste-from-office/src/normalizers/googledocsnormalizer.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-paste-from-office/src/filters/removeboldwrapper.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-paste-from-office/src/filters/space.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-paste-from-office/src/filters/parse.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-paste-from-office/src/filters/image.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-paste-from-office/src/normalizers/mswordnormalizer.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/commands/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/converters/upcasttable.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/tablewalker.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/converters/downcast.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/commands/inserttablecommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/commands/insertrowcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/commands/insertcolumncommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/commands/splitcellcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/commands/mergecellcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/commands/removerowcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/commands/removecolumncommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/commands/setheaderrowcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/commands/setheadercolumncommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/tableutils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/converters/table-layout-post-fixer.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/converters/table-cell-paragraph-post-fixer.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/converters/table-cell-refresh-post-fixer.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/tableediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/ui/inserttableview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/tableui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/theme/assets/icons/table.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/theme/assets/icons/table-column.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/theme/assets/icons/table-row.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/theme/assets/icons/table-merge-cell.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline/underlineediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline/underlineui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/theme/assets/icons/underline.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/theme/assets/icons/strikethrough.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/theme/assets/icons/code.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/theme/assets/icons/subscript.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/theme/assets/icons/superscript.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-remove-format/src/removeformatui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-remove-format/theme/assets/icons/remove-format.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-remove-format/src/removeformatcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-remove-format/src/removeformatediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-horizontal-line/src/horizontallinecommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-horizontal-line/src/horizontallineediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-horizontal-line/src/horizontallineui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-horizontal-line/theme/assets/icons/horizontalline.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-upload/src/adapters/base64uploadadapter.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-alignment/src/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-alignment/src/alignmentcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-alignment/src/alignmentediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/align-left.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/align-right.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-alignment/src/alignmentui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/align-center.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/align-justify.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-widget/src/widgetresize/resizerstate.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-widget/src/widgetresize/resizer.js","webpack://ClassicEditor/./node_modules/lodash-es/throttle.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-widget/src/widgetresize.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imageresize/imageresizecommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/colorgrid/colortileview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/theme/assets/icons/color-tile-check.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/colorgrid/colorgridview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/documentcolorcollection.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/ui/colortableview.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-core/theme/assets/icons/eraser.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontfamily/fontfamilycommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontfamily/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontfamily/fontfamilyediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontfamily/fontfamilyui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/theme/assets/icons/font-family.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontfamily.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontsize/fontsizecommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontsize/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontsize/fontsizeediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontsize/fontsizeui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/theme/assets/icons/font-size.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontsize.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontcolor/fontcolorcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontcolor/fontcolorediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ui/src/colorgrid/utils.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/ui/colorui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontcolor/fontcolorui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/theme/assets/icons/font-color.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontcolor.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontbackgroundcolor/fontbackgroundcolorcommand.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontbackgroundcolor/fontbackgroundcolorediting.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontbackgroundcolor/fontbackgroundcolorui.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/theme/assets/icons/font-background.svg","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/fontbackgroundcolor.js","webpack://ClassicEditor/./src/ckeditor.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-essentials/src/essentials.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/bold.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/italic.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-block-quote/src/blockquote.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-ckfinder/src/ckfinder.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-easy-image/src/easyimage.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-heading/src/heading.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagecaption.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagestyle.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imagetoolbar.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-indent/src/indent.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-link/src/link.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-list/src/list.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-media-embed/src/mediaembed.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-paste-from-office/src/pastefromoffice.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/table.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-table/src/tabletoolbar.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/underline.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/code.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-remove-format/src/removeformat.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-horizontal-line/src/horizontalline.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-alignment/src/alignment.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-image/src/imageresize.js","webpack://ClassicEditor/./node_modules/@ckeditor/ckeditor5-font/src/font.js"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","CKEditorError","Error","message","context","data","attachLinkToDocumentation","JSON","stringify","super","this","type","err","is","error","stack","matchedErrorName","match","memo","isOldIE","Boolean","document","all","atob","getTarget","target","styleTarget","querySelector","HTMLIFrameElement","contentDocument","head","e","stylesInDom","getIndexByIdentifier","identifier","result","length","modulesToDom","list","options","idCountMap","identifiers","item","id","base","count","concat","index","obj","css","media","sourceMap","references","updater","push","addStyle","insertStyleElement","style","createElement","attributes","nonce","keys","forEach","setAttribute","insert","appendChild","textStore","replaceText","replacement","filter","join","applyToSingletonTag","remove","styleSheet","cssText","cssNode","createTextNode","childNodes","removeChild","insertBefore","applyToTag","removeAttribute","btoa","unescape","encodeURIComponent","firstChild","singleton","singletonCounter","update","styleIndex","parentNode","removeStyleElement","newObj","lastIdentifiers","newList","toString","newLastIdentifiers","_i","_index","splice","freeSelf","self","Function","freeExports","nodeType","freeModule","Buffer","undefined","isBuffer","freeProcess","process","nodeUtil","types","require","binding","windowOrGlobal","global","CKEDITOR_VERSION","freeGlobal","allocUnsafe","buffer","isDeep","slice","constructor","copy","originalModule","webpackPolyfill","children","g","api","content","default","exported","locals","objectProto","nativeObjectToString","symToStringTag","isOwn","tag","unmasked","func","transform","arg","getPrototypeOf","funcProto","funcToString","objectCtorString","proto","Ctor","__data__","size","other","array","Array","pop","ListCache","entries","clear","entry","set","has","uid","maskSrcKey","exec","IE_PROTO","reIsHostCtor","reIsNative","RegExp","replace","test","Hash","map","MapCache","pairs","LARGE_ARRAY_SIZE","Stack","iteratee","objValue","source","props","customizer","isNew","newValue","propertyIsEnumerable","arguments","isArray","reIsUint","typedArrayTags","nodeIsTypedArray","isTypedArray","inherited","isArr","isArg","isBuff","isType","skipIndexes","String","isProto","predicate","resIndex","nativeGetSymbols","getOwnPropertySymbols","symbol","values","offset","keysFunc","symbolsFunc","dataViewCtorString","mapCtorString","promiseCtorString","setCtorString","weakMapCtorString","getTag","ArrayBuffer","resolve","ctorString","input","Uint8Array","arrayBuffer","byteLength","dataView","byteOffset","reFlags","regexp","lastIndex","symbolProto","symbolValueOf","valueOf","typedArray","objectCreate","nodeIsMap","isMap","nodeIsSet","isSet","cloneableTags","baseClone","bitmask","isFlat","isFull","isFunc","stacked","subValue","add","keysIn","configurations","defaultConfigurations","_config","cloneConfig","_setObjectToTarget","_setToTarget","_getFromSource","isDefine","parts","split","part","configuration","leaveDOMReferences","spy","called","path","stop","off","HEX_NUMBERS","fill","val","r1","Math","random","r2","r3","r4","priority","normal","highest","high","low","lowest","_listeningTo","_emitterId","event","callback","listenTo","wasFired","args","stopListening","emitter","emitterInfo","eventCallbacks","emitters","_getEmitterId","_setEmitterId","emitterId","callbacks","eventName","events","getEvents","childEventName","newEventNodes","childEvents","substr","lastIndexOf","node","createEventNamespace","lists","getCallbacksListsForNamespace","callbackDefinition","added","removeCallback","eventOrInfo","eventInfo","getCallbacksForEvent","_events","indexOf","callbackArgs","from","apply","_delegations","destinations","passAllDestinations","fireDelegatedEvents","return","rethrowUnexpectedError","to","nameOrFunction","Map","delete","eventNode","callbacksLists","childCallbacksLists","fireArgs","delegatedInfo","fire","mix","baseClass","mixins","mixin","getOwnPropertyNames","sourceDescriptor","getOwnPropertyDescriptor","_items","_itemMap","_idProperty","idProperty","_bindToExternalToInternalMap","WeakMap","_bindToInternalToExternalMap","_skippedIndexesFromExternal","itemId","idOrIndex","itemOrId","subject","itemDoesNotExist","externalItem","ctx","find","_bindToCollection","externalCollection","as","Class","_setUpBindToBinding","using","callbackOrProperty","addItem","evt","isExternalBoundToThis","externalItemBound","finalIndex","skipped","getIndex","reduce","iterator","availablePlugins","contextPlugins","_context","_plugins","_availablePlugins","PluginConstructor","pluginName","_contextPlugins","pluginInstance","plugin","errorMsg","plugins","removePlugins","that","loading","Set","loaded","pluginConstructors","mapToAvailableConstructors","removePluginConstructors","missingPlugins","pluginNameOrConstructor","getPluginConstructor","getMissingPluginNames","console","Promise","reject","loadPlugin","then","initPlugins","includes","requires","RequiredPluginConstructorOrName","RequiredPluginConstructor","isContextPlugin","requiredBy","_add","instantiatePlugin","catch","loadedPlugins","method","promise","PluginConstructorOrName","promises","destroy","plugin1","plugin2","translate","language","translationKey","numberOfLanguages","CKEDITOR_TRANSLATIONS","hasTranslation","RTL_LANGUAGE_CODES","uiLanguage","contentLanguage","uiLanguageDirection","getLanguageDirection","contentLanguageDirection","_t","warn","str","translatedString","languageCode","config","defaultConfig","builtinPlugins","languageConfig","locale","ui","editors","_contextOwner","Plugin","init","editor","isContextOwner","names","compareArrays","a","b","minLen","min","parent","pos","getChildIndex","getChild","unshift","includeSelf","parentFirst","ancestors","ancestorsA","getAncestors","ancestorsB","thisPath","getPath","nodePath","isBefore","_removeChildren","_fireChange","json","_textData","otherNode","textNode","offsetInText","substring","isIterable","toMap","objectToMap","Matcher","pattern","_patterns","classes","element","singleElement","isElementMatching","results","matchName","patterns","hasAttribute","attribute","getAttribute","matchAttributes","getClassNames","hasClass","matchClasses","styles","hasStyle","getStyle","matchStyles","reIsDeepProp","reIsPlainProp","memoize","resolver","TypeError","memoized","cache","Cache","rePropName","reEscapeChar","string","charCodeAt","number","quote","subString","symbolToString","baseToString","start","end","defaultValue","fromRight","iterable","srcIndex","mergeFunc","srcValue","isCommon","isTyped","baseMerge","thisArg","nativeMax","max","otherArgs","nativeNow","Date","now","lastCalled","stamp","remaining","assigner","sources","guard","nested","_styles","_styleProcessor","isEmpty","getStyleNames","inlineStyle","parsedStyles","stylesString","quoteType","propertyNameStart","propertyValueStart","propertyName","stylesMap","charAt","char","propertyValue","trim","parseInlineStyles","toNormalizedForm","propertyDescriptor","getReducedForm","nameOrObject","valueOrObject","toPath","_cleanEmptyObjectsOnPath","getNormalized","_getStylesEntries","arr","sort","getRelatedStyles","parsed","pathParts","parentPath","parentObject","_processor","processor","_normalizers","_extractors","_reducers","_consumables","appendStyleValue","normalizer","extractor","normalizedValue","reducer","callbackOrPath","shorthandName","styleNames","_mapStyleNames","alsoName","stylesObject","nameOrPath","valueToSet","attrs","_attrs","parseAttributes","_children","_insertChild","_classes","classString","parseClasses","setTo","_customProperties","cutType","otherElement","className","getAsString","matcher","deep","childrenClone","child","getChildren","_clone","cloned","getFillerOffset","items","childCount","nodes","normalize","_remove","howMany","classesSet","classesString","classArray","lastChild","observablePropertiesSymbol","boundObservablesSymbol","boundPropertiesSymbol","ObservableMixin","initObservable","properties","configurable","oldValue","bindProperties","isStringArray","boundProperties","bindings","bindTo","toMany","bindToMany","_observable","_bindProperties","_to","_bindings","unbindProperties","boundObservables","toObservable","toProperty","toProperties","toPropertyBindings","boundObservable","methodName","originalMethod","on","observable","parsedArgs","lastObservable","parseBindToArgs","bindingsKeys","numberOfBindings","updateBoundObservableProperty","chain","toPropertyName","bindingsToObservable","updateBoundObservables","updateBindToBound","observables","observableAndAttributePairs","getBindingTargets","every","documentSymbol","getCustomProperty","_setCustomProperty","isFocused","selection","editableElement","rootNameSymbol","rootName","boundaries","startPosition","direction","position","_createAt","singleCharacters","shallow","ignoreElementEnd","_boundaryStartParent","_boundaryEndParent","skip","done","prevPosition","next","_next","_previous","clone","previousPosition","isAtEnd","_createAfter","_formatReturnValue","charactersCount","textLength","textProxy","isAtStart","_createBefore","startOffset","nextPosition","isEqual","endOffset","editable","shift","shifted","treeWalker","otherPosition","compareWith","otherPath","itemOrPosition","getLastMatchingPosition","enlargeTrimSkip","isAfter","nodeAfterStart","nodeAfter","nodeBeforeEnd","nodeBefore","otherRange","loose","isCollapsed","containsStart","containsPosition","containsEnd","ranges","isIntersecting","commonRangeStart","commonRangeEnd","getCommonAncestor","startElement","endElement","getShiftedBy","_createFromParentsAndOffsets","offsetSize","_createFromPositionAndShift","_","selectable","placeOrOffset","_ranges","_lastRangeBackward","_isFake","_fakeSelectionLabel","range","rangeCount","anchor","first","last","firstRange","getFirstRange","lastRange","getLastRange","otherSelection","isFake","fakeSelectionLabel","focus","thisRange","found","isBackward","numOfRangesA","getRanges","rangeA","getTrimmed","rangeB","nextSibling","previousSibling","_setRanges","_setFakeOptions","fake","label","backward","_createIn","_createOn","newFocus","_addRange","newRanges","isLastBackward","_pushRange","storedRange","addedRange","intersectingRange","_selection","delegate","getFirstPosition","getLastPosition","getSelectedElement","isSimilar","setFocus","roots","_postFixers","postFixer","writer","wasFixed","_priority","_id","_clonesGroup","nonUiChildrenCount","DEFAULT_PRIORITY","userAgent","navigator","toLowerCase","isMac","isEdge","isGecko","isSafari","isAndroid","features","isRegExpUnicodePropertySupported","isSupported","search","macGlyphsToModifiers","modifiersToMacGlyphs","keyCodes","arrowleft","arrowup","arrowright","arrowdown","backspace","enter","space","esc","tab","ctrl","cmd","alt","code","letter","fromCharCode","generateKnownKeyCodes","getCode","keyCode","altKey","ctrlKey","shiftKey","parseKeystroke","keystroke","splitKeystrokeText","sum","getEnvKeystrokeText","domDocument","toDomElement","domElement","getAttributeKeys","injectUiElementHandling","view","domConverter","domSelection","domTarget","ownerDocument","defaultView","getSelection","domSelectionCollapsed","getRangeAt","collapsed","domParent","focusNode","domOffset","focusOffset","viewPosition","domPositionToView","jumpedOverAnyUiElement","nextViewPosition","newDomPosition","viewPositionToDom","collapse","extend","jumpOverUiElement","_cloneGroups","_setTo","_setFocus","attributeElement","_document","renderFunction","uiElement","render","_setAttribute","_removeAttribute","_addClass","_removeClass","_setStyle","_removeStyle","_removeCustomProperty","positionOrRange","_breakAttributes","_breakAttributesRange","newElement","sourceRange","targetPosition","move","positionOffset","positionParent","_removeFromClonedElementsGroup","mergeAttributes","mergeTextNodes","_appendChild","prev","newPosition","validateNodesToInsert","errorContext","validNodesToInsert","some","validNode","container","getParentContainer","insertionPosition","_addToClonedElementsGroup","endPosition","rangeOrItem","validateRangeContainer","breakStart","breakEnd","parentContainer","removed","mergePosition","walker","getWalker","current","rangeToRemove","parentElement","ancestor","countBefore","_wrapPosition","viewSelection","setSelection","_wrapRange","newRange","_unwrapChildren","newName","viewElement","getAttributes","groupName","wrapElement","wrapPositions","isText","isAttribute","isUI","_wrapAttributeElement","shouldABeOutsideB","newAttribute","_wrapChildren","offsetChange","unwrapElement","unwrapPositions","unwrapped","_unwrapAttributeElement","movePositionToTextNode","breakTextNode","fakePosition","createAttributeElement","Number","POSITIVE_INFINITY","wrapRange","wrap","wrapper","toWrap","canBeJoined","setStyle","addClass","toUnwrap","removeClass","removeStyle","forceSplitText","rangeStart","rangeEnd","isContainerOrFragment","offsetAfter","clonedNode","nodesToMove","group","getIdentity","textToMove","_data","t1","t2","nodeBeforeLength","startContainer","endContainer","NBSP_FILLER","BR_FILLER","fillerBr","dataset","ckeFiller","INLINE_FILLER","inlineFiller","startsWithFiller","domNode","isInlineFiller","domText","getDataWithoutFiller","jumpOverInlineFiller","fastDiff","cmp","atomicChanges","changeIndexes","arr1","arr2","firstIndex","findFirstDifferenceIndex","lastIndexOld","lastIndexNew","oldArrayReversed","cutAndReverse","newArrayReversed","findChangeBoundaryIndexes","newLength","changeIndexesToAtomicChanges","newArray","changeIndexesToChanges","reverse","aLength","bLength","_insert","_delete","tmp","delta","es","fp","snake","k","y1","y2","dir","y","x","nodeToInsert","isNode","Document","Node","domDocuments","markedAttributes","markedChildren","markedTexts","_inlineFiller","_fakeSelectionContainer","mapViewToDom","inlineFillerPosition","_updateChildrenMappings","_isSelectionInInlineFiller","_removeInlineFiller","_getInlineFillerPosition","_needsInlineFillerAtSelection","_updateAttrs","_updateChildren","_updateText","fillerDomPosition","addInlineFiller","_updateSelection","_updateFocus","actualDomChildren","expectedDomChildren","viewChildrenToDom","withChildren","diff","_diffNodeLists","actions","_findReplaceActions","counter","equal","action","insertIndex","deleteIndex","viewChild","_updateElementMappings","unbindDomElement","bindElements","firstPos","selectionPosition","domFillerNode","selectionParent","selectionOffset","findAncestor","isEditable","viewText","findCorrespondingDomText","newDomText","viewToDom","actualText","expectedText","filler","insertData","deleteData","domAttrKeys","attr","viewAttrKeys","nodesToUnbind","_markDescendantTextToSync","domToView","domChildList","fakeSelectionContainer","childList","filterOutFakeSelectionContainer","actualDom","expectedDom","newActions","actualSlice","expectedSlice","areSimilar","viewNode","_removeDomSelection","_removeFakeSelection","domRoot","_updateFakeSelection","_updateDomSelection","assign","top","left","width","textContent","createFakeSelectionContainer","bindFakeSelection","_fakeSelectionNeedsUpdate","domRange","createRange","removeAllRanges","selectNodeContents","addRange","_domSelectionNeedsUpdate","ELEMENT_NODE","childAtOffset","tagName","fixGeckoSelectionAfterBr","isDomSelectionCorrect","oldViewSelection","domSelectionToView","anchorNode","contains","doc","activeDomElement","activeElement","mapDomToView","domParentOrArray","nodeAfterFiller","fillerNode","node1","node2","actualDomChild","expectedDomChild","isBlockFiller","DOCUMENT_NODE","BR_FILLER_REF","blockFillerMode","preElements","blockElements","_blockFiller","_domToViewMapping","_viewToDomMapping","_fakeSelectionMapping","viewDocumentSelection","domFragment","viewFragment","textData","_processDataFromViewText","createDocumentFragment","bindDocumentFragments","createElementNS","fillerPositionOffset","childView","viewRange","domStart","domEnd","setStart","setEnd","viewParent","domBefore","domAfter","getParentUIElement","_processDataFromDomText","isComment","isDocumentFragment","viewName","keepOriginalCase","domChildrenToView","domChild","fakeSelectionToView","isDomSelectionBackward","viewRanges","domRangeToView","viewStart","viewEnd","findCorrespondingViewText","viewBefore","domElementOrDocumentFragment","isElement","documentFragmentOrElement","viewEditable","domEditable","scrollX","scrollY","scrollPositions","forEachDomNodeAncestor","scrollLeft","scrollTop","scrollTo","DOCUMENT_FRAGMENT_NODE","COMMENT_NODE","isEqualNode","hasBlockParent","isNbspBlockFiller","anchorOffset","detach","_isDomSelectionPositionCorrect","prevNode","_getTouchingViewTextNode","_nodeEndsWithSpace","nextNode","_hasDomParentOfType","_getTouchingInlineDomNode","shouldLeftTrim","_checkShouldLeftTrimDomText","shouldRightTrim","_checkShouldRightTrimDomText","Text","getNext","topmostParent","createTreeWalker","NodeFilter","SHOW_TEXT","SHOW_ELEMENT","acceptNode","FILTER_ACCEPT","FILTER_SKIP","currentNode","touchingNode","lca","nodeA","nodeB","boundaryParent","parents","isWindow","stringifiedObject","rest","proxy","_getProxyEmitter","attach","listeningEmitter","listenedToEmitterId","getNodeUID","_domNode","_domListeners","domListener","_createDomListener","useCapture","addEventListener","removeListener","domEvt","removeEventListener","Observer","isEnabled","disable","SetCache","equalFunc","isPartial","arrLength","othLength","seen","arrValue","othValue","compared","othIndex","convert","objProps","objLength","skipCtor","objCtor","othCtor","objIsArr","othIsArr","objTag","othTag","objIsObj","othIsObj","isSameTag","objIsWrapped","othIsWrapped","objUnwrapped","othUnwrapped","baseIsEqual","characterData","characterDataOldValue","subtree","renderer","_renderer","_domElements","_mutationObserver","MutationObserver","_onMutations","takeRecords","observe","enable","disconnect","domMutations","mutatedTexts","mutatedElements","mutation","_isBogusBrMutation","text","oldText","newText","viewMutations","mutatedText","markToSync","viewChildren","newViewChildren","sameNodes","oldChildren","newChildren","viewSelectionAnchor","viewSelectionFocus","child1","child2","forceRender","addedNode","removedNodes","addedNodes","domEvent","additionalData","preventDefault","stopPropagation","domEventType","onDomEvent","eventType","metaKey","reTrim","reIsBadHex","reIsBinary","reIsOctal","freeParseInt","parseInt","isBinary","nativeMin","wait","lastArgs","lastThis","maxWait","timerId","lastCallTime","lastInvokeTime","leading","maxing","trailing","invokeFunc","time","leadingEdge","setTimeout","timerExpired","shouldInvoke","timeSinceLastCall","trailingEdge","timeWaiting","remainingWait","debounced","isInvoking","clearTimeout","cancel","flush","_fireSelectionChangeDoneDebounced","_handleSelectionMove","newSelection","oldSelection","mutationObserver","getObserver","_documents","WeakSet","_clearInfiniteLoopInterval","setInterval","_clearInfiniteLoop","_loopbackCounter","_handleSelectionChange","clearInterval","newViewSelection","_renderTimeoutId","selectedEditable","isComposing","isRange","getBorderWidths","getComputedStyle","borderTopWidth","right","borderRightWidth","bottom","borderBottomWidth","borderLeftWidth","rectProperties","isSourceRange","_source","writable","copyRectProperties","getDomRangeRects","getBoundingClientRect","innerWidth","innerHeight","height","anotherRect","rect","getIntersection","getArea","visibleRect","isBody","commonAncestorContainer","parentRect","intersectionRect","prop","intersectRect","scrollBarWidth","scrollBarHeight","documentElement","clientWidth","clientHeight","borderWidths","offsetWidth","offsetHeight","rects","clientRects","getClientRects","elementOrRange","body","scrollViewportToShowTarget","viewportOffset","targetWindow","getWindow","currentWindow","currentFrame","firstAncestorToScroll","getParentElement","scrollAncestorsToShowRect","getRectRelativeToWindow","targetRect","scrollWindowToShowRect","frameElement","targetShiftedDownRect","moveBy","targetShiftedUpRect","viewportRect","excludeScrollbarsAndBorders","isAbove","isBelow","isLeftOf","isRightOf","getRect","parentWindow","firstRect","secondRect","relativeWindow","frame","frameRect","scrollAncestorsToShowTarget","domRoots","_initialDomRootAttributes","_observers","_ongoingChange","_postFixersInProgress","_renderingDisabled","_hasChangedSinceTheLastRendering","_writer","addObserver","_render","viewRoot","getRoot","_name","initialDomRootAttributes","updateContenteditableAttribute","isReadOnly","change","observer","viewRangeToDom","isRenderingInProgress","callbackResult","_callPostFixers","flag","disableObservers","enableObservers","getChildStartOffset","toJSON","_nodes","_insertNodes","getNodeIndex","maxOffset","getNodeStartOffset","totalOffset","nodeList","indexStart","getNode","offsetToIndex","relativePath","_removeNodes","fromJSON","stickiness","_visitedParent","prevVisitedParent","formatReturnValue","offsetInTextNode","newOffset","diffAt","leftParent","getParentPath","operation","_getTransformedByInsertOperation","_getTransformedByMoveOperation","_getTransformedBySplitOperation","_getTransformedByMergeOperation","_getTransformedByInsertion","_getTransformedByMove","sourcePosition","movedRange","_getCombined","splitPosition","moveTargetPosition","graveyardPosition","_getTransformedByDeletion","deletionPosition","deletePosition","transformed","insertPosition","combined","graveyard","getCommonPath","posParent","operations","getTransformedByOperation","j","containsRange","spread","newPos","moveRange","differenceSet","getDifference","difference","common","transformedCommon","newStart","newEnd","ref","refIndex","_modelToViewMapping","_viewToModelMapping","_viewToModelLengthCallbacks","_markerNameToElements","_elementToMarkerNames","_unboundMarkerNames","viewContainer","modelPosition","_findPositionIn","viewBlock","findMappedViewAncestor","modelParent","modelOffset","_toModelOffset","modelElement","toModelElement","markerName","toViewElement","elements","nameToElements","elementToNames","markerNames","toModelPosition","modelRange","toViewPosition","mapper","isPhantom","boundElements","getElementsWithSameId","viewElementName","lengthCallback","viewOffset","getModelLength","len","expectedOffset","lastLength","_moveViewPositionToTextNode","_consumable","_textProxyRegistry","_normalizeConsumableType","_getSymbolForTextProxy","itemConsumables","startMap","endMap","_addSymbolForTextProxy","conversionApi","dispatcher","differ","markers","getMarkersToRemove","convertMarkerRemove","getChanges","convertInsert","convertRemove","convertAttribute","attributeKey","attributeOldValue","attributeNewValue","flushUnboundMarkerNames","markerRange","getRange","convertMarkerAdd","getMarkersToAdd","consumable","_createInsertConsumable","_testAndFire","_clearConversionApi","_createConsumableForRange","markersAtSelection","getMarkersAtPosition","_createSelectionConsumable","marker","shouldMarkerChangeBeConverted","getItems","containsItem","anyNewRange","oldRange","_removeAllRanges","directChange","_popRange","attributeKeys","visited","startBlock","getParentBlock","isTopBlockInRange","block","isUnvisitedTopBlock","endBlock","isTouching","limitStartPosition","limitEndPosition","_checkRange","isUnvisitedBlock","model","schema","isBlock","hasParentLimit","isLimit","parentBlock","findAncestorBlock","bindWithDocument","isDocumentOperation","_createFromRanges","boundariesChanged","contentChanged","doesOperationChangeRangeContent","toRange","hasOwnRange","isGravityOverridden","getSelectedBlocks","containsEntireContent","_updateMarkers","_updateAttributes","_getStoredAttributes","overrideGravity","restoreGravity","startsWith","_model","_attributePriority","_fixGraveyardRangesData","_hasChangedRange","_overriddenGravityRegister","liveRange","_fixGraveyardSelection","_validateSelectionRange","batch","changeParent","enqueueChange","storedAttributes","clearAttributesStoredInElement","_getDefaultRange","optionsOrPlaceOrOffset","overrideUid","_prepareRange","fromRange","changed","selectionRange","oldMarkers","clearAll","newAttributes","_getSurroundingAttributes","oldAttributes","_setAttributesTo","newKey","oldKey","realKey","getAttrsIfCharacter","isObject","removedRangeStart","positionCandidate","getNearestSelectionRange","ConversionHelpers","dispatchers","_dispatchers","conversionHelper","normalizeToElementConfig","elementCreator","consume","converterPriority","downcastElementToElement","modelValue","getFromAttributeCreator","oldViewElement","newViewElement","viewWriter","toViewRange","unwrap","downcastAttributeToElement","normalizeToAttributeConfig","attributeCreator","oldAttribute","downcastAttributeToAttribute","isOpening","viewStartElement","viewEndElement","bindElementToMarker","markerNameToElements","unbindElementFromMarkerName","createRangeOn","clearClonedElementsGroup","downcastMarkerToElement","highlightDescriptor","descriptor","prepareDescriptor","createViewElementFromHighlightDescriptor","rangeAfterWrap","highlightElement","viewHighlightElement","removeHighlight","downcastMarkerToHighlight","viewElementType","modelData","viewElementDefinition","createContainerElement","createUIElement","createViewElementFromDefinition","modelAttributeValue","upcastElementToElement","normalizeModelAttributeConfig","converter","prepareToAttributeConverter","elementName","getViewElementNameFromConfig","upcastElementToAttribute","viewKey","normalized","normalizeViewAttributeKeyValueConfig","upcastAttributeToAttribute","oldModel","modelWriter","normalizeToMarkerConfig","upcastElementToMarker","matcherResult","viewItem","splitResult","splitToAllowedParent","modelCursor","convertChildren","createPositionAt","getSplitParts","createPositionBefore","createPositionAfter","cursorParent","prepareToElementConverter","viewConfig","viewAttributeKeyToCopy","defaultModelValue","modelKey","configToTest","onlyViewNameIsDefined","modelAttribute","checkAttribute","setAttributeOn","downcastDispatcher","_disableRendering","convertChanges","convertSelection","modelSelection","toModelRange","convertSelectionChange","createText","modelEnd","createRangeIn","unbindViewElement","brokenPosition","breakAttributes","_commands","commandName","command","execute","commands","ViewConsumable","consumables","elementConsumables","revert","instance","consumablesFromElement","createFrom","_canConsumeName","_test","_consume","_revert","consumableName","toConsume","_sourceDefinitions","_attributeProperties","decorate","SchemaContext","getDefinition","itemName","definition","_clearCache","_compiledDefinitions","_compile","getDefinitions","def","isInline","_checkContextMatch","attributeName","allowAttributes","positionOrBaseElement","elementToMerge","checkMerge","checkChild","childDef","retValue","getAttributeProperties","selectionOrRangeOrPosition","rangeCommonAncestor","getMinimalFlatRanges","convertToMinimalFlatRanges","_getValidRangesForRange","backwardWalker","forwardWalker","forward","step","combineWalkers","removeDisallowedAttributeFromNode","positionsInRange","getPositions","compiledDefinitions","sourceRules","itemNames","compileBaseItemRule","compileAllowContentOf","compileAllowWhere","compileAllowAttributesOf","compileInheritPropertiesFrom","cleanUpAllowIn","cleanUpAllowAttributes","contextItemIndex","contextItem","getItem","allowIn","parentRule","mapContextItem","query","getNames","endsWith","sourceItemRules","itemRule","allowContentOf","allowWhere","allowAttributesOf","inheritTypesFrom","sourceItemRule","typeNames","copyTypes","copyProperty","inheritFrom","inheritAllFrom","makeInheritAllWork","allowContentOfItemName","getAllowedChildren","allowedItem","allowWhereItemName","allowedIn","allowAttributeOfItem","inheritAttributes","inheritPropertiesOfItem","existingItems","itemToCheck","ctxItem","_splitParts","_modelCursor","convertItem","_convertItem","_convertChildren","_splitToAllowedParent","_getSplitParts","contextDefinition","append","createContextTree","store","documentFragment","_removeEmptyElements","modelItem","markerElements","markerElement","currentPosition","extractMarkersFromModelFragment","nextModelCursor","allowedParent","findAllowedParent","treeWalkerValue","originalPart","splitPart","_registerSplitPair","anyRemoved","dataProcessor","upcastDispatcher","_checkIfRootsExists","hasContent","ignoreWhitespaces","modelElementOrFragment","viewDocumentFragment","toView","toData","clearBindings","elementRange","intersection","_getMarkersRelativeToElement","version","initialData","main","modelRoot","parse","newData","removeSelectionAttribute","toModel","viewElementOrFragment","rootNames","getRootNames","downcastDispatchers","upcastDispatchers","_helpers","_downcast","_createConversionHelpers","isDowncast","_upcast","alias","for","elementToElement","_getAllUpcastDefinitions","attributeToElement","elementToAttribute","attributeToAttribute","helpers","upcastAlso","_getUpcastDefinition","upcastAlsoItem","Batch","op","baseVersion","Operation","__className","_normalizeNodes","_splitNodeAtPosition","_mergeNodesAtIndex","_move","_haveSameAttributes","mergedNode","offsetDiff","firstPart","secondPart","iteratorA","iteratorB","newTargetPosition","getMovedRangeStart","sourceElement","targetElement","sourceOffset","targetOffset","shouldReceiveAttributes","gyPosition","originalNodes","affectsData","_markers","oldName","mergedElement","getInsertionPosition","splitElement","_doc","_assertWriterUsedCorrectly","isSameTree","addOperation","applyOperation","rangeRootPosition","usingOperation","updateMarker","addMarker","itemOrRange","setAttributeOnRange","setAttributeOnItem","removeAttributesFromItem","_addOperationForAffectedMarkers","flat","applyRemoveOperation","_merge","_mergeDetached","createPositionFromPath","createSelection","merge","renameOperation","limitElement","firstSplitElement","firstCopyElement","elementOrString","shiftedRange","applyMarkerOperation","_set","markerOrName","currentMarker","_refresh","hasUsingOperationDefined","affectsDataDefined","currentRange","updatedRange","managedUsingOperations","keyOrObjectOrIterable","_setSelectionAttribute","keyOrIterableOfKeys","_removeSelectionAttribute","_overrideGravity","_restoreGravity","storeKey","_getStoreAttributeKey","_currentWriter","isAffected","elementBefore","elementAfter","affectedInLeftElement","affectedInRightElement","affectedAfterLeftElement","affectedBeforeRightElement","valueBefore","valueAfter","lastSplitPosition","previousValue","rootA","rootB","markerCollection","_markerCollection","_changesInElement","_elementSnapshots","_changedMarkers","_changeCount","_cachedChanges","_cachedChangesWithGraveyard","_isInInsertedElement","_markRemove","_markInsert","getMarkersIntersectingRange","bufferMarkerChange","_markAttribute","sourceParentInserted","targetParentInserted","graveyardParent","mergedIntoElement","buffered","includeChangesInGraveyard","diffSet","changes","snapshotChildren","elementChildren","_getChildrenSnapshot","_generateActionsFromChanges","_getInsertDiff","_getRemoveDiff","elementAttributes","snapshotAttributes","_getAttributesDiff","changeCount","prevDiff","thisDiff","isConsecutiveTextRemove","isConsecutiveTextAdd","isConsecutiveAttributeChange","_changesInGraveyardFilter","changeItem","_markChange","_removeAllNestedChanges","_makeSnapshot","_getChangesForElement","_handleChange","inc","nodesToHandle","old","incEnd","oldEnd","intersectionLength","howManyAfter","attributePart","diffs","snapshot","oldChildrenLength","oldChildrenHandled","repeat","posInGy","rangeInGy","History","_operations","_undoPairs","_undoneOperations","undoneOperation","undoingOperation","isInsideSurrogatePair","character","isLowSurrogateHalf","isInsideCombinedSymbol","history","_hasSelectionChangedFromTheLastChangeBlock","createRoot","bufferOperation","_hasDocumentChangedFromTheLastChangeBlock","refresh","hasDataChanges","reset","defaultRoot","_getDefaultRoot","validateTextNodePosition","rangeBoundary","oldMarker","hasChanged","_attachLiveRange","_managedUsingOperations","_affectsData","_destroyMarker","prefix","_detachLiveRange","_liveRange","stopDelegating","oldPosition","toPosition","canMergeWith","_filterAttributesOf","_affectedStart","_affectedEnd","parentContext","_handleNode","isFirst","isLast","removeDisallowedAttributes","nodeToSelect","_handleObject","_checkAndSplitToAllowedPosition","_mergeSiblingsOf","_handleDisallowedNode","_tryAutoparagraphing","handleNodes","livePos","fromPosition","_setAffectedBoundaries","mergeLeft","_canMergeLeft","mergeRight","_canMergeRight","mergePosLeft","mergePosRight","livePosition","paragraph","_getAllowedIn","tempPos","deleteContent","selRange","doNotResetEntireContent","getLimitElement","shouldEntireContentBeReplacedWithParagraph","insertParagraph","replaceEntireContentWithParagraph","startPos","endPos","leaveUnmerged","mergeBranches","startParent","endParent","leftPos","rightPos","rangeToCheck","checkCanBeMerged","parentToRemove","collapseSelectionAt","isTextAllowed","isParagraphAllowed","shouldAutoparagraph","validSelectionRange","doNotAutoparagraph","tryExtendingTo","unit","isForward","isAtWordBoundary","isAtNodeBoundary","boundaryChar","getCorrectWordBreakPosition","getCorrectPosition","getSearchRange","searchEnd","offsetToCheck","removeRangeContent","parentsToCheck","itemRange","parentToCheck","removeRange","injectSelectionPostFixer","registerPostFixer","correctedRange","tryFixingRange","nonIntersectingRanges","previousRange","merged","mergeIntersectingRanges","selectionPostFixer","originalPosition","nearestSelectionRange","fixedPosition","tryFixingCollapsedRange","isTextAllowedOnStart","isTextAllowedOnEnd","startLimitElement","endLimitElement","startIsOnBlock","endIsOnBlock","checkSelectionOnNonLimitElements","fixedStart","fixedEnd","isStartInLimit","isEndInLimit","bothInSameParent","expandStart","isInObject","expandEnd","findOutermostLimitAncestor","tryFixingNonCollapsedRage","startingNode","isLimitNode","_pendingChanges","_validate","register","addChildCheck","childDefinition","_runPendingChanges","batchOrType","_execute","insertion","nodesToInsert","getSelectionRange","affectedRange","getAffectedRange","insertContent","setSelectionFocus","modifySelection","frag","commonPath","commonParent","getNodeByPath","flatSubtreeRange","appendText","leftExcessRange","getSelectedContent","rangeOrElement","intersectingMarker","ret","currentBatch","callbackReturnValue","_handleChangeBlock","_listener","keyEvtData","evtData","_addEditor","_getEditorConfig","once","state","editing","conversion","addAlias","keystrokes","extraPlugins","readyPromise","_removeEditor","el","HTMLTextAreaElement","innerHTML","BasicHtmlWriter","fragment","implementation","createHTMLDocument","_domParser","DOMParser","_domConverter","_htmlWriter","getHtml","_toDom","parseFromString","_components","originalName","_elements","_nextEventLoopTimeout","_focus","_blur","focusedElement","componentFactory","focusTracker","_editableElementsMap","ckeditorInstance","editorUI","documentPlaceholders","enablePlaceholder","isDirectHost","updateDocumentPlaceholders","hidePlaceholder","placeholders","wasViewModified","updatePlaceholder","hostElement","getChildPlaceholderHostSubstitute","isEmptyish","selectionAnchor","needsPlaceholder","showPlaceholder","ElementReplacer","_replacedElements","display","_toolbarConfig","_elementReplacer","replacementElement","editingView","editingRoot","setEditableElement","attachDomRoot","_initPlaceholder","_initToolbar","restore","detachDomRoot","stickyPanel","limiterElement","viewportTopOffset","toolbar","fillFromConfig","origin","originKeystrokeHandler","originFocusTracker","beforeFocus","afterBlur","enableToolbarKeyboardFocus","placeholderText","isRendered","_parentElement","elementOrDocFragment","dest","evtName","_isRendered","_revertData","_renderNode","intoFragment","isApplying","revertData","_revertTemplateFromNode","isView","isTemplate","eventNameOrFunctionOrAttribute","TemplateToBinding","eventNameOrFunction","if","valueIfTrue","TemplateIfBinding","template","extendTemplate","extendObjectValueArray","eventListeners","childIndex","isInvalid","_renderText","_renderElement","_renderAttributes","_renderElementChildren","_setUpListeners","hasTemplateBinding","_bindToObservable","getTextUpdater","attrName","attrValue","domAttrValue","attrNs","valueToBind","shouldExtend","getAttributeUpdater","_renderStyleAttribute","arrayValueReducer","isFalsy","setAttributeNS","styleName","styleValue","getStyleUpdater","isViewCollection","setParent","childRevertData","revertBindings","schemaItem","domEvtName","domSelector","activateDomEventListener","syncValueSchemaValue","templateBinding","activateAttributeListener","revertBinding","TemplateBinding","matches","getValue","getValueSchemaValue","removeAttributeNS","normalizePlainTextDefinition","normalizeTextDefinition","listeners","arrayify","normalizeListeners","normalizeAttributes","cur","ext","_viewCollections","_unboundChildren","createCollection","collection","_bindTemplate","registerChild","getViews","_bodyCollectionContainer","class","namespace","xmlns","childElementCount","attachToDom","detachFromDom","bindTemplate","setTemplate","_voiceLabelView","_createVoiceLabel","role","lang","voiceLabel","_editableElement","_hasExternalElement","_editingView","_updateIsFocusedClasses","updateAfterRender","toUnit","toPx","_contentPanelPlaceholder","isSticky","_panelRect","_contentPanel","_hasViewportTopOffset","_isStickyToTheLimiter","limiterBottomOffset","marginLeft","_checkIfShouldBeSticky","panelRect","limiterRect","_limiterRect","isActive","_marginLeft","FocusCycler","keystrokeHandler","focusables","isFocusable","_getFocusableItem","viewIndex","focused","previous","collectionLength","_observerInstance","_createObserver","_element","_callback","_addElementCallback","_deleteElementCallback","_elementCallbacks","_getElementCallbacks","unobserve","ObserverConstructor","ResizeObserver","_previousRects","_periodicCheckTimeout","_checkElementRectsAndExecuteCallback","_startPeriodicCheck","_stopPeriodicCheck","periodicCheck","_hasRectChanged","contentRect","currentRect","previousRect","selectstart","focusLast","getOptimalPosition","positions","limiter","fitInViewport","positionedElementAncestor","getPositionedAncestor","elementRect","bestPosition","getVisible","bestPositionRect","bestPositionName","maxLimiterIntersectArea","maxViewportIntersectArea","elementRectArea","positionName","positionRect","getPosition","limiterIntersectArea","viewportIntersectArea","limiterViewportIntersectRect","getIntersectionArea","setBestPosition","getBestPosition","getAbsoluteRectCoordinates","ancestorPosition","ancestorBorderWidths","moveTo","buttonView","panelView","isOpen","panelPosition","_getOptimalPosition","_panelPositions","closeDropdown","southEast","southWest","northEast","northWest","defaultPanelPositions","buttonRect","viewBox","_updateXMLContent","_colorFillPaths","svg","fillColor","querySelectorAll","ariaLabelUid","tooltipView","_createTooltipView","labelView","_createLabelView","iconView","keystrokeView","_createKeystrokeView","_getTooltipString","tabindex","isToggleable","mousedown","click","icon","withKeystroke","tooltip","arrowView","_createArrowView","_focusCycler","focusPrevious","focusNext","focusFirst","toggleSwitchView","_createToggleView","clickOutsideHandler","activator","contextElements","contextElement","createDropdown","ButtonClass","dropdownView","closeDropdownOnBlur","closeDropdownOnExecute","focusDropdownContentsOnArrows","addDefaultBehavior","addToolbarToDropdown","buttons","toolbarView","addListToDropdown","listView","listItemView","itemsView","_behavior","shouldGroupWhenFull","StaticLayout","viewFocusables","viewItemsView","viewFocusTracker","viewLocale","ungroupedItems","groupedItems","groupedItemsDropdown","_createGroupedItemsDropdown","resizeObserver","cachedPadding","_updateFocusCycleableItems","_updateGrouping","_enableGroupingOnResize","wereItemsGrouped","_areItemsOverflowing","_groupLastItem","_ungroupFirstItem","lastChildRect","toolbarRect","computedStyle","paddingProperty","previousWidth","dropdown","shouldToolbarGroupWhenFull","sourceElementOrData","updateSourceElement","form","originalSubmit","onSubmit","submit","attachToForm","getInitialData","_disableStack","forceDisable","DataTransfer","nativeDataTransfer","files","kind","getAsFile","getFiles","_native","getData","setData","viewDocument","handleInput","targetRanges","dropRange","dataTransfer","clipboardData","domDoc","clientX","clientY","caretRangeFromPoint","rangeParent","rangeOffset","getDropViewRange","smallPaddingElements","modelDocument","onCopyCut","_htmlDataProcessor","fullMatch","spaces","scrollToTheSelection","dataController","modelFragment","viewToPlainText","childText","Command","forceDisabled","clearForceDisabled","getCopyOnEnterAttributes","allAttributes","copyOnEnter","isSelectionEmpty","attributesToCopy","splitBlock","setSelectionAttribute","isContainedWithinOneElement","enterBlock","splitPos","isSoft","insertBreak","softBreakAction","anchorPos","isInsideLimitElement","breakLineElement","createEmptyElement","ChangeBuffer","limit","isLocked","_changeCallback","_batch","_reset","_selectionChangeCallback","createBatch","ignoreLock","undoStepSize","_buffer","_batches","textInsertions","resultRange","isCollapsedRange","lock","unlock","injectUnsafeKeystrokesHandling","latestCompositionSelection","inputCommand","handleUnsafeKeystroke","isSelectionUnchanged","keyData","safeKeycodes","isSafeKeystroke","deleteSelectionContent","isFlatSelection","getSingleTextNodeChange","output","lastOperation","pushLast","isContinuationOf","expected","diffToChanges","compareChildNodes","oldChild","newChild","mutations","containerChildrenMutated","_handleContainerChildrenMutations","_handleTextMutation","_handleTextNodeInsertion","mutationsCommonAncestor","commonAncestor","getMutationsContainer","domMutationCommonAncestor","freshDomConverter","modelFromCurrentDom","currentModel","modelFromDomChildren","currentModelChildren","lastDomChild","lastCurrentChild","isSafeForTextMutation","diffResult","firstChangeAt","insertions","deletions","calculateChanges","modelSelectionRange","insertText","viewPos","modelPos","insertedText","lastChangeAt","handle","injectTypingMutationsHandling","_shouldEntireContentBeReplacedWithParagraph","sequence","_replaceEntireContentWithParagraph","limitElementFirstChild","fireViewDeleteEvent","originalEvent","hasWordModifier","inputType","selectionToRemove","deleteCommandParams","domSelectionAfterDeletion","transformations","setTransformation","OperationA","OperationB","transformationFunction","aGroup","noUpdateTransformation","getTransformation","transformSets","operationsA","operationsB","contextFactory","useRelations","forceWeakRemove","setOriginalOperations","originalOperations","nextTransformIndex","nextBaseVersionA","nextBaseVersionB","originalOperationsACount","originalOperationsBCount","opA","indexB","opB","newOpsA","getContext","newOpsB","updateRelation","newOpA","padWithNoOps","brokenOperationsACount","brokenOperationsBCount","updateBaseVersions","_history","_useRelations","_forceWeakRemove","_relations","takeFrom","originalOperation","_setRelation","affectedLeft","affectedRight","side","wasInLeftElement","wasStartBeforeMergedElement","wasEndBeforeMergedElement","wasInRightElement","aIsStrong","aWasUndone","_wasUndone","bWasUndone","abRelation","_getRelation","baRelation","originalOp","wasUndone","isUndoneOperation","origB","undoneB","getUndoneOperation","origA","relationsA","relation","_getComplementaryAttributeOperations","insertOperation","insertValue","_moveTargetIntoMovedRange","_makeMoveOperationsFromRanges","hasSameParentAs","moveOp","_breakRangeByMoveOperation","aNewRange","aToGraveyard","bToGraveyard","aIsWeak","removedRange","mergeInside","mergeSplittingElement","getReversed","aCompB","shouldSpread","rightRange","movesGraveyardElement","gyMoveSource","splitNodesMoveSource","gyMoveTarget","gyMove","splitNodesMoveTargetPath","splitNodesMoveTarget","splitNodesMove","extraRename","splitPath","additionalSplit","rangeToMove","gyElementMoved","newParentPosition","newTargetPath","howManyRemoved","aInGraveyard","bInGraveyard","newPositionPath","_stack","_createdBatches","docSelection","selectionRanges","transformSelectionRange","batchToUndo","undoingBatch","operationsToUndo","operationToUndo","nextBaseVersion","historyOperations","getOperations","reversedOperations","setOperationAsUndone","getTransformedByOperations","batchIndex","findIndex","_undo","_restoreSelection","redoingBatch","_batchRegistry","_undoCommand","_redoCommand","isRedoBatch","isUndoBatch","addBatch","clearStack","undoneBatch","localizedUndoIcon","undo","redo","localizedRedoIcon","_addButton","Icon","ContextPlugin","_actions","hasAny","FileReader","reader","_reader","onprogress","file","total","onload","onerror","onabort","readAsDataURL","abort","loaders","_updatePendingAction","_loadersMap","_pendingAction","uploaded","fileOrPromise","createUploadAdapter","loader","aggregatedUploaded","aggregatedTotal","uploadTotal","fileOrPromiseOrLoader","getLoader","_destroy","pendingActions","getMessage","uploadedPercent","filePromise","uploadAdapterCreator","_filePromiseWrapper","_createFilePromiseWrapper","_adapter","status","read","upload","uploadResponse","isFulfilled","rejecter","getCsrfToken","token","cookie","pair","decodeURIComponent","getCookie","randValues","crypto","getRandomValues","toUpperCase","generateToken","url","_initRequest","_initListeners","_sendRequest","xhr","XMLHttpRequest","open","responseType","genericError","response","lengthComputable","FormData","send","callbackOrCommand","blockToFormat","testRegexpOrCallback","attributeOrCallback","regExp","testCallback","formatCallback","format","leftDel","rightDel","delStart","delEnd","rangesToFormat","validRanges","getValidRanges","rangeText","getLastTextLine","testOutput","testOutputToRanges","rangesToRemove","arrays","getCallbackFunctionForInlineAutoformat","_getValueFromFirstAllowedNode","checkAttributeInSelection","forceValue","setAttributeProperties","isFormatting","fontWeight","iteratorItem","_getValue","_checkEnabled","blocks","blocksToQuote","findQuote","checkCanBeQuoted","_applyQuote","_removeQuote","firstBlock","getRangesOfBlockGroups","groupRange","positionBefore","positionAfter","quotesToMerge","currentQuote","nextQuote","elementOrPosition","nextBlock","isBQAllowed","isBlockAllowedInBQ","button","_fireEvents","modelToViewAttributeConverter","img","HighlightStack","oldTop","_insertDescriptor","newTop","compareDescriptors","oldDescriptor","newDescriptor","_removeDescriptor","shouldABeBeforeB","classesToString","isWidget","toWidget","setCustomProperty","labelOrCreator","setLabel","hasSelectionHandle","widgetElement","selectionHandle","addSelectionHandle","setHighlightHandling","normalizeToArray","getLabel","labelCreator","toWidgetEditable","findOptimalInsertionPosition","selectedElement","getSelectedImageWidget","isImageWidget","isImage","insertImage","imageElement","insertAtSelection","isImageAllowed","getInsertImageParent","isImageAllowedInParent","checkSelectionOnObject","isInOtherImage","src","createImageViewElement","toImageWidget","altText","srcset","srcsetAttributeConverter","viewImage","conversionResult","modelImage","viewFigureToModel","emptyElement","figure","findLinkRange","_findBound","lookBack","lastNode","manualDecorators","manualDecorator","_getDecoratorStateFromModel","href","manualDecoratorIds","truthyManualDecorators","falsyManualDecorators","linkRange","decoratorName","linkCommand","rangesToUnlink","reHasUnicode","rsAstral","rsCombo","rsFitz","rsNonAstral","rsRegional","rsSurrPair","reOptMod","rsSeq","rsSymbol","reUnicode","strSymbols","chr","ATTRIBUTE_WHITESPACES","SAFE_URL","createLinkElement","linkElement","ensureSafeUrl","isSafeUrl","AutomaticDecorators","_definitions","ManualDecorator","TwoStepCaretHandler","_modelSelection","_overrideUid","_isNextGravityRestorationSkipped","_isGravityOverridden","isAtBoundary","_hasSelectionAttribute","isBetweenDifferentValues","_preventCaretMovement","isAtStartBoundary","isAtEndBoundary","_setSelectionAttributeFromTheNodeBefore","isStepAfterTheAttributeBoundary","_skipNextAutomaticGravityRestoration","overrideSelectionGravity","restoreSelectionGravity","isAttrBefore","isAttrAfter","EXTERNAL_LINKS_REGEXP","addTargetToExternalLinks","linkDecorators","decorators","localizedDecoratorsLabels","decorator","getLocalizedDecorators","retArray","normalizeDecorators","_enableAutomaticDecorators","_enableManualDecorators","twoStepCaretHandler","arrowRightPressed","arrowLeftPressed","contentDirection","isMovementHandled","handleForwardMovement","handleBackwardMovement","bindTwoStepCaretToAttribute","_setupLinkHighlight","automaticDecoratorDefinitions","automaticDecorators","rel","getDispatcher","manualDecoratorDefinitions","manualDecoratorName","highlightedLinks","alert","_showNotification","title","imageCommand","openerMethod","chooseFiles","originalOnInit","onInit","finder","toArray","links","images","linkFile","getUrl","imagesUrls","image","request","insertImages","resizedUrl","notification","showWarning","CKFinder","urls","BASE64_HEADER_REG_EXP","fileOrData","apiAddress","_isBase64","base64","sliceSize","contentType","base64Data","byteArrays","byteNumbers","Blob","_base64ToBlob","_token","_apiAddress","_prepareRequest","_attachXHRListeners","setRequestHeader","onError","statusCode","xhrResponse","formData","DEFAULT_OPTIONS","refreshInterval","autoRefresh","tokenUrlOrRefreshToken","initValue","defaultRefreshToken","tokenUrl","_options","_startRefreshing","_refreshToken","_stopRefreshing","_refreshInterval","optionName","Token","cloudServices","uploadUrl","_uploadGateway","_UploadGateway","Adapter","uploadGateway","fileUploader","selectAllKeystrokeCode","_previouslySelected","_clearPreviouslySelectedWidgets","lastMarked","isChild","_onMousedown","_onKeydown","_handleDelete","domEventData","isInsideNestedEditable","detail","_setSelectionOverElement","isLtrContent","wasHandled","isArrowKeyCode","isSelectAllKeyCode","_handleEnterKey","_selectAllNestedEditableContent","_selectAllContent","_handleArrowKeys","objectElement","_getObjectElementNextToSelection","previousNode","nodeToRemove","objectElement2","isBackwards","paragraphLimit","documentSelection","widgetParent","probe","widget","InputView","inputUid","statusUid","inputView","_createInputView","statusView","_createStatusView","errorText","infoText","ariaDescribedById","select","placeholder","readonly","setValue","submitHandler","labeledInput","_createLabeledInputView","saveButtonView","_createButton","check","cancelButtonView","_focusables","v","defaultLimiterElement","isVisible","show","defaultPositions","positionOptions","southArrowNorth","southArrowNorthWest","southArrowNorthEast","northArrowSouth","northArrowSouthWest","northArrowSouthEast","optimalPosition","unpin","_pinWhenIsVisibleCallback","_startPinning","_stopPinning","hide","attachTo","getDomElement","scrollTarget","isWithinScrollTarget","isLimiterWithinScrollTarget","getNorthTop","balloonRect","arrowVerticalOffset","getSouthTop","arrowHorizontalOffset","northWestArrowSouth","northWestArrowSouthWest","northWestArrowSouthEast","northEastArrowSouth","northEastArrowSouthEast","northEastArrowSouthWest","southWestArrowNorth","southWestArrowNorthWest","southWestArrowNorthEast","southEastArrowNorth","southEastArrowNorthEast","southEastArrowNorthWest","positionLimiter","_viewToStack","_idToStack","_rotatorView","_createRotatorView","_fakePanelsView","_createFakePanelsView","hasView","stackId","_numberOfStacks","_visibleStack","singleViewMode","showStack","_showView","_singleViewMode","visibleView","_showNextStack","hideView","_getStackId","pin","_getBalloonPosition","updatePosition","visibleStack","stacks","nextIndex","isSingleViewMode","numberOfStacks","buttonNextView","buttonPrevView","_showPrevStack","balloonClassName","withArrow","showView","_createButtonView","balloonPanelView","_balloonPanelView","_addPanels","_removePanels","deregisterChild","numberOfPanels","getBalloonPositionData","_createForm","_form","_showForm","_balloon","_hideForm","_isVisible","balloon","repositionContextualBalloon","_isInBalloon","focusEditable","_fileInputView","accept","multiple","createImageTypeRegExp","regExpSafeNames","fetchLocalImage","imageSrc","fetch","resource","blob","mimeType","getImageMimeType","filename","File","createFileFromBlob","imageTypes","imageTypesRegExp","acceptedType","allowMultipleFiles","imagesToUpload","uploadStatusChange","uploadId","fileRepository","viewFigure","_startAppearEffect","_showPlaceholder","_hidePlaceholder","progressBar","_createProgressBar","_showProgressBar","viewImg","_displayLocalImage","completeIcon","_showCompleteIcon","_removeUIElement","_hideProgressBar","_stopAppearEffect","_getUIElement","_createPlaceholder","imageFigure","uniqueProperty","removeChildren","oldElement","insertChild","filesToUpload","uploadImage","createLoader","fetchableImages","isLocalImage","fetchableImage","isInGraveyard","getImagesFromChangeItem","_readAndUpload","domFigure","originalDisplay","_ckHack","setAttributes","uploadStatus","_parseAndSetSrcsetAttributeOnImage","clean","destroyLoader","maxWidth","srcsetAttribute","isNaN","checkCanBecomeParagraph","rename","paragraphLikeElements","isParagraphable","wrapInParagraph","_autoparagraphEmptyRoots","insertElement","createContext","modelElements","heading","checkCanBecomeHeading","option","_addDefaultH1Conversion","enterCommand","localizedTitles","Paragraph","getLocalizedOptions","defaultTitle","dropdownTooltip","titles","itemDefinitions","headingCommand","paragraphCommand","withText","commandValue","isOn","areEnabled","para","whichModel","getCaptionFromImage","imageModelElement","matchImageCaption","_insertMissingModelCaptionElement","captionModelToView","createCaptionForEditing","createEditableElement","captionElementCreator","_fixCaptionVisibility","_updateCaptionVisibility","lastCaption","_lastSelectedCaption","viewCaption","modelCaption","getParentCaption","hideCaptionIfEmpty","showCaption","viewModified","nodeFinder","imagesWithoutCaption","nestedItem","appendElement","captionElement","insertViewCaptionAndBind","caption","defaultStyle","isDefault","attributeValue","getStyleByName","defaultStyles","full","alignLeft","alignCenter","alignRight","defaultIcons","center","normalizeImageStyles","configuredStyles","_normalizeStyle","extendedStyle","modelToViewConverter","newStyle","oldStyle","modelToViewStyleAttribute","filteredStyles","viewFigureElement","modelImageElement","viewToModelStyleAttribute","translatedStyles","translateStyles","localizedDefaultStylesTitles","componentName","balloonToolbar","isWidgetSelected","_toolbarDefinitions","_updateToolbarsVisibility","toolbarConfig","toolbarId","ariaLabel","getRelatedElement","maxRelatedElementDepth","deepestRelatedElement","deepestToolbarDefinition","relatedElement","relatedElementDepth","_isToolbarVisible","_hideToolbar","_isToolbarInBalloon","_showToolbar","toolbarDefinition","_childCommands","_getFirstEnabledCommand","localizedIndentIcon","indent","outdent","localizedOutdentIcon","_defineButton","urlInputView","_createUrlInput","_manualDecoratorSwitches","_createManualDecoratorSwitches","_createFormChildren","classList","accumulator","switchButton","switches","additionalButtonsView","previewButtonView","_createPreviewButton","unlinkButtonView","editButtonView","actionsView","_createActionsView","formView","_createFormView","_createToolbarLinkButton","_enableUserBalloonInteractions","unlinkCommand","_addFormView","_hideUI","getDecoratorSwitchesState","_closeFormView","_showUI","_getSelectedLinkElement","_areActionsVisible","_isUIVisible","_isUIInPanel","_areActionsInPanel","_getBalloonPositionData","_isFormInPanel","restoreManualDecoratorStates","_removeFormView","forceVisible","_addActionsView","_startUpdatingUI","prevSelectedLink","prevSelectionParent","getSelectionParent","selectedLink","targetLink","findLinkElementAncestor","startLink","endLink","isLinkElement","checkCanBecomeListItem","turnOff","currentIndent","newIndent","listIndent","lowestIndent","_fixType","listType","listItem","startingItem","indentDirection","_indentBy","itemsToChange","lastItem","generateLiInUl","getListItemFillerOffset","createViewListItemElement","viewList","injectViewList","injectedItem","injectedList","refItem","getSiblingListItem","sameIndent","smallerIndent","prevItem","breakContainer","positionAfterUiElements","prevView","breakPosition","mergeViewLists","nextViewList","lastSubChild","modelChild","firstList","secondList","mergeContainers","itemIndent","createUIComponent","hasOnlyLists","modelViewInsertion","modelViewChangeType","listName","modelViewMergeAfterChangeType","modelViewSplitOnInsert","removeStart","removeEnd","previousList","mergePos","modelViewMergeAfter","viewItemPrev","viewItemNext","viewModelConverter","getIndent","listItemModel","convertedChild","findNextListItem","viewToModelListItemChildrenConverter","cleanList","isList","cleanListItem","foundList","firstNode","modelToViewPosition","topmostViewList","modelIndentPasteFixer","indentChange","hoistNestedLists","nextIndent","modelRemoveStartPosition","viewRemoveStartPosition","viewRemovedItem","prevModelItem","foo","prevIndent","prevViewList","itemToListHead","applied","_addListToFix","innerItem","listHead","_fixListIndents","_fixListTypes","maxIndent","fixBy","typesStack","modelChangePostFixer","registerViewToModelLength","getViewListItemLength","modelNode","modelLength","viewListPrev","modelViewChangeIndent","modelViewRemove","firstPosition","getCommandExecuter","registerChildCommand","modelToViewUrlAttributeConverter","registry","mediaViewElement","getMediaViewElement","createMediaFigureElement","getSelectedMediaModelWidget","insertMedia","mediaElement","selectedMedia","providers","extraProviders","removedProviders","removeProviders","providerDefinitions","provider","_getMedia","getViewElement","previewRenderer","html","subPattern","_getUrlMatches","rawUrl","_getValidUrl","_match","_previewRenderer","renderForEditingView","renderMediaPreview","mediaHtml","_getPreviewHtml","_getPlaceholderHtml","outerHTML","viewMedia","hasMedia","URL_REGEXP","_timeoutId","_positionToInsert","leftLivePosition","rightLivePosition","_embedMediaBetweenPositions","leftPosition","rightPosition","mediaRegistry","urlRange","validators","_validators","resetFormStatus","validator","_urlInputViewInfoDefault","_urlInputViewInfoTip","getFormValidators","_setUpDropdown","_setUpForm","closeUI","isValid","transformListItemLikeElementsIntoLists","itemLikeElements","itemLikeElementsMatcher","itemData","getListItemData","order","findAllItemLikeElements","currentList","itemLikeElement","previousItem","currentItem","isNewListNeeded","listStyle","listLikeItem","listStyleRegexp","listStyleTypeRegex","listStyleMatch","listStyleType","listStyleTypeMatch","detectListStyle","insertNewEmptyList","bulletMatcher","removeBulletElement","transformElementIntoListItem","idMatch","orderMatch","indentMatch","googleDocsMatch","htmlString","removeBoldWrapper","unwrapParagraphInListItem","normalizeSafariSpaceSpans","parseHtml","domParser","normalizedHtml","normalizeSpacing","cleanContentAfterBody","htmlDocument","innerTextLength","normalizeSpacerunSpans","bodyString","bodyView","documentToView","styleTags","getElementsByTagName","sheet","cssRules","extractStyles","replaceImagesSourceWithBase64","rtfData","upcastWriter","shapesIds","imageElementsMatcher","imgs","shapes","shape","removeAllImgElementsRepresentingShapes","shapeElementsMatcher","prevSiblingName","findAllShapesIds","removeAllShapeElements","findAllImageElementsWithLocalSource","imageElements","imagesHexSources","newSrc","hexString","hex","replaceImagesFileSourceWithInlineRepresentation","regexPictureHeader","regexPicture","imageType","extractImageDataFromRtf","msWordMatch1","msWordMatch2","parentName","updateNumericAttribute","createEmptyTableCell","tableCell","upcastTable","viewTable","rows","headingRows","headingColumns","tableMeta","headRows","bodyRows","firstTheadElement","tableChild","trs","tr","headingCols","scanRowForHeadingColumns","scanTable","table","row","upcastTableCell","viewTableCell","th","TableWalker","startRow","endRow","includeSpanned","column","_skipRows","_row","_column","_cellIndex","_spannedCells","_nextCellAtColumn","_isOverEndRow","cell","skipCurrentValue","outValue","_isSpanned","_getSpanned","_shouldSkipRow","_shouldSkipColumn","_formatOutValue","colspan","rowspan","_recordSpans","isSpanned","cellIndex","rowIsBelowStartRow","rowIsMarkedAsSkipped","columnToUpdate","_markSpannedCell","rowToUpdate","isTableWidget","getSelectedTableWidget","getTableWidgetAncestor","parentTable","downcastInsertTable","asWidget","figureElement","tableElement","tableWidget","tableWalker","tableAttributes","viewRows","tableWalkerValue","tableSection","getOrCreateTableSection","getSectionName","tableRow","trElement","createTr","createViewTableCellElement","downcastInsertRow","getViewTable","downcastInsertCell","rowIndex","downcastTableHeadingRowsChange","oldRows","newRows","rowsToMove","isBetween","moveViewRowsToTableSection","renameViewTableCell","removeTableSectionIfEmpty","renameViewTableCellIfRequired","lower","upper","downcastTableHeadingColumnsChange","oldColumns","newColumns","lastColumnToCheck","desiredCellElementName","viewCell","renamedCell","getCellElementName","cellElementName","cellElement","isSingleParagraph","innerParagraph","paragraphInsertPosition","fakeParagraph","sectionName","viewTableSection","getExistingTableSectionElement","tableChildElement","createTableSection","viewTableRow","validParent","getInsertTableParent","tableUtils","columns","createTable","tableParent","insertAt","insertRows","at","getCellLocation","insertColumns","isHorizontally","splitCellHorizontally","splitCellVertically","isHorizontal","cellToMerge","_getMergeableCell","isMergeNext","cellToExpand","cellToRemove","removedTableCellRow","mergeTableCells","spanAttribute","cellSpan","cellToMergeSpan","removedRowIndex","removeEmptyRow","horizontalCell","cellOnLeft","cellOnRight","leftCellColumn","rightCellColumn","leftCellSpan","rightCellSpan","isMergeWithBodyCell","isMergeWithHeadCell","getHorizontalCell","currentCellRowSpan","rowOfCellToMerge","tableMap","mergeColumn","cellToMergeData","getVerticalCell","span","currentRow","cellsToMove","rowspanToSet","targetRow","previousCell","cellToMove","getColumns","removedColumn","isInTable","_isInHeading","currentHeadingRows","selectionRow","headingRowsToSet","cellsToSplit","getOverlappingCells","splitHorizontally","newRowspan","spanToSet","columnIndex","tableCellPosition","selectionColumn","headingColumnsToSet","createEmptyRows","rowsToInsert","tableIterator","cellsToInsert","overlapsInsertedRow","columnsToInsert","tableColumns","createCells","skipRow","numberOfCells","newCellsSpan","updatedSpan","breakSpanEvenly","newCellsAttributes","splitCellColumn","cellsToUpdate","splitCellRow","cellColumn","isOnSameColumn","isInEvenlySplitRow","tableCellToInsert","cells","floor","injectTableLayoutPostFixer","analyzedTables","isTableAttributeEntry","fixTableCellsRowspan","fixTableRowsSizes","tableLayoutPostFixer","cellsToTrim","maxRows","rowLimit","findCellsToTrim","rowsLengths","lengths","getRowsLengths","tableSize","maxColumns","isAttributeType","injectTableCellParagraphPostFixer","fixTable","fixTableRow","fixTableCellContent","checkTableCellChange","tableCellContentsPostFixer","textNodes","injectTableCellRefreshPostFixer","cellsToRefresh","checkRefresh","refreshItem","tableCellRefreshPostFixer","attributesCount","_handleTabOnSelectedTable","_getTabHandler","currentRowIndex","currentCellIndex","isFirstCellInRow","isLastCellInRow","isLastRow","cellToFocus","nextRow","previousRow","boxView","_highlightGridBoxes","mouseover","isContentLtr","insertTableView","bindIsOn","_prepareDropdown","addListOption","_getFormattingItems","_getFormattingAttributes","itemHasRemovableFormatting","curRange","attributeProperties","getInsertHorizontalLineParent","isHorizontalLineAllowedInParent","isHorizontalLineAllowed","horizontalElement","nextElement","viewWrapper","viewHrElement","toHorizontalLineWidget","supportedOptions","alignment","_canBeAligned","currentAlignment","removeAlignmentFromSelection","setAlignmentOnSelection","enabledOptions","_buildDefinition","icons","isVertical","defaultIcon","areActive","localizedOptionTitles","_referenceCoordinates","domResizeHandle","domHandleHost","domResizeHost","clientRect","activeHandlePosition","domHandle","resizerPositions","getHandlePosition","resizerPosition","positionParts","getAbsoluteBoundaryPoint","replacements","getOppositePosition","originalWidth","originalHeight","aspectRatio","widthStyle","originalWidthPercents","parseFloat","resizeHostRect","domResizeHostParent","parentWidth","calculateHostPercentageWidth","newSize","proposedWidth","proposedHeight","proposedWidthPercents","widthPercents","proposedHandleHostWidth","handleHostWidth","proposedHandleHostHeight","handleHostHeight","_domResizerWrapper","_viewResizerWrapper","_cleanup","viewResizerWrapper","_appendHandles","_appendSizeUI","propName","_sizeUI","bindToState","begin","_getHandleHost","_getResizeHost","_proposeNewSize","newWidth","domHandleHostRect","round","domResizeHostRect","redraw","onCommit","handleHostRect","domWrapper","widgetWrapper","handleHost","offsets","offsetLeft","offsetTop","isSameNode","dismiss","currentCoordinates","pageX","pageY","isCentered","enlargement","proposedSize","abs","dominant","targetSize","getResizeHost","getHandleHost","getResizerClass","sizeUI","visible","resizerState","unbind","_resizers","_observer","isResizeHandle","resizeHandle","_activeResizer","_getResizerByHandle","updateSize","commit","redrawFocusedResizer","_visibleResizer","redrawFocusedResizerThrottled","_getResizerByViewElement","resizer","widgetToolbarRepository","containsHandle","backgroundColor","colorDefinitions","viewStyleAttribute","gridTemplateColumns","colorTile","color","selectedColor","hasBorder","colors","removeButtonLabel","documentColorsLabel","documentColorsCount","documentColors","_documentColorsLabel","_removeColorButton","maxCount","_addColorToDocumentColors","documentColorsGrid","staticColorsGrid","_createStaticColorsGrid","_createDocumentColorsGrid","colorGrid","colorObj","predefinedColor","buildDefinition","modelAttributeKey","renderUpcastAttribute","styleAttr","renderDowncastElement","normalizeOptions","configuredOptions","getOptionDefinition","fontDefinition","fontNames","firstFontName","cssFontNames","normalizeFontNameForCSS","generateFontPreset","fontName","_getLocalizedOptions","commandParam","_prepareListOptions","namedPresets","tiny","small","big","huge","sizePreset","Default","Tiny","Small","Big","Huge","normalizeSingleColorDefinition","dropdownLabel","colorTableView","localizedColors","localizedColorNames","Black","Grey","White","Red","Orange","Yellow","Green","Aquamarine","Turquoise","Blue","Purple","colorOption","getLocalizedColorOptions","addColorTableToDropdown","appendGrids","updateDocumentColors","updateSelectedColors","_addListAutoformats","_addBasicStylesAutoformats","_addHeadingAutoformats","_addBlockQuoteAutoformats","_addCodeBlockAutoformats","boldCallback","italicCallback","codeCallback","level","normalizers","isTransformedWithPasteFromOffice","activeNormalizer","tableContentToolbarItems","tableToolbarItems","_registerSchema","_registerConverters","domWidgetElement","imageStyle","contentToolbar"],"mappings":"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","file":"ckeditor.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClassicEditor\"] = factory();\n\telse\n\t\troot[\"ClassicEditor\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 104);\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/ckeditorerror\n */\n\n/**\n * URL to the documentation with error codes.\n */\nexport const DOCUMENTATION_URL =\n\t'https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/error-codes.html';\n\n/**\n * The CKEditor error class.\n *\n * You should throw `CKEditorError` when:\n *\n * * An unexpected situation occurred and the editor (most probably) will not work properly. Such exception will be handled\n * by the {@link module:watchdog/watchdog~Watchdog watchdog} (if it is integrated),\n * * If the editor is incorrectly integrated or the editor API is used in the wrong way. This way you will give\n * feedback to the developer as soon as possible. Keep in mind that for common integration issues which should not\n * stop editor initialization (like missing upload adapter, wrong name of a toolbar component) we use `console.warn()` with\n * {@link module:utils/ckeditorerror~attachLinkToDocumentation `attachLinkToDocumentation()`}\n * to improve developers experience and let them see the working editor as soon as possible.\n *\n *\t\t/**\n *\t\t * Error thrown when a plugin cannot be loaded due to JavaScript errors, lack of plugins with a given name, etc.\n *\t\t *\n *\t\t * @error plugin-load\n *\t\t * @param pluginName The name of the plugin that could not be loaded.\n *\t\t * @param moduleName The name of the module which tried to load this plugin.\n *\t\t * /\n *\t\tthrow new CKEditorError( 'plugin-load: It was not possible to load the \"{$pluginName}\" plugin in module \"{$moduleName}', {\n *\t\t\tpluginName: 'foo',\n *\t\t\tmoduleName: 'bar'\n *\t\t} );\n *\n * @extends Error\n */\nexport default class CKEditorError extends Error {\n\t/**\n\t * Creates an instance of the CKEditorError class.\n\t *\n\t * @param {String} message The error message in an `error-name: Error message.` format.\n\t * During the minification process the \"Error message\" part will be removed to limit the code size\n\t * and a link to this error documentation will be added to the `message`.\n\t * @param {Object|null} context A context of the error by which the {@link module:watchdog/watchdog~Watchdog watchdog}\n\t * is able to determine which editor crashed. It should be an editor instance or a property connected to it. It can be also\n\t * a `null` value if the editor should not be restarted in case of the error (e.g. during the editor initialization).\n\t * The error context should be checked using the `areConnectedThroughProperties( editor, context )` utility\n\t * to check if the object works as the context.\n\t * @param {Object} [data] Additional data describing the error. A stringified version of this object\n\t * will be appended to the error message, so the data are quickly visible in the console. The original\n\t * data object will also be later available under the {@link #data} property.\n\t */\n\tconstructor( message, context, data ) {\n\t\tmessage = attachLinkToDocumentation( message );\n\n\t\tif ( data ) {\n\t\t\tmessage += ' ' + JSON.stringify( data );\n\t\t}\n\n\t\tsuper( message );\n\n\t\t/**\n\t\t * @type {String}\n\t\t */\n\t\tthis.name = 'CKEditorError';\n\n\t\t/**\n\t\t * A context of the error by which the Watchdog is able to determine which editor crashed.\n\t\t *\n\t\t * @type {Object|null}\n\t\t */\n\t\tthis.context = context;\n\n\t\t/**\n\t\t * The additional error data passed to the constructor. Undefined if none was passed.\n\t\t *\n\t\t * @type {Object|undefined}\n\t\t */\n\t\tthis.data = data;\n\t}\n\n\t/**\n\t * Checks if the error is of the `CKEditorError` type.\n\t */\n\tis( type ) {\n\t\treturn type === 'CKEditorError';\n\t}\n\n\t/**\n\t * A utility that ensures the the thrown error is a {@link module:utils/ckeditorerror~CKEditorError} one.\n\t * It is useful when combined with the {@link module:watchdog/watchdog~Watchdog} feature, which can restart the editor in case\n\t * of a {@link module:utils/ckeditorerror~CKEditorError} error.\n\t *\n\t * @param {Error} err An error.\n\t * @param {Object} context An object connected through properties with the editor instance. This context will be used\n\t * by the watchdog to verify which editor should be restarted.\n\t */\n\tstatic rethrowUnexpectedError( err, context ) {\n\t\tif ( err.is && err.is( 'CKEditorError' ) ) {\n\t\t\tthrow err;\n\t\t}\n\n\t\t/**\n\t\t * An unexpected error occurred inside the CKEditor 5 codebase. This error will look like the original one\n\t\t * to make the debugging easier.\n\t\t *\n\t\t * This error is only useful when the editor is initialized using the {@link module:watchdog/watchdog~Watchdog} feature.\n\t\t * In case of such error (or any {@link module:utils/ckeditorerror~CKEditorError} error) the watchdog should restart the editor.\n\t\t *\n\t\t * @error unexpected-error\n\t\t */\n\t\tconst error = new CKEditorError( err.message, context );\n\n\t\t// Restore the original stack trace to make the error look like the original one.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/5595 for more details.\n\t\terror.stack = err.stack;\n\n\t\tthrow error;\n\t}\n}\n\n/**\n * Attaches the link to the documentation at the end of the error message. Use whenever you log a warning or error on the\n * console. It is also used by {@link module:utils/ckeditorerror~CKEditorError}.\n *\n *\t\t /**\n *\t\t * There was a problem processing the configuration of the toolbar. The item with the given\n *\t\t * name does not exist so it was omitted when rendering the toolbar.\n *\t\t *\n *\t\t * @error toolbarview-item-unavailable\n *\t\t * @param {String} name The name of the component.\n *\t\t * /\n *\t\t console.warn( attachLinkToDocumentation(\n *\t\t \t'toolbarview-item-unavailable: The requested toolbar item is unavailable.' ), { name } );\n *\n * @param {String} message Message to be logged.\n * @returns {String}\n */\nexport function attachLinkToDocumentation( message ) {\n\tconst matchedErrorName = message.match( /^([^:]+):/ );\n\n\tif ( !matchedErrorName ) {\n\t\treturn message;\n\t}\n\n\treturn message + ` Read more: ${ DOCUMENTATION_URL }#error-${ matchedErrorName[ 1 ] }\\n`;\n}\n","\"use strict\";\n\nvar isOldIE = function isOldIE() {\n var memo;\n return function memorize() {\n if (typeof memo === 'undefined') {\n // Test for IE <= 9 as proposed by Browserhacks\n // @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805\n // Tests for existence of standard globals is to allow style-loader\n // to operate correctly into non-standard environments\n // @see https://github.com/webpack-contrib/style-loader/issues/177\n memo = Boolean(window && document && document.all && !window.atob);\n }\n\n return memo;\n };\n}();\n\nvar getTarget = function getTarget() {\n var memo = {};\n return function memorize(target) {\n if (typeof memo[target] === 'undefined') {\n var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself\n\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n\n memo[target] = styleTarget;\n }\n\n return memo[target];\n };\n}();\n\nvar stylesInDom = [];\n\nfunction getIndexByIdentifier(identifier) {\n var result = -1;\n\n for (var i = 0; i < stylesInDom.length; i++) {\n if (stylesInDom[i].identifier === identifier) {\n result = i;\n break;\n }\n }\n\n return result;\n}\n\nfunction modulesToDom(list, options) {\n var idCountMap = {};\n var identifiers = [];\n\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var count = idCountMap[id] || 0;\n var identifier = \"\".concat(id, \" \").concat(count);\n idCountMap[id] = count + 1;\n var index = getIndexByIdentifier(identifier);\n var obj = {\n css: item[1],\n media: item[2],\n sourceMap: item[3]\n };\n\n if (index !== -1) {\n stylesInDom[index].references++;\n stylesInDom[index].updater(obj);\n } else {\n stylesInDom.push({\n identifier: identifier,\n updater: addStyle(obj, options),\n references: 1\n });\n }\n\n identifiers.push(identifier);\n }\n\n return identifiers;\n}\n\nfunction insertStyleElement(options) {\n var style = document.createElement('style');\n var attributes = options.attributes || {};\n\n if (typeof attributes.nonce === 'undefined') {\n var nonce = typeof __webpack_nonce__ !== 'undefined' ? __webpack_nonce__ : null;\n\n if (nonce) {\n attributes.nonce = nonce;\n }\n }\n\n Object.keys(attributes).forEach(function (key) {\n style.setAttribute(key, attributes[key]);\n });\n\n if (typeof options.insert === 'function') {\n options.insert(style);\n } else {\n var target = getTarget(options.insert || 'head');\n\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n\n target.appendChild(style);\n }\n\n return style;\n}\n\nfunction removeStyleElement(style) {\n // istanbul ignore if\n if (style.parentNode === null) {\n return false;\n }\n\n style.parentNode.removeChild(style);\n}\n/* istanbul ignore next */\n\n\nvar replaceText = function replaceText() {\n var textStore = [];\n return function replace(index, replacement) {\n textStore[index] = replacement;\n return textStore.filter(Boolean).join('\\n');\n };\n}();\n\nfunction applyToSingletonTag(style, index, remove, obj) {\n var css = remove ? '' : obj.media ? \"@media \".concat(obj.media, \" {\").concat(obj.css, \"}\") : obj.css; // For old IE\n\n /* istanbul ignore if */\n\n if (style.styleSheet) {\n style.styleSheet.cssText = replaceText(index, css);\n } else {\n var cssNode = document.createTextNode(css);\n var childNodes = style.childNodes;\n\n if (childNodes[index]) {\n style.removeChild(childNodes[index]);\n }\n\n if (childNodes.length) {\n style.insertBefore(cssNode, childNodes[index]);\n } else {\n style.appendChild(cssNode);\n }\n }\n}\n\nfunction applyToTag(style, options, obj) {\n var css = obj.css;\n var media = obj.media;\n var sourceMap = obj.sourceMap;\n\n if (media) {\n style.setAttribute('media', media);\n } else {\n style.removeAttribute('media');\n }\n\n if (sourceMap && btoa) {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n } // For old IE\n\n /* istanbul ignore if */\n\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n while (style.firstChild) {\n style.removeChild(style.firstChild);\n }\n\n style.appendChild(document.createTextNode(css));\n }\n}\n\nvar singleton = null;\nvar singletonCounter = 0;\n\nfunction addStyle(obj, options) {\n var style;\n var update;\n var remove;\n\n if (options.singleton) {\n var styleIndex = singletonCounter++;\n style = singleton || (singleton = insertStyleElement(options));\n update = applyToSingletonTag.bind(null, style, styleIndex, false);\n remove = applyToSingletonTag.bind(null, style, styleIndex, true);\n } else {\n style = insertStyleElement(options);\n update = applyToTag.bind(null, style, options);\n\n remove = function remove() {\n removeStyleElement(style);\n };\n }\n\n update(obj);\n return function updateStyle(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) {\n return;\n }\n\n update(obj = newObj);\n } else {\n remove();\n }\n };\n}\n\nmodule.exports = function (list, options) {\n options = options || {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of <style>\n // tags it will allow on a page\n\n if (!options.singleton && typeof options.singleton !== 'boolean') {\n options.singleton = isOldIE();\n }\n\n list = list || [];\n var lastIdentifiers = modulesToDom(list, options);\n return function update(newList) {\n newList = newList || [];\n\n if (Object.prototype.toString.call(newList) !== '[object Array]') {\n return;\n }\n\n for (var i = 0; i < lastIdentifiers.length; i++) {\n var identifier = lastIdentifiers[i];\n var index = getIndexByIdentifier(identifier);\n stylesInDom[index].references--;\n }\n\n var newLastIdentifiers = modulesToDom(newList, options);\n\n for (var _i = 0; _i < lastIdentifiers.length; _i++) {\n var _identifier = lastIdentifiers[_i];\n\n var _index = getIndexByIdentifier(_identifier);\n\n if (stylesInDom[_index].references === 0) {\n stylesInDom[_index].updater();\n\n stylesInDom.splice(_index, 1);\n }\n }\n\n lastIdentifiers = newLastIdentifiers;\n };\n};","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nexport default root;\n","import root from './_root.js';\nimport stubFalse from './stubFalse.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined;\n\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\nexport default isBuffer;\n","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Detect free variable `process` from Node.js. */\nvar freeProcess = moduleExports && freeGlobal.process;\n\n/** Used to access faster Node.js helpers. */\nvar nodeUtil = (function() {\n try {\n // Use `util.types` for Node.js 10+.\n var types = freeModule && freeModule.require && freeModule.require('util').types;\n\n if (types) {\n return types;\n }\n\n // Legacy `process.binding('util')` for Node.js < 10.\n return freeProcess && freeProcess.binding && freeProcess.binding('util');\n } catch (e) {}\n}());\n\nexport default nodeUtil;\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/version\n */\n\n/* globals window, global */\n\nimport CKEditorError from './ckeditorerror';\n\nconst version = '17.0.0';\n\n/* istanbul ignore next */\nconst windowOrGlobal = typeof window === 'object' ? window : global;\n\n/* istanbul ignore next */\nif ( windowOrGlobal.CKEDITOR_VERSION ) {\n\t/**\n\t * This error is thrown when due to a mistake in how CKEditor 5 was installed or initialized, some\n\t * of its modules were duplicated (evaluated and executed twice). Module duplication leads to inevitable runtime\n\t * errors.\n\t *\n\t * There are many situations in which some modules can be loaded twice. In the worst case scenario,\n\t * you may need to check your project for each of these issues and fix them all.\n\t *\n\t * # Trying to add a plugin to an existing build\n\t *\n\t * If you import an existing CKEditor 5 build and a plugin like this:\n\t *\n\t *\t\timport ClassicEditor from '@ckeditor/ckeditor5-build-classic';\n\t *\t\timport Highlight from '@ckeditor/ckeditor5-highlight/src/highlight';\n\t *\n\t * Then your project loads some CKEditor 5 packages twice. How does it happen?\n\t *\n\t * The build package contains a file which is already compiled with webpack. This means\n\t * that it contains all the necessary code from e.g. `@ckeditor/ckeditor5-engine` and `@ckeditor/ckeditor5-utils`.\n\t *\n\t * However, the `Highlight` plugin imports some of the modules from these packages, too. If you ask webpack to\n\t * build such a project, you will end up with the modules being included (and run) twice — first, because they are\n\t * included inside the build package, and second, because they are required by the `Highlight` plugin.\n\t *\n\t * Therefore, **you must never add plugins to an existing build** unless your plugin has no dependencies.\n\t *\n\t * Adding plugins to a build is done by taking the source version of this build (so, before it was built with webpack)\n\t * and adding plugins there. In this situation, webpack will know that it only needs to load each plugin once.\n\t *\n\t * Read more in the {@glink builds/guides/integration/installing-plugins \"Installing plugins\"} guide.\n\t *\n\t * # Confused an editor build with an editor implementation\n\t *\n\t * This scenario is very similar to the previous one, but has a different origin.\n\t *\n\t * Let's assume that you wanted to use CKEditor 5 from source, as explained in the\n\t * {@glink builds/guides/integration/advanced-setup#scenario-2-building-from-source \"Building from source\"} section\n\t * or in the {@glink framework/guides/quick-start \"Quick start\"} guide of CKEditor 5 Framework.\n\t *\n\t * The correct way to do so is to import an editor and plugins and run them together like this:\n\t *\n\t *\t\timport ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';\n\t *\t\timport Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';\n\t *\t\timport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\n\t *\t\timport Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';\n\t *\t\timport Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';\n\t *\n\t *\t\tClassicEditor\n\t *\t\t\t.create( document.querySelector( '#editor' ), {\n\t *\t\t\t\tplugins: [ Essentials, Paragraph, Bold, Italic ],\n\t *\t\t\t\ttoolbar: [ 'bold', 'italic' ]\n\t *\t\t\t} )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\t\t\t} )\n\t *\t\t\t.catch( error => {\n\t *\t\t\t\tconsole.error( error.stack );\n\t *\t\t\t} );\n\t *\n\t * However, you might have mistakenly imported a build instead of the source `ClassicEditor`. In this case\n\t * your imports will look like this:\n\t *\n\t *\t\timport ClassicEditor from '@ckeditor/ckeditor5-build-classic';\n\t *\t\timport Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';\n\t *\t\timport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\n\t *\t\timport Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';\n\t *\t\timport Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';\n\t *\n\t * This creates the same situation as in the previous section because you use a build together with source plugins.\n\t *\n\t * Remember: `@ckeditor/ckeditor5-build-*` packages contain editor builds and `@ckeditor/ckeditor5-editor-*` contain source editors.\n\t *\n\t * # Loading two or more builds on one page\n\t *\n\t * If you use CKEditor 5 builds, you might have loaded two (or more) `ckeditor.js` files on one web page.\n\t * Check your web page for duplicated `<script>` elements or make sure your page builder/bundler includes CKEditor only once.\n\t *\n\t * If you want to use two different types of editors at once, see the\n\t * {@glink builds/guides/integration/advanced-setup#scenario-3-using-two-different-editors \"Using two different editors\"}\n\t * section.\n\t *\n\t * # Using outdated packages\n\t *\n\t * Building CKEditor 5 from source requires using multiple npm packages. These packages have their dependencies\n\t * to other packages. If you use the latest version of, for example, `@ckeditor/ckeditor5-editor-classic` with\n\t * an outdated version of `@ckeditor/ckeditor5-image`, npm or yarn will need to install two different versions of\n\t * `@ckeditor/ckeditor5-core` because `@ckeditor/ckeditor5-editor-classic` and `@ckeditor/ckeditor5-image` may require\n\t * different versions of the core package.\n\t *\n\t * The solution to this issue is to update all packages to their latest version. We recommend\n\t * using tools like [`node-check-updates`](https://www.npmjs.com/package/npm-check-updates) which simplify this process.\n\t *\n\t * # Conflicting version of dependencies\n\t *\n\t * This is a special case of the previous scenario. If you use CKEditor 5 with some third-party plugins,\n\t * it may happen that even if you use the latest versions of the official packages and the latest version of\n\t * these third-party packages, there will be a conflict between some of their dependencies.\n\t *\n\t * Such a problem can be resolved by either downgrading CKEditor 5 packages (which we do not recommend) or\n\t * asking the author of the third-party package to upgrade its depdendencies (or forking their project and doing this yourself).\n\t *\n\t * # Packages were duplicated in `node_modules`\n\t *\n\t * In some situations, especially when calling `npm install` multiple times, it may happen\n\t * that npm will not correctly \"deduplicate\" packages.\n\t *\n\t * Normally, npm deduplicates all packages so, for example, `@ckeditor/ckeditor5-core` is installed only once in `node_modules/`.\n\t * However, it is known to fail to do so from time to time.\n\t *\n\t * We recommend checking if any of the steps listed below help:\n\t *\n\t * * `rm -rf node_modules && npm install` to make sure you have a clean `node_modules/` directory. This step\n\t * is known to help in most cases.\n\t * * If you use `yarn.lock` or `package-lock.json`, remove it before `npm install`.\n\t * * Check whether all CKEditor 5 packages are up to date and reinstall them\n\t * if you changed anything (`rm -rf node_modules && npm install`).\n\t *\n\t * If all packages are correct and compatible with each other, the steps above are known to help. If not, you may\n\t * try to check with `npm ls` how many times packages like `@ckeditor/ckeditor5-core`, `@ckeditor/ckeditor5-engine` and\n\t *`@ckeditor/ckeditor5-utils` are installed. If more than once, verify which package causes that.\n\t *\n\t * @error ckeditor-duplicated-modules\n\t */\n\tthrow new CKEditorError(\n\t\t'ckeditor-duplicated-modules: Some CKEditor 5 modules are duplicated.',\n\t\tnull\n\t);\n} else {\n\twindowOrGlobal.CKEDITOR_VERSION = version;\n}\n","/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nexport default freeGlobal;\n","import root from './_root.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined,\n allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined;\n\n/**\n * Creates a clone of `buffer`.\n *\n * @private\n * @param {Buffer} buffer The buffer to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Buffer} Returns the cloned buffer.\n */\nfunction cloneBuffer(buffer, isDeep) {\n if (isDeep) {\n return buffer.slice();\n }\n var length = buffer.length,\n result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);\n\n buffer.copy(result);\n return result;\n}\n\nexport default cloneBuffer;\n","module.exports = function(originalModule) {\n\tif (!originalModule.webpackPolyfill) {\n\t\tvar module = Object.create(originalModule);\n\t\t// module.parent = undefined by default\n\t\tif (!module.children) module.children = [];\n\t\tObject.defineProperty(module, \"loaded\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.l;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"id\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.i;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"exports\", {\n\t\t\tenumerable: true\n\t\t});\n\t\tmodule.webpackPolyfill = 1;\n\t}\n\treturn module;\n};\n","var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || new Function(\"return this\")();\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./heading.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./code.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./placeholder.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-placeholder:before,.ck .ck-placeholder:before{content:attr(data-placeholder);pointer-events:none}.ck.ck-read-only .ck-placeholder:before{display:none}.ck.ck-placeholder:before,.ck .ck-placeholder:before{cursor:text;color:var(--ck-color-engine-placeholder-text)}\"","var api = require(\"!../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../postcss-loader/src/index.js??ref--5-1!./globals.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck-hidden{display:none!important}.ck.ck-reset,.ck.ck-reset_all,.ck.ck-reset_all *{box-sizing:border-box;width:auto;height:auto;position:static}:root{--ck-z-default:1;--ck-z-modal:calc(var(--ck-z-default) + 999);--ck-color-base-foreground:#fafafa;--ck-color-base-background:#fff;--ck-color-base-border:#c4c4c4;--ck-color-base-action:#61b045;--ck-color-base-focus:#6cb5f9;--ck-color-base-text:#333;--ck-color-base-active:#198cf0;--ck-color-base-active-focus:#0e7fe1;--ck-color-base-error:#db3700;--ck-color-focus-border:#1f89e5;--ck-color-focus-outer-shadow:#bcdefb;--ck-color-focus-disabled-shadow:rgba(119,186,248,0.3);--ck-color-focus-error-shadow:rgba(255,64,31,0.3);--ck-color-text:var(--ck-color-base-text);--ck-color-shadow-drop:rgba(0,0,0,0.15);--ck-color-shadow-drop-active:rgba(0,0,0,0.2);--ck-color-shadow-inner:rgba(0,0,0,0.1);--ck-color-button-default-background:transparent;--ck-color-button-default-hover-background:#e6e6e6;--ck-color-button-default-active-background:#d9d9d9;--ck-color-button-default-active-shadow:#bfbfbf;--ck-color-button-default-disabled-background:transparent;--ck-color-button-on-background:#dedede;--ck-color-button-on-hover-background:#c4c4c4;--ck-color-button-on-active-background:#bababa;--ck-color-button-on-active-shadow:#a1a1a1;--ck-color-button-on-disabled-background:#dedede;--ck-color-button-action-background:var(--ck-color-base-action);--ck-color-button-action-hover-background:#579e3d;--ck-color-button-action-active-background:#53973b;--ck-color-button-action-active-shadow:#498433;--ck-color-button-action-disabled-background:#7ec365;--ck-color-button-action-text:var(--ck-color-base-background);--ck-color-button-save:#008a00;--ck-color-button-cancel:#db3700;--ck-color-switch-button-off-background:#b0b0b0;--ck-color-switch-button-off-hover-background:#a3a3a3;--ck-color-switch-button-on-background:var(--ck-color-button-action-background);--ck-color-switch-button-on-hover-background:#579e3d;--ck-color-switch-button-inner-background:var(--ck-color-base-background);--ck-color-switch-button-inner-shadow:rgba(0,0,0,0.1);--ck-color-dropdown-panel-background:var(--ck-color-base-background);--ck-color-dropdown-panel-border:var(--ck-color-base-border);--ck-color-input-background:var(--ck-color-base-background);--ck-color-input-border:#c7c7c7;--ck-color-input-error-border:var(--ck-color-base-error);--ck-color-input-text:var(--ck-color-base-text);--ck-color-input-disabled-background:#f2f2f2;--ck-color-input-disabled-border:#c7c7c7;--ck-color-input-disabled-text:#5c5c5c;--ck-color-list-background:var(--ck-color-base-background);--ck-color-list-button-hover-background:var(--ck-color-button-default-hover-background);--ck-color-list-button-on-background:var(--ck-color-base-active);--ck-color-list-button-on-background-focus:var(--ck-color-base-active-focus);--ck-color-list-button-on-text:var(--ck-color-base-background);--ck-color-panel-background:var(--ck-color-base-background);--ck-color-panel-border:var(--ck-color-base-border);--ck-color-toolbar-background:var(--ck-color-base-foreground);--ck-color-toolbar-border:var(--ck-color-base-border);--ck-color-tooltip-background:var(--ck-color-base-text);--ck-color-tooltip-text:var(--ck-color-base-background);--ck-color-engine-placeholder-text:#707070;--ck-color-upload-bar-background:#6cb5f9;--ck-color-link-default:#0000f0;--ck-color-link-selected-background:rgba(31,177,255,0.1);--ck-disabled-opacity:.5;--ck-focus-outer-shadow-geometry:0 0 0 3px;--ck-focus-outer-shadow:var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-outer-shadow);--ck-focus-disabled-outer-shadow:var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-disabled-shadow);--ck-focus-error-outer-shadow:var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-error-shadow);--ck-focus-ring:1px solid var(--ck-color-focus-border);--ck-font-size-base:13px;--ck-line-height-base:1.84615;--ck-font-face:Helvetica,Arial,Tahoma,Verdana,Sans-Serif;--ck-font-size-tiny:0.7em;--ck-font-size-small:0.75em;--ck-font-size-normal:1em;--ck-font-size-big:1.4em;--ck-font-size-large:1.8em;--ck-ui-component-min-height:2.3em}.ck.ck-reset,.ck.ck-reset_all,.ck.ck-reset_all *{margin:0;padding:0;border:0;background:transparent;text-decoration:none;vertical-align:middle;transition:none;word-wrap:break-word}.ck.ck-reset_all,.ck.ck-reset_all *{border-collapse:collapse;font:normal normal normal var(--ck-font-size-base)/var(--ck-line-height-base) var(--ck-font-face);color:var(--ck-color-text);text-align:left;white-space:nowrap;cursor:auto;float:none}.ck.ck-reset_all .ck-rtl *{text-align:right}.ck.ck-reset_all iframe{vertical-align:inherit}.ck.ck-reset_all textarea{white-space:pre-wrap}.ck.ck-reset_all input[type=password],.ck.ck-reset_all input[type=text],.ck.ck-reset_all textarea{cursor:text}.ck.ck-reset_all input[type=password][disabled],.ck.ck-reset_all input[type=text][disabled],.ck.ck-reset_all textarea[disabled]{cursor:default}.ck.ck-reset_all fieldset{padding:10px;border:2px groove #dfdee3}.ck.ck-reset_all button::-moz-focus-inner{padding:0;border:0}.ck[dir=rtl],.ck[dir=rtl] .ck{text-align:right}:root{--ck-border-radius:2px;--ck-inner-shadow:2px 2px 3px var(--ck-color-shadow-inner) inset;--ck-drop-shadow:0 1px 2px 1px var(--ck-color-shadow-drop);--ck-drop-shadow-active:0 3px 6px 1px var(--ck-color-shadow-drop-active);--ck-spacing-unit:0.6em;--ck-spacing-large:calc(var(--ck-spacing-unit)*1.5);--ck-spacing-standard:var(--ck-spacing-unit);--ck-spacing-medium:calc(var(--ck-spacing-unit)*0.8);--ck-spacing-small:calc(var(--ck-spacing-unit)*0.5);--ck-spacing-tiny:calc(var(--ck-spacing-unit)*0.3);--ck-spacing-extra-tiny:calc(var(--ck-spacing-unit)*0.16)}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./editorui.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-editor__editable:not(.ck-editor__nested-editable){border-radius:0}.ck-rounded-corners .ck.ck-editor__editable:not(.ck-editor__nested-editable),.ck.ck-editor__editable:not(.ck-editor__nested-editable).ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-editor__editable:not(.ck-editor__nested-editable).ck-focused{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-inner-shadow),0 0}.ck.ck-editor__editable_inline{overflow:auto;padding:0 var(--ck-spacing-standard);border:1px solid transparent}.ck.ck-editor__editable_inline[dir=ltr]{text-align:left}.ck.ck-editor__editable_inline[dir=rtl]{text-align:right}.ck.ck-editor__editable_inline>:first-child{margin-top:var(--ck-spacing-large)}.ck.ck-editor__editable_inline>:last-child{margin-bottom:var(--ck-spacing-large)}.ck.ck-balloon-panel.ck-toolbar-container[class*=arrow_n]:after{border-bottom-color:var(--ck-color-base-foreground)}.ck.ck-balloon-panel.ck-toolbar-container[class*=arrow_s]:after{border-top-color:var(--ck-color-base-foreground)}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./label.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-label{display:block}.ck.ck-voice-label{display:none}.ck.ck-label{font-weight:700}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./stickypanel.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-sticky-panel .ck-sticky-panel__content_sticky{z-index:var(--ck-z-modal);position:fixed;top:0}.ck.ck-sticky-panel .ck-sticky-panel__content_sticky_bottom-limit{top:auto;position:absolute}.ck.ck-sticky-panel .ck-sticky-panel__content_sticky{box-shadow:var(--ck-drop-shadow),0 0;border-width:0 1px 1px;border-top-left-radius:0;border-top-right-radius:0}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./dropdown.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-dropdown{display:inline-block;position:relative}.ck.ck-dropdown .ck-dropdown__arrow{pointer-events:none;z-index:var(--ck-z-default)}.ck.ck-dropdown .ck-button.ck-dropdown__button{width:100%}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on .ck-tooltip{display:none}.ck.ck-dropdown .ck-dropdown__panel{-webkit-backface-visibility:hidden;display:none;z-index:var(--ck-z-modal);position:absolute}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel-visible{display:inline-block}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_ne,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nw{bottom:100%}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw{top:100%;bottom:auto}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_ne,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se{left:0}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw{right:0}:root{--ck-dropdown-arrow-size:calc(0.5*var(--ck-icon-size))}.ck.ck-dropdown{font-size:inherit}.ck.ck-dropdown .ck-dropdown__arrow{width:var(--ck-dropdown-arrow-size)}[dir=ltr] .ck.ck-dropdown .ck-dropdown__arrow{right:var(--ck-spacing-standard);margin-left:var(--ck-spacing-small)}[dir=rtl] .ck.ck-dropdown .ck-dropdown__arrow{left:var(--ck-spacing-standard);margin-right:var(--ck-spacing-small)}.ck.ck-dropdown.ck-disabled .ck-dropdown__arrow{opacity:var(--ck-disabled-opacity)}[dir=ltr] .ck.ck-dropdown .ck-button.ck-dropdown__button:not(.ck-button_with-text){padding-left:var(--ck-spacing-small)}[dir=rtl] .ck.ck-dropdown .ck-button.ck-dropdown__button:not(.ck-button_with-text){padding-right:var(--ck-spacing-small)}.ck.ck-dropdown .ck-button.ck-dropdown__button .ck-button__label{width:7em;overflow:hidden;text-overflow:ellipsis}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-disabled .ck-button__label{opacity:var(--ck-disabled-opacity)}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on{border-bottom-left-radius:0;border-bottom-right-radius:0}.ck.ck-dropdown__panel{box-shadow:var(--ck-drop-shadow),0 0;border-radius:0}.ck-rounded-corners .ck.ck-dropdown__panel,.ck.ck-dropdown__panel.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0}.ck.ck-dropdown__panel{background:var(--ck-color-dropdown-panel-background);border:1px solid var(--ck-color-dropdown-panel-border);bottom:0;min-width:100%}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./icon.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-icon{vertical-align:middle}:root{--ck-icon-size:calc(var(--ck-line-height-base)*var(--ck-font-size-normal))}.ck.ck-icon{width:var(--ck-icon-size);height:var(--ck-icon-size);font-size:.8333350694em;will-change:transform}.ck.ck-icon,.ck.ck-icon *{color:inherit;cursor:inherit}.ck.ck-icon :not([fill]){fill:currentColor}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./tooltip.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-tooltip,.ck.ck-tooltip .ck-tooltip__text:after{position:absolute;pointer-events:none;-webkit-backface-visibility:hidden}.ck.ck-tooltip{visibility:hidden;opacity:0;display:none;z-index:var(--ck-z-modal)}.ck.ck-tooltip .ck-tooltip__text{display:inline-block}.ck.ck-tooltip .ck-tooltip__text:after{content:\\\"\\\";width:0;height:0}:root{--ck-tooltip-arrow-size:5px}.ck.ck-tooltip{left:50%;top:0;transition:opacity .2s ease-in-out .2s}.ck.ck-tooltip .ck-tooltip__text{border-radius:0}.ck-rounded-corners .ck.ck-tooltip .ck-tooltip__text,.ck.ck-tooltip .ck-tooltip__text.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-tooltip .ck-tooltip__text{font-size:.9em;line-height:1.5;color:var(--ck-color-tooltip-text);padding:var(--ck-spacing-small) var(--ck-spacing-medium);background:var(--ck-color-tooltip-background);position:relative;left:-50%}.ck.ck-tooltip .ck-tooltip__text:after{transition:opacity .2s ease-in-out .2s;border-style:solid;left:50%}.ck.ck-tooltip.ck-tooltip_s{bottom:calc(-1*var(--ck-tooltip-arrow-size));transform:translateY(100%)}.ck.ck-tooltip.ck-tooltip_s .ck-tooltip__text:after{top:calc(-1*var(--ck-tooltip-arrow-size));transform:translateX(-50%);border-left-color:transparent;border-bottom-color:var(--ck-color-tooltip-background);border-right-color:transparent;border-top-color:transparent;border-left-width:var(--ck-tooltip-arrow-size);border-bottom-width:var(--ck-tooltip-arrow-size);border-right-width:var(--ck-tooltip-arrow-size);border-top-width:0}.ck.ck-tooltip.ck-tooltip_n{top:calc(-1*var(--ck-tooltip-arrow-size));transform:translateY(-100%)}.ck.ck-tooltip.ck-tooltip_n .ck-tooltip__text:after{bottom:calc(-1*var(--ck-tooltip-arrow-size));transform:translateX(-50%);border-left-color:transparent;border-bottom-color:transparent;border-right-color:transparent;border-top-color:var(--ck-color-tooltip-background);border-left-width:var(--ck-tooltip-arrow-size);border-bottom-width:0;border-right-width:var(--ck-tooltip-arrow-size);border-top-width:var(--ck-tooltip-arrow-size)}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./button.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-button,a.ck.ck-button{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.ck.ck-button .ck-tooltip,a.ck.ck-button .ck-tooltip{display:block}@media (hover:none){.ck.ck-button .ck-tooltip,a.ck.ck-button .ck-tooltip{display:none}}.ck.ck-button,a.ck.ck-button{position:relative;display:inline-flex;align-items:center;justify-content:left}.ck.ck-button .ck-button__label,a.ck.ck-button .ck-button__label{display:none}.ck.ck-button.ck-button_with-text .ck-button__label,a.ck.ck-button.ck-button_with-text .ck-button__label{display:inline-block}.ck.ck-button:not(.ck-button_with-text),a.ck.ck-button:not(.ck-button_with-text){justify-content:center}.ck.ck-button:hover .ck-tooltip,a.ck.ck-button:hover .ck-tooltip{visibility:visible;opacity:1}.ck.ck-button:focus:not(:hover) .ck-tooltip,a.ck.ck-button:focus:not(:hover) .ck-tooltip{display:none}.ck.ck-button,a.ck.ck-button{background:var(--ck-color-button-default-background)}.ck.ck-button:not(.ck-disabled):hover,a.ck.ck-button:not(.ck-disabled):hover{background:var(--ck-color-button-default-hover-background)}.ck.ck-button:not(.ck-disabled):active,a.ck.ck-button:not(.ck-disabled):active{background:var(--ck-color-button-default-active-background);box-shadow:inset 0 2px 2px var(--ck-color-button-default-active-shadow)}.ck.ck-button.ck-disabled,a.ck.ck-button.ck-disabled{background:var(--ck-color-button-default-disabled-background)}.ck.ck-button,a.ck.ck-button{border-radius:0}.ck-rounded-corners .ck.ck-button,.ck-rounded-corners a.ck.ck-button,.ck.ck-button.ck-rounded-corners,a.ck.ck-button.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-button,a.ck.ck-button{white-space:nowrap;cursor:default;vertical-align:middle;padding:var(--ck-spacing-tiny);text-align:center;min-width:var(--ck-ui-component-min-height);min-height:var(--ck-ui-component-min-height);line-height:1;font-size:inherit;border:1px solid transparent;transition:box-shadow .2s ease-in-out,border .2s ease-in-out;-webkit-appearance:none}.ck.ck-button:active,.ck.ck-button:focus,a.ck.ck-button:active,a.ck.ck-button:focus{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow),0 0}.ck.ck-button .ck-button__icon use,.ck.ck-button .ck-button__icon use *,a.ck.ck-button .ck-button__icon use,a.ck.ck-button .ck-button__icon use *{color:inherit}.ck.ck-button .ck-button__label,a.ck.ck-button .ck-button__label{font-size:inherit;font-weight:inherit;color:inherit;cursor:inherit;vertical-align:middle}[dir=ltr] .ck.ck-button .ck-button__label,[dir=ltr] a.ck.ck-button .ck-button__label{text-align:left}[dir=rtl] .ck.ck-button .ck-button__label,[dir=rtl] a.ck.ck-button .ck-button__label{text-align:right}.ck.ck-button .ck-button__keystroke,a.ck.ck-button .ck-button__keystroke{color:inherit}[dir=ltr] .ck.ck-button .ck-button__keystroke,[dir=ltr] a.ck.ck-button .ck-button__keystroke{margin-left:var(--ck-spacing-large)}[dir=rtl] .ck.ck-button .ck-button__keystroke,[dir=rtl] a.ck.ck-button .ck-button__keystroke{margin-right:var(--ck-spacing-large)}.ck.ck-button .ck-button__keystroke,a.ck.ck-button .ck-button__keystroke{font-weight:700;opacity:.7}.ck.ck-button.ck-disabled:active,.ck.ck-button.ck-disabled:focus,a.ck.ck-button.ck-disabled:active,a.ck.ck-button.ck-disabled:focus{box-shadow:var(--ck-focus-disabled-outer-shadow),0 0}.ck.ck-button.ck-disabled .ck-button__icon,a.ck.ck-button.ck-disabled .ck-button__icon{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-disabled .ck-button__label,a.ck.ck-button.ck-disabled .ck-button__label{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-disabled .ck-button__keystroke,a.ck.ck-button.ck-disabled .ck-button__keystroke{opacity:.3}.ck.ck-button.ck-button_with-text,a.ck.ck-button.ck-button_with-text{padding:var(--ck-spacing-tiny) var(--ck-spacing-standard)}[dir=ltr] .ck.ck-button.ck-button_with-text .ck-button__icon,[dir=ltr] a.ck.ck-button.ck-button_with-text .ck-button__icon{margin-left:calc(-1*var(--ck-spacing-small));margin-right:var(--ck-spacing-small)}[dir=rtl] .ck.ck-button.ck-button_with-text .ck-button__icon,[dir=rtl] a.ck.ck-button.ck-button_with-text .ck-button__icon{margin-right:calc(-1*var(--ck-spacing-small));margin-left:var(--ck-spacing-small)}.ck.ck-button.ck-button_with-keystroke .ck-button__label,a.ck.ck-button.ck-button_with-keystroke .ck-button__label{flex-grow:1}.ck.ck-button.ck-on,a.ck.ck-button.ck-on{background:var(--ck-color-button-on-background)}.ck.ck-button.ck-on:not(.ck-disabled):hover,a.ck.ck-button.ck-on:not(.ck-disabled):hover{background:var(--ck-color-button-on-hover-background)}.ck.ck-button.ck-on:not(.ck-disabled):active,a.ck.ck-button.ck-on:not(.ck-disabled):active{background:var(--ck-color-button-on-active-background);box-shadow:inset 0 2px 2px var(--ck-color-button-on-active-shadow)}.ck.ck-button.ck-on.ck-disabled,a.ck.ck-button.ck-on.ck-disabled{background:var(--ck-color-button-on-disabled-background)}.ck.ck-button.ck-button-save,a.ck.ck-button.ck-button-save{color:var(--ck-color-button-save)}.ck.ck-button.ck-button-cancel,a.ck.ck-button.ck-button-cancel{color:var(--ck-color-button-cancel)}.ck.ck-button-action,a.ck.ck-button-action{background:var(--ck-color-button-action-background)}.ck.ck-button-action:not(.ck-disabled):hover,a.ck.ck-button-action:not(.ck-disabled):hover{background:var(--ck-color-button-action-hover-background)}.ck.ck-button-action:not(.ck-disabled):active,a.ck.ck-button-action:not(.ck-disabled):active{background:var(--ck-color-button-action-active-background);box-shadow:inset 0 2px 2px var(--ck-color-button-action-active-shadow)}.ck.ck-button-action.ck-disabled,a.ck.ck-button-action.ck-disabled{background:var(--ck-color-button-action-disabled-background)}.ck.ck-button-action,a.ck.ck-button-action{color:var(--ck-color-button-action-text)}.ck.ck-button-bold,a.ck.ck-button-bold{font-weight:700}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./list.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-list{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;display:flex;flex-direction:column}.ck.ck-list .ck-list__item,.ck.ck-list .ck-list__separator{display:block}.ck.ck-list .ck-list__item>:focus{position:relative;z-index:var(--ck-z-default)}.ck.ck-list{border-radius:0}.ck-rounded-corners .ck.ck-list,.ck.ck-list.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-list{list-style-type:none;background:var(--ck-color-list-background)}.ck.ck-list__item{cursor:default;min-width:12em}.ck.ck-list__item .ck-button{min-height:unset;width:100%;text-align:left;border-radius:0;padding:calc(0.2*var(--ck-line-height-base)*var(--ck-font-size-base)) calc(0.4*var(--ck-line-height-base)*var(--ck-font-size-base))}.ck.ck-list__item .ck-button .ck-button__label{line-height:calc(1.2*var(--ck-line-height-base)*var(--ck-font-size-base))}.ck.ck-list__item .ck-button:active{box-shadow:none}.ck.ck-list__item .ck-button.ck-on{background:var(--ck-color-list-button-on-background);color:var(--ck-color-list-button-on-text)}.ck.ck-list__item .ck-button.ck-on:active{box-shadow:none}.ck.ck-list__item .ck-button.ck-on:hover:not(.ck-disabled){background:var(--ck-color-list-button-on-background-focus)}.ck.ck-list__item .ck-button.ck-on:focus:not(.ck-disabled){border-color:var(--ck-color-base-background)}.ck.ck-list__item .ck-button:hover:not(.ck-disabled){background:var(--ck-color-list-button-hover-background)}.ck.ck-list__item .ck-switchbutton.ck-on{background:var(--ck-color-list-background);color:inherit}.ck.ck-list__item .ck-switchbutton.ck-on:hover:not(.ck-disabled){background:var(--ck-color-list-button-hover-background);color:inherit}.ck.ck-list__separator{height:1px;width:100%;background:var(--ck-color-base-border)}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./switchbutton.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-button.ck-switchbutton .ck-button__toggle,.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{display:block}:root{--ck-switch-button-toggle-width:2.6153846154em;--ck-switch-button-toggle-inner-size:1.0769230769em;--ck-switch-button-toggle-spacing:1px;--ck-switch-button-translation:1.3846153847em}[dir=ltr] .ck.ck-button.ck-switchbutton .ck-button__label{margin-right:calc(2*var(--ck-spacing-large))}[dir=rtl] .ck.ck-button.ck-switchbutton .ck-button__label{margin-left:calc(2*var(--ck-spacing-large))}.ck.ck-button.ck-switchbutton .ck-button__toggle{border-radius:0}.ck-rounded-corners .ck.ck-button.ck-switchbutton .ck-button__toggle,.ck.ck-button.ck-switchbutton .ck-button__toggle.ck-rounded-corners{border-radius:var(--ck-border-radius)}[dir=ltr] .ck.ck-button.ck-switchbutton .ck-button__toggle{margin-left:auto}[dir=rtl] .ck.ck-button.ck-switchbutton .ck-button__toggle{margin-right:auto}.ck.ck-button.ck-switchbutton .ck-button__toggle{transition:background .4s ease;width:var(--ck-switch-button-toggle-width);background:var(--ck-color-switch-button-off-background)}.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{border-radius:0}.ck-rounded-corners .ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner,.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner.ck-rounded-corners{border-radius:var(--ck-border-radius);border-radius:calc(0.5*var(--ck-border-radius))}.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{margin:var(--ck-switch-button-toggle-spacing);width:var(--ck-switch-button-toggle-inner-size);height:var(--ck-switch-button-toggle-inner-size);background:var(--ck-color-switch-button-inner-background);transition:all .3s ease}.ck.ck-button.ck-switchbutton .ck-button__toggle:hover{background:var(--ck-color-switch-button-off-hover-background)}.ck.ck-button.ck-switchbutton .ck-button__toggle:hover .ck-button__toggle__inner{box-shadow:0 0 0 5px var(--ck-color-switch-button-inner-shadow)}.ck.ck-button.ck-switchbutton.ck-disabled .ck-button__toggle{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle{background:var(--ck-color-switch-button-on-background)}.ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle:hover{background:var(--ck-color-switch-button-on-hover-background)}[dir=ltr] .ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle .ck-button__toggle__inner{transform:translateX(var(--ck-switch-button-translation))}[dir=rtl] .ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle .ck-button__toggle__inner{transform:translateX(calc(-1*var(--ck-switch-button-translation)))}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./toolbardropdown.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-toolbar-dropdown .ck.ck-toolbar .ck.ck-toolbar__items{flex-wrap:nowrap}.ck.ck-toolbar-dropdown .ck-dropdown__panel .ck-button:focus{z-index:calc(var(--ck-z-default) + 1)}.ck.ck-toolbar-dropdown .ck-toolbar{border:0}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./listdropdown.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-dropdown .ck-dropdown__panel .ck-list{border-radius:0}.ck-rounded-corners .ck.ck-dropdown .ck-dropdown__panel .ck-list,.ck.ck-dropdown .ck-dropdown__panel .ck-list.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0}.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:first-child .ck-button{border-radius:0}.ck-rounded-corners .ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:first-child .ck-button,.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:first-child .ck-button.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0;border-bottom-left-radius:0;border-bottom-right-radius:0}.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:last-child .ck-button{border-radius:0}.ck-rounded-corners .ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:last-child .ck-button,.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:last-child .ck-button.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0;border-top-right-radius:0}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./toolbar.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-toolbar{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;display:flex;flex-flow:row nowrap;align-items:center}.ck.ck-toolbar>.ck-toolbar__items{display:flex;flex-flow:row wrap;align-items:center;flex-grow:1}.ck.ck-toolbar .ck.ck-toolbar__separator{display:inline-block}.ck.ck-toolbar .ck.ck-toolbar__separator:first-child,.ck.ck-toolbar .ck.ck-toolbar__separator:last-child{display:none}.ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items{flex-wrap:nowrap}.ck.ck-toolbar.ck-toolbar_vertical>.ck-toolbar__items{flex-direction:column}.ck.ck-toolbar.ck-toolbar_floating>.ck-toolbar__items{flex-wrap:nowrap}.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown>.ck-dropdown__button .ck-dropdown__arrow{display:none}.ck.ck-toolbar{border-radius:0}.ck-rounded-corners .ck.ck-toolbar,.ck.ck-toolbar.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-toolbar{background:var(--ck-color-toolbar-background);padding:0 var(--ck-spacing-small);border:1px solid var(--ck-color-toolbar-border)}.ck.ck-toolbar>.ck-toolbar__items>*{margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small);margin-right:var(--ck-spacing-small)}.ck.ck-toolbar.ck-toolbar_vertical{padding:0}.ck.ck-toolbar.ck-toolbar_vertical>.ck-toolbar__items>.ck{width:100%;margin:0;border-radius:0;border:0}.ck.ck-toolbar.ck-toolbar_compact{padding:0}.ck.ck-toolbar.ck-toolbar_compact .ck-toolbar__items>.ck{margin:0}.ck.ck-toolbar.ck-toolbar_compact .ck-toolbar__items>.ck:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.ck.ck-toolbar.ck-toolbar_compact .ck-toolbar__items>.ck:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.ck.ck-toolbar.ck-toolbar_compact .ck-toolbar__items>.ck:not(:first-child):not(:last-child){border-radius:0}.ck.ck-toolbar>.ck-toolbar__items>*,.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown{margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small)}.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown>.ck.ck-button.ck-dropdown__button{padding-left:var(--ck-spacing-tiny)}.ck.ck-toolbar .ck.ck-toolbar__separator{align-self:stretch;width:1px;min-width:1px;margin-top:0;margin-bottom:0;background:var(--ck-color-toolbar-border)}.ck-toolbar-container .ck.ck-toolbar{border:0}.ck.ck-toolbar[dir=rtl]>.ck.ck-toolbar__grouped-dropdown,[dir=rtl] .ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown{padding-right:var(--ck-spacing-small)}.ck.ck-toolbar[dir=rtl]>.ck.ck-toolbar__items>*,[dir=rtl] .ck.ck-toolbar>.ck.ck-toolbar__items>*{margin-left:var(--ck-spacing-small);margin-right:0}.ck.ck-toolbar[dir=rtl]>.ck.ck-toolbar__items>:last-child,[dir=rtl] .ck.ck-toolbar>.ck.ck-toolbar__items>:last-child{margin-left:0}.ck.ck-toolbar[dir=rtl].ck-toolbar_grouping>.ck-toolbar__items,[dir=rtl] .ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items{margin-left:var(--ck-spacing-small)}.ck.ck-toolbar[dir=ltr]>.ck.ck-toolbar__grouped-dropdown,[dir=ltr] .ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown{padding-left:var(--ck-spacing-small)}.ck.ck-toolbar[dir=ltr]>.ck.ck-toolbar__items>:last-child,[dir=ltr] .ck.ck-toolbar>.ck.ck-toolbar__items>:last-child{margin-right:0}.ck.ck-toolbar[dir=ltr].ck-toolbar_grouping>.ck-toolbar__items,[dir=ltr] .ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items{margin-right:var(--ck-spacing-small)}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./classiceditor.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-editor{position:relative}.ck.ck-editor .ck-editor__top .ck-sticky-panel .ck-toolbar{z-index:var(--ck-z-modal)}.ck.ck-editor__top .ck-sticky-panel .ck-toolbar{border-radius:0}.ck-rounded-corners .ck.ck-editor__top .ck-sticky-panel .ck-toolbar,.ck.ck-editor__top .ck-sticky-panel .ck-toolbar.ck-rounded-corners{border-radius:var(--ck-border-radius);border-bottom-left-radius:0;border-bottom-right-radius:0}.ck.ck-editor__top .ck-sticky-panel .ck-toolbar{border-bottom-width:0}.ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content_sticky .ck-toolbar{border-bottom-width:1px;border-radius:0}.ck-rounded-corners .ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content_sticky .ck-toolbar,.ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content_sticky .ck-toolbar.ck-rounded-corners{border-radius:var(--ck-border-radius);border-radius:0}.ck.ck-editor__main>.ck-editor__editable{background:var(--ck-color-base-background);border-radius:0}.ck-rounded-corners .ck.ck-editor__main>.ck-editor__editable,.ck.ck-editor__main>.ck-editor__editable.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0;border-top-right-radius:0}.ck.ck-editor__main>.ck-editor__editable:not(.ck-focused){border-color:var(--ck-color-base-border)}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./blockquote.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck-content blockquote{overflow:hidden;padding-right:1.5em;padding-left:1.5em;margin-left:0;margin-right:0;font-style:italic;border-left:5px solid #ccc}.ck-content[dir=rtl] blockquote{border-left:0;border-right:5px solid #ccc}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./link.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck .ck-link_selected{background:var(--ck-color-link-selected-background)}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./widget.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \":root{--ck-color-resizer:var(--ck-color-focus-border);--ck-resizer-size:10px;--ck-resizer-border-width:1px;--ck-resizer-border-radius:2px;--ck-resizer-offset:calc(var(--ck-resizer-size)/-2 - 2px);--ck-resizer-tooltip-offset:10px;--ck-color-resizer-tooltip-background:#262626;--ck-color-resizer-tooltip-text:#f2f2f2}.ck .ck-widget.ck-widget_with-selection-handle{position:relative}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{position:absolute}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon{display:block}.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected .ck-widget__selection-handle,.ck .ck-widget.ck-widget_with-selection-handle:hover .ck-widget__selection-handle{visibility:visible}.ck .ck-size-view{background:var(--ck-color-resizer-tooltip-background);color:var(--ck-color-resizer-tooltip-text);border:1px solid var(--ck-color-resizer-tooltip-text);border-radius:var(--ck-resizer-border-radius);font-size:var(--ck-font-size-tiny);display:block;padding:var(--ck-spacing-small)}.ck .ck-size-view.ck-orientation-bottom-left,.ck .ck-size-view.ck-orientation-bottom-right,.ck .ck-size-view.ck-orientation-top-left,.ck .ck-size-view.ck-orientation-top-right{position:absolute}.ck .ck-size-view.ck-orientation-top-left{top:var(--ck-resizer-tooltip-offset);left:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-top-right{top:var(--ck-resizer-tooltip-offset);right:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-bottom-right{bottom:var(--ck-resizer-tooltip-offset);right:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-bottom-left{bottom:var(--ck-resizer-tooltip-offset);left:var(--ck-resizer-tooltip-offset)}:root{--ck-widget-outline-thickness:3px;--ck-widget-handler-icon-size:16px;--ck-widget-handler-animation-duration:200ms;--ck-widget-handler-animation-curve:ease;--ck-color-widget-blurred-border:#dedede;--ck-color-widget-hover-border:#ffc83d;--ck-color-widget-editable-focus-background:var(--ck-color-base-background);--ck-color-widget-drag-handler-icon-color:var(--ck-color-base-background)}.ck .ck-widget{outline-width:var(--ck-widget-outline-thickness);outline-style:solid;outline-color:transparent;transition:outline-color var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve)}.ck .ck-widget.ck-widget_selected,.ck .ck-widget.ck-widget_selected:hover{outline:var(--ck-widget-outline-thickness) solid var(--ck-color-focus-border)}.ck .ck-widget:hover{outline-color:var(--ck-color-widget-hover-border)}.ck .ck-editor__nested-editable{border:1px solid transparent}.ck .ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck .ck-editor__nested-editable:focus{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-inner-shadow),0 0;background-color:var(--ck-color-widget-editable-focus-background)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{padding:4px;box-sizing:border-box;background-color:transparent;opacity:0;transition:background-color var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve),visibility var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve),opacity var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);border-radius:var(--ck-border-radius) var(--ck-border-radius) 0 0;transform:translateY(-100%);left:calc(0px - var(--ck-widget-outline-thickness))}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon{width:var(--ck-widget-handler-icon-size);height:var(--ck-widget-handler-icon-size);color:var(--ck-color-widget-drag-handler-icon-color)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{opacity:0;transition:opacity .3s var(--ck-widget-handler-animation-curve)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle:hover .ck-icon .ck-icon__selected-indicator{opacity:1}.ck .ck-widget.ck-widget_with-selection-handle:hover .ck-widget__selection-handle{opacity:1;background-color:var(--ck-color-widget-hover-border)}.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected .ck-widget__selection-handle,.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected:hover .ck-widget__selection-handle{opacity:1;background-color:var(--ck-color-focus-border)}.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator,.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected:hover .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{opacity:1}.ck-editor__editable>.ck-widget.ck-widget_with-selection-handle:first-child,.ck-editor__editable blockquote>.ck-widget.ck-widget_with-selection-handle:first-child{margin-top:calc(1em + var(--ck-widget-handler-icon-size))}.ck[dir=rtl] .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{left:auto;right:calc(0px - var(--ck-widget-outline-thickness))}.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected,.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover{outline-color:var(--ck-color-widget-blurred-border)}.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected.ck-widget_with-selection-handle .ck-widget__selection-handle,.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected.ck-widget_with-selection-handle .ck-widget__selection-handle:hover,.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover.ck-widget_with-selection-handle .ck-widget__selection-handle,.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover.ck-widget_with-selection-handle .ck-widget__selection-handle:hover{background:var(--ck-color-widget-blurred-border)}.ck-editor__editable.ck-read-only .ck-widget{--ck-widget-outline-thickness:0}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./labeledinput.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-labeled-input .ck-labeled-input__status{font-size:var(--ck-font-size-small);margin-top:var(--ck-spacing-small);white-space:normal}.ck.ck-labeled-input .ck-labeled-input__status_error{color:var(--ck-color-base-error)}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./inputtext.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \":root{--ck-input-text-width:18em}.ck.ck-input-text{border-radius:0}.ck-rounded-corners .ck.ck-input-text,.ck.ck-input-text.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-input-text{box-shadow:var(--ck-inner-shadow),0 0;background:var(--ck-color-input-background);border:1px solid var(--ck-color-input-border);padding:var(--ck-spacing-extra-tiny) var(--ck-spacing-medium);min-width:var(--ck-input-text-width);min-height:var(--ck-ui-component-min-height);transition:box-shadow .2s ease-in-out,border .2s ease-in-out}.ck.ck-input-text:focus{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow),var(--ck-inner-shadow)}.ck.ck-input-text[readonly]{border:1px solid var(--ck-color-input-disabled-border);background:var(--ck-color-input-disabled-background);color:var(--ck-color-input-disabled-text)}.ck.ck-input-text[readonly]:focus{box-shadow:var(--ck-focus-disabled-outer-shadow),var(--ck-inner-shadow)}.ck.ck-input-text.ck-error{border-color:var(--ck-color-input-error-border);animation:ck-text-input-shake .3s ease both}.ck.ck-input-text.ck-error:focus{box-shadow:var(--ck-focus-error-outer-shadow),var(--ck-inner-shadow)}@keyframes ck-text-input-shake{20%{transform:translateX(-2px)}40%{transform:translateX(2px)}60%{transform:translateX(-1px)}80%{transform:translateX(1px)}}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./textalternativeform.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-text-alternative-form{display:flex;flex-direction:row;flex-wrap:nowrap}.ck.ck-text-alternative-form .ck-labeled-input{display:inline-block}.ck.ck-text-alternative-form .ck-label{display:none}@media screen and (max-width:600px){.ck.ck-text-alternative-form{flex-wrap:wrap}.ck.ck-text-alternative-form .ck-labeled-input{flex-basis:100%}.ck.ck-text-alternative-form .ck-button{flex-basis:50%}}.ck.ck-text-alternative-form{padding:var(--ck-spacing-standard)}.ck.ck-text-alternative-form:focus{outline:none}[dir=ltr] .ck.ck-text-alternative-form>:not(:first-child),[dir=rtl] .ck.ck-text-alternative-form>:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-text-alternative-form{padding:0;width:calc(0.8*var(--ck-input-text-width))}.ck.ck-text-alternative-form .ck-labeled-input{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) 0}.ck.ck-text-alternative-form .ck-labeled-input .ck-input-text{min-width:0;width:100%}.ck.ck-text-alternative-form .ck-button{padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-standard);border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border)}[dir=ltr] .ck.ck-text-alternative-form .ck-button{margin-left:0}[dir=ltr] .ck.ck-text-alternative-form .ck-button:first-of-type{border-right:1px solid var(--ck-color-base-border)}[dir=rtl] .ck.ck-text-alternative-form .ck-button{margin-left:0}[dir=rtl] .ck.ck-text-alternative-form .ck-button:last-of-type{border-right:1px solid var(--ck-color-base-border)}}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./balloonpanel.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \":root{--ck-balloon-panel-arrow-z-index:calc(var(--ck-z-default) - 3)}.ck.ck-balloon-panel{display:none;position:absolute;z-index:var(--ck-z-modal)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after,.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{content:\\\"\\\";position:absolute}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel[class*=arrow_n]:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel[class*=arrow_n]:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel[class*=arrow_s]:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel[class*=arrow_s]:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel.ck-balloon-panel_visible{display:block}:root{--ck-balloon-arrow-offset:2px;--ck-balloon-arrow-height:10px;--ck-balloon-arrow-half-width:8px}.ck.ck-balloon-panel{border-radius:0}.ck-rounded-corners .ck.ck-balloon-panel,.ck.ck-balloon-panel.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-balloon-panel{box-shadow:var(--ck-drop-shadow),0 0;min-height:15px;background:var(--ck-color-panel-background);border:1px solid var(--ck-color-panel-border)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after,.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{width:0;height:0;border-style:solid}.ck.ck-balloon-panel[class*=arrow_n]:after,.ck.ck-balloon-panel[class*=arrow_n]:before{border-left-width:var(--ck-balloon-arrow-half-width);border-bottom-width:var(--ck-balloon-arrow-height);border-right-width:var(--ck-balloon-arrow-half-width);border-top-width:0}.ck.ck-balloon-panel[class*=arrow_n]:before{border-bottom-color:var(--ck-color-panel-border)}.ck.ck-balloon-panel[class*=arrow_n]:after,.ck.ck-balloon-panel[class*=arrow_n]:before{border-left-color:transparent;border-right-color:transparent;border-top-color:transparent}.ck.ck-balloon-panel[class*=arrow_n]:after{border-bottom-color:var(--ck-color-panel-background);margin-top:var(--ck-balloon-arrow-offset)}.ck.ck-balloon-panel[class*=arrow_s]:after,.ck.ck-balloon-panel[class*=arrow_s]:before{border-left-width:var(--ck-balloon-arrow-half-width);border-bottom-width:0;border-right-width:var(--ck-balloon-arrow-half-width);border-top-width:var(--ck-balloon-arrow-height)}.ck.ck-balloon-panel[class*=arrow_s]:before{border-top-color:var(--ck-color-panel-border)}.ck.ck-balloon-panel[class*=arrow_s]:after,.ck.ck-balloon-panel[class*=arrow_s]:before{border-left-color:transparent;border-bottom-color:transparent;border-right-color:transparent}.ck.ck-balloon-panel[class*=arrow_s]:after{border-top-color:var(--ck-color-panel-background);margin-bottom:var(--ck-balloon-arrow-offset)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_n:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_n:before{left:50%;margin-left:calc(-1*var(--ck-balloon-arrow-half-width));top:calc(-1*var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_nw:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_nw:before{left:calc(2*var(--ck-balloon-arrow-half-width));top:calc(-1*var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_ne:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_ne:before{right:calc(2*var(--ck-balloon-arrow-half-width));top:calc(-1*var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_s:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_s:before{left:50%;margin-left:calc(-1*var(--ck-balloon-arrow-half-width));bottom:calc(-1*var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_sw:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_sw:before{left:calc(2*var(--ck-balloon-arrow-half-width));bottom:calc(-1*var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_se:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_se:before{right:calc(2*var(--ck-balloon-arrow-half-width));bottom:calc(-1*var(--ck-balloon-arrow-height))}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./balloonrotator.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck .ck-balloon-rotator__navigation{display:flex;align-items:center;justify-content:center}.ck .ck-balloon-rotator__content .ck-toolbar{justify-content:center}.ck .ck-balloon-rotator__navigation{background:var(--ck-color-toolbar-background);border-bottom:1px solid var(--ck-color-toolbar-border);padding:0 var(--ck-spacing-small)}.ck .ck-balloon-rotator__navigation>*{margin-right:var(--ck-spacing-small);margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small)}.ck .ck-balloon-rotator__navigation .ck-balloon-rotator__counter{margin-right:var(--ck-spacing-standard);margin-left:var(--ck-spacing-small)}.ck .ck-balloon-rotator__content .ck.ck-annotation-wrapper{box-shadow:none}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./fakepanel.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck .ck-fake-panel{position:absolute;z-index:calc(var(--ck-z-modal) - 1)}.ck .ck-fake-panel div{position:absolute}.ck .ck-fake-panel div:first-child{z-index:2}.ck .ck-fake-panel div:nth-child(2){z-index:1}:root{--ck-balloon-fake-panel-offset-horizontal:6px;--ck-balloon-fake-panel-offset-vertical:6px}.ck .ck-fake-panel div{box-shadow:var(--ck-drop-shadow),0 0;min-height:15px;background:var(--ck-color-panel-background);border:1px solid var(--ck-color-panel-border);border-radius:var(--ck-border-radius);width:100%;height:100%}.ck .ck-fake-panel div:first-child{margin-left:var(--ck-balloon-fake-panel-offset-horizontal);margin-top:var(--ck-balloon-fake-panel-offset-vertical)}.ck .ck-fake-panel div:nth-child(2){margin-left:calc(var(--ck-balloon-fake-panel-offset-horizontal)*2);margin-top:calc(var(--ck-balloon-fake-panel-offset-vertical)*2)}.ck .ck-fake-panel div:nth-child(3){margin-left:calc(var(--ck-balloon-fake-panel-offset-horizontal)*3);margin-top:calc(var(--ck-balloon-fake-panel-offset-vertical)*3)}.ck .ck-balloon-panel_arrow_s+.ck-fake-panel,.ck .ck-balloon-panel_arrow_se+.ck-fake-panel,.ck .ck-balloon-panel_arrow_sw+.ck-fake-panel{--ck-balloon-fake-panel-offset-vertical:-6px}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./image.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck-content .image{display:table;clear:both;text-align:center;margin:1em auto}.ck-content .image>img{display:block;margin:0 auto;max-width:100%;min-width:50px}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./imageuploadprogress.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-editor__editable .image{position:relative}.ck.ck-editor__editable .image .ck-progress-bar{position:absolute;top:0;left:0}.ck.ck-editor__editable .image.ck-appear{animation:fadeIn .7s}.ck.ck-editor__editable .image .ck-progress-bar{height:2px;width:0;background:var(--ck-color-upload-bar-background);transition:width .1s}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./imageuploadicon.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck-image-upload-complete-icon{display:block;position:absolute;top:10px;right:10px;border-radius:50%}.ck-image-upload-complete-icon:after{content:\\\"\\\";position:absolute}:root{--ck-color-image-upload-icon:#fff;--ck-color-image-upload-icon-background:#008a00;--ck-image-upload-icon-size:20px;--ck-image-upload-icon-width:2px}.ck-image-upload-complete-icon{width:var(--ck-image-upload-icon-size);height:var(--ck-image-upload-icon-size);opacity:0;background:var(--ck-color-image-upload-icon-background);animation-name:ck-upload-complete-icon-show,ck-upload-complete-icon-hide;animation-fill-mode:forwards,forwards;animation-duration:.5s,.5s;font-size:var(--ck-image-upload-icon-size);animation-delay:0ms,3s}.ck-image-upload-complete-icon:after{left:25%;top:50%;opacity:0;height:0;width:0;transform:scaleX(-1) rotate(135deg);transform-origin:left top;border-top:var(--ck-image-upload-icon-width) solid var(--ck-color-image-upload-icon);border-right:var(--ck-image-upload-icon-width) solid var(--ck-color-image-upload-icon);animation-name:ck-upload-complete-icon-check;animation-duration:.5s;animation-delay:.5s;animation-fill-mode:forwards;box-sizing:border-box}@keyframes ck-upload-complete-icon-show{0%{opacity:0}to{opacity:1}}@keyframes ck-upload-complete-icon-hide{0%{opacity:1}to{opacity:0}}@keyframes ck-upload-complete-icon-check{0%{opacity:1;width:0;height:0}33%{width:.3em;height:0}to{opacity:1;width:.3em;height:.45em}}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./imageuploadloader.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck .ck-upload-placeholder-loader{position:absolute;display:flex;align-items:center;justify-content:center;top:0;left:0}.ck .ck-upload-placeholder-loader:before{content:\\\"\\\";position:relative}:root{--ck-color-upload-placeholder-loader:#b3b3b3;--ck-upload-placeholder-loader-size:32px}.ck .ck-image-upload-placeholder{width:100%;margin:0}.ck .ck-upload-placeholder-loader{width:100%;height:100%}.ck .ck-upload-placeholder-loader:before{width:var(--ck-upload-placeholder-loader-size);height:var(--ck-upload-placeholder-loader-size);border-radius:50%;border-top:3px solid var(--ck-color-upload-placeholder-loader);border-right:2px solid transparent;animation:ck-upload-placeholder-loader 1s linear infinite}@keyframes ck-upload-placeholder-loader{to{transform:rotate(1turn)}}\"","module.exports = \".ck.ck-heading_heading1{font-size:20px}.ck.ck-heading_heading2{font-size:17px}.ck.ck-heading_heading3{font-size:14px}.ck[class*=ck-heading_heading]{font-weight:700}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__button .ck-button__label{width:8em}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__panel .ck-list__item{min-width:18em}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./imagecaption.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck-content .image>figcaption{display:table-caption;caption-side:bottom;word-break:break-word;color:#333;background-color:#f7f7f7;padding:.6em;font-size:.75em;outline-offset:-1px}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./imagestyle.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \":root{--ck-image-style-spacing:1.5em}.ck-content .image-style-align-center,.ck-content .image-style-align-left,.ck-content .image-style-align-right,.ck-content .image-style-side{max-width:50%}.ck-content .image-style-side{float:right;margin-left:var(--ck-image-style-spacing)}.ck-content .image-style-align-left{float:left;margin-right:var(--ck-image-style-spacing)}.ck-content .image-style-align-center{margin-left:auto;margin-right:auto}.ck-content .image-style-align-right{float:right;margin-left:var(--ck-image-style-spacing)}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./linkform.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-link-form{display:flex}.ck.ck-link-form .ck-label{display:none}@media screen and (max-width:600px){.ck.ck-link-form{flex-wrap:wrap}.ck.ck-link-form .ck-labeled-input{flex-basis:100%}.ck.ck-link-form .ck-button{flex-basis:50%}}.ck.ck-link-form_layout-vertical{display:block}.ck.ck-link-form{padding:var(--ck-spacing-standard)}.ck.ck-link-form:focus{outline:none}[dir=ltr] .ck.ck-link-form>:not(:first-child),[dir=rtl] .ck.ck-link-form>:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-link-form{padding:0;width:calc(0.8*var(--ck-input-text-width))}.ck.ck-link-form .ck-labeled-input{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) 0}.ck.ck-link-form .ck-labeled-input .ck-input-text{min-width:0;width:100%}.ck.ck-link-form .ck-button{padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-standard);border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border)}[dir=ltr] .ck.ck-link-form .ck-button{margin-left:0}[dir=ltr] .ck.ck-link-form .ck-button:first-of-type{border-right:1px solid var(--ck-color-base-border)}[dir=rtl] .ck.ck-link-form .ck-button{margin-left:0}[dir=rtl] .ck.ck-link-form .ck-button:last-of-type{border-right:1px solid var(--ck-color-base-border)}}.ck.ck-link-form_layout-vertical{padding:0;min-width:var(--ck-input-text-width)}.ck.ck-link-form_layout-vertical .ck-labeled-input{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) var(--ck-spacing-small)}.ck.ck-link-form_layout-vertical .ck-labeled-input .ck-input-text{min-width:0;width:100%}.ck.ck-link-form_layout-vertical .ck-button{padding:var(--ck-spacing-standard);margin:0;border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border);width:50%}[dir=ltr] .ck.ck-link-form_layout-vertical .ck-button{margin-left:0}[dir=ltr] .ck.ck-link-form_layout-vertical .ck-button:first-of-type{border-right:1px solid var(--ck-color-base-border)}[dir=rtl] .ck.ck-link-form_layout-vertical .ck-button{margin-left:0}[dir=rtl] .ck.ck-link-form_layout-vertical .ck-button:last-of-type{border-right:1px solid var(--ck-color-base-border)}.ck.ck-link-form_layout-vertical .ck.ck-list{margin-left:0}.ck.ck-link-form_layout-vertical .ck.ck-list .ck-button.ck-switchbutton{border:0;width:100%}.ck.ck-link-form_layout-vertical .ck.ck-list .ck-button.ck-switchbutton:hover{background:none}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./linkactions.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-link-actions{display:flex;flex-direction:row;flex-wrap:nowrap}.ck.ck-link-actions .ck-link-actions__preview{display:inline-block}.ck.ck-link-actions .ck-link-actions__preview .ck-button__label{overflow:hidden}@media screen and (max-width:600px){.ck.ck-link-actions{flex-wrap:wrap}.ck.ck-link-actions .ck-link-actions__preview{flex-basis:100%}.ck.ck-link-actions .ck-button:not(.ck-link-actions__preview){flex-basis:50%}}.ck.ck-link-actions{padding:var(--ck-spacing-standard)}.ck.ck-link-actions .ck-button.ck-link-actions__preview{padding-left:0;padding-right:0}.ck.ck-link-actions .ck-button.ck-link-actions__preview .ck-button__label{padding:0 var(--ck-spacing-medium);color:var(--ck-color-link-default);text-overflow:ellipsis;cursor:pointer;max-width:var(--ck-input-text-width);min-width:3em;text-align:center}.ck.ck-link-actions .ck-button.ck-link-actions__preview .ck-button__label:hover{text-decoration:underline}.ck.ck-link-actions .ck-button.ck-link-actions__preview,.ck.ck-link-actions .ck-button.ck-link-actions__preview:active,.ck.ck-link-actions .ck-button.ck-link-actions__preview:focus,.ck.ck-link-actions .ck-button.ck-link-actions__preview:hover{background:none}.ck.ck-link-actions .ck-button.ck-link-actions__preview:active{box-shadow:none}.ck.ck-link-actions .ck-button.ck-link-actions__preview:focus .ck-button__label{text-decoration:underline}.ck.ck-link-actions:focus{outline:none}[dir=ltr] .ck.ck-link-actions .ck-button:not(:first-child),[dir=rtl] .ck.ck-link-actions .ck-button:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-link-actions{padding:0;width:calc(0.8*var(--ck-input-text-width))}.ck.ck-link-actions .ck-button.ck-link-actions__preview{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) 0}.ck.ck-link-actions .ck-button.ck-link-actions__preview .ck-button__label{min-width:0;max-width:100%}.ck.ck-link-actions .ck-button:not(.ck-link-actions__preview){padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-standard);border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border)}[dir=ltr] .ck.ck-link-actions .ck-button:not(.ck-link-actions__preview){margin-left:0}[dir=ltr] .ck.ck-link-actions .ck-button:not(.ck-link-actions__preview):first-of-type{border-right:1px solid var(--ck-color-base-border)}[dir=rtl] .ck.ck-link-actions .ck-button:not(.ck-link-actions__preview){margin-left:0}[dir=rtl] .ck.ck-link-actions .ck-button:not(.ck-link-actions__preview):last-of-type{border-right:1px solid var(--ck-color-base-border)}}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./mediaembedediting.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck-media__wrapper .ck-media__placeholder{display:flex;flex-direction:column;align-items:center}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url .ck-tooltip{display:block}@media (hover:none){.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url .ck-tooltip{display:none}}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url{max-width:100%;position:relative}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url:hover .ck-tooltip{visibility:visible;opacity:1}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url .ck-media__placeholder__url__text{overflow:hidden;display:block}.ck-media__wrapper[data-oembed-url*=\\\"facebook.com\\\"] .ck-media__placeholder__icon *,.ck-media__wrapper[data-oembed-url*=\\\"google.com/maps\\\"] .ck-media__placeholder__icon *,.ck-media__wrapper[data-oembed-url*=\\\"instagram.com\\\"] .ck-media__placeholder__icon *,.ck-media__wrapper[data-oembed-url*=\\\"twitter.com\\\"] .ck-media__placeholder__icon *{display:none}.ck-editor__editable:not(.ck-read-only) .ck-media__wrapper>:not(.ck-media__placeholder),.ck-editor__editable:not(.ck-read-only) .ck-widget:not(.ck-widget_selected) .ck-media__placeholder{pointer-events:none}:root{--ck-media-embed-placeholder-icon-size:3em;--ck-color-media-embed-placeholder-url-text:#757575;--ck-color-media-embed-placeholder-url-text-hover:var(--ck-color-base-text)}.ck-media__wrapper{margin:0 auto}.ck-media__wrapper .ck-media__placeholder{padding:calc(3*var(--ck-spacing-standard));background:var(--ck-color-base-foreground)}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__icon{min-width:var(--ck-media-embed-placeholder-icon-size);height:var(--ck-media-embed-placeholder-icon-size);margin-bottom:var(--ck-spacing-large);background-position:50%;background-size:cover}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__icon .ck-icon{width:100%;height:100%}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url__text{color:var(--ck-color-media-embed-placeholder-url-text);white-space:nowrap;text-align:center;font-style:italic;text-overflow:ellipsis}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url__text:hover{color:var(--ck-color-media-embed-placeholder-url-text-hover);cursor:pointer;text-decoration:underline}.ck-media__wrapper[data-oembed-url*=\\\"open.spotify.com\\\"]{max-width:300px;max-height:380px}.ck-media__wrapper[data-oembed-url*=\\\"google.com/maps\\\"] .ck-media__placeholder__icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNTAuMzc4IiBoZWlnaHQ9IjI1NC4xNjciIHZpZXdCb3g9IjAgMCA2Ni4yNDYgNjcuMjQ4Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTcyLjUzMSAtMjE4LjQ1NSkgc2NhbGUoLjk4MDEyKSI+PHJlY3Qgcnk9IjUuMjM4IiByeD0iNS4yMzgiIHk9IjIzMS4zOTkiIHg9IjE3Ni4wMzEiIGhlaWdodD0iNjAuMDk5IiB3aWR0aD0iNjAuMDk5IiBmaWxsPSIjMzRhNjY4IiBwYWludC1vcmRlcj0ibWFya2VycyBzdHJva2UgZmlsbCIvPjxwYXRoIGQ9Ik0yMDYuNDc3IDI2MC45bC0yOC45ODcgMjguOTg3YTUuMjE4IDUuMjE4IDAgMDAzLjc4IDEuNjFoNDkuNjIxYzEuNjk0IDAgMy4xOS0uNzk4IDQuMTQ2LTIuMDM3eiIgZmlsbD0iIzVjODhjNSIvPjxwYXRoIGQ9Ik0yMjYuNzQyIDIyMi45ODhjLTkuMjY2IDAtMTYuNzc3IDcuMTctMTYuNzc3IDE2LjAxNC4wMDcgMi43NjIuNjYzIDUuNDc0IDIuMDkzIDcuODc1LjQzLjcwMy44MyAxLjQwOCAxLjE5IDIuMTA3LjMzMy41MDIuNjUgMS4wMDUuOTUgMS41MDguMzQzLjQ3Ny42NzMuOTU3Ljk4OCAxLjQ0IDEuMzEgMS43NjkgMi41IDMuNTAyIDMuNjM3IDUuMTY4Ljc5MyAxLjI3NSAxLjY4MyAyLjY0IDIuNDY2IDMuOTkgMi4zNjMgNC4wOTQgNC4wMDcgOC4wOTIgNC42IDEzLjkxNHYuMDEyYy4xODIuNDEyLjUxNi42NjYuODc5LjY2Ny40MDMtLjAwMS43NjgtLjMxNC45My0uNzk5LjYwMy01Ljc1NiAyLjIzOC05LjcyOSA0LjU4NS0xMy43OTQuNzgyLTEuMzUgMS42NzMtMi43MTUgMi40NjUtMy45OSAxLjEzNy0xLjY2NiAyLjMyOC0zLjQgMy42MzgtNS4xNjkuMzE1LS40ODIuNjQ1LS45NjIuOTg4LTEuNDM5LjMtLjUwMy42MTctMS4wMDYuOTUtMS41MDguMzU5LS43Ljc2LTEuNDA0IDEuMTktMi4xMDcgMS40MjYtMi40MDIgMi01LjExNCAyLjAwNC03Ljg3NSAwLTguODQ0LTcuNTExLTE2LjAxNC0xNi43NzYtMTYuMDE0eiIgZmlsbD0iI2RkNGIzZSIgcGFpbnQtb3JkZXI9Im1hcmtlcnMgc3Ryb2tlIGZpbGwiLz48ZWxsaXBzZSByeT0iNS41NjQiIHJ4PSI1LjgyOCIgY3k9IjIzOS4wMDIiIGN4PSIyMjYuNzQyIiBmaWxsPSIjODAyZDI3IiBwYWludC1vcmRlcj0ibWFya2VycyBzdHJva2UgZmlsbCIvPjxwYXRoIGQ9Ik0xOTAuMzAxIDIzNy4yODNjLTQuNjcgMC04LjQ1NyAzLjg1My04LjQ1NyA4LjYwNnMzLjc4NiA4LjYwNyA4LjQ1NyA4LjYwN2MzLjA0MyAwIDQuODA2LS45NTggNi4zMzctMi41MTYgMS41My0xLjU1NyAyLjA4Ny0zLjkxMyAyLjA4Ny02LjI5IDAtLjM2Mi0uMDIzLS43MjItLjA2NC0xLjA3OWgtOC4yNTd2My4wNDNoNC44NWMtLjE5Ny43NTktLjUzMSAxLjQ1LTEuMDU4IDEuOTg2LS45NDIuOTU4LTIuMDI4IDEuNTQ4LTMuOTAxIDEuNTQ4LTIuODc2IDAtNS4yMDgtMi4zNzItNS4yMDgtNS4yOTkgMC0yLjkyNiAyLjMzMi01LjI5OSA1LjIwOC01LjI5OSAxLjM5OSAwIDIuNjE4LjQwNyAzLjU4NCAxLjI5M2wyLjM4MS0yLjM4YzAtLjAwMi0uMDAzLS4wMDQtLjAwNC0uMDA1LTEuNTg4LTEuNTI0LTMuNjItMi4yMTUtNS45NTUtMi4yMTV6bTQuNDMgNS42NmwuMDAzLjAwNnYtLjAwM3oiIGZpbGw9IiNmZmYiIHBhaW50LW9yZGVyPSJtYXJrZXJzIHN0cm9rZSBmaWxsIi8+PHBhdGggZD0iTTIxNS4xODQgMjUxLjkyOWwtNy45OCA3Ljk3OSAyOC40NzcgMjguNDc1YTUuMjMzIDUuMjMzIDAgMDAuNDQ5LTIuMTIzdi0zMS4xNjVjLS40NjkuNjc1LS45MzQgMS4zNDktMS4zODIgMi4wMDUtLjc5MiAxLjI3NS0xLjY4MiAyLjY0LTIuNDY1IDMuOTktMi4zNDcgNC4wNjUtMy45ODIgOC4wMzgtNC41ODUgMTMuNzk0LS4xNjIuNDg1LS41MjcuNzk4LS45My43OTktLjM2My0uMDAxLS42OTctLjI1NS0uODc5LS42Njd2LS4wMTJjLS41OTMtNS44MjItMi4yMzctOS44Mi00LjYtMTMuOTE0LS43ODMtMS4zNS0xLjY3My0yLjcxNS0yLjQ2Ni0zLjk5LTEuMTM3LTEuNjY2LTIuMzI3LTMuNC0zLjYzNy01LjE2OWwtLjAwMi0uMDAzeiIgZmlsbD0iI2MzYzNjMyIvPjxwYXRoIGQ9Ik0yMTIuOTgzIDI0OC40OTVsLTM2Ljk1MiAzNi45NTN2LjgxMmE1LjIyNyA1LjIyNyAwIDAwNS4yMzggNS4yMzhoMS4wMTVsMzUuNjY2LTM1LjY2NmExMzYuMjc1IDEzNi4yNzUgMCAwMC0yLjc2NC0zLjkgMzcuNTc1IDM3LjU3NSAwIDAwLS45ODktMS40NCAzNS4xMjcgMzUuMTI3IDAgMDAtLjk1LTEuNTA4Yy0uMDgzLS4xNjItLjE3Ni0uMzI2LS4yNjQtLjQ4OXoiIGZpbGw9IiNmZGRjNGYiIHBhaW50LW9yZGVyPSJtYXJrZXJzIHN0cm9rZSBmaWxsIi8+PHBhdGggZD0iTTIxMS45OTggMjYxLjA4M2wtNi4xNTIgNi4xNTEgMjQuMjY0IDI0LjI2NGguNzgxYTUuMjI3IDUuMjI3IDAgMDA1LjIzOS01LjIzOHYtMS4wNDV6IiBmaWxsPSIjZmZmIiBwYWludC1vcmRlcj0ibWFya2VycyBzdHJva2UgZmlsbCIvPjwvZz48L3N2Zz4=)}.ck-media__wrapper[data-oembed-url*=\\\"facebook.com\\\"] .ck-media__placeholder{background:#4268b3}.ck-media__wrapper[data-oembed-url*=\\\"facebook.com\\\"] .ck-media__placeholder .ck-media__placeholder__icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAyNCIgaGVpZ2h0PSIxMDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik05NjcuNDg0IDBINTYuNTE3QzI1LjMwNCAwIDAgMjUuMzA0IDAgNTYuNTE3djkxMC45NjZDMCA5OTguNjk0IDI1LjI5NyAxMDI0IDU2LjUyMiAxMDI0SDU0N1Y2MjhINDE0VjQ3M2gxMzNWMzU5LjAyOWMwLTEzMi4yNjIgODAuNzczLTIwNC4yODIgMTk4Ljc1Ni0yMDQuMjgyIDU2LjUxMyAwIDEwNS4wODYgNC4yMDggMTE5LjI0NCA2LjA4OVYyOTlsLTgxLjYxNi4wMzdjLTYzLjk5MyAwLTc2LjM4NCAzMC40OTItNzYuMzg0IDc1LjIzNlY0NzNoMTUzLjQ4N2wtMTkuOTg2IDE1NUg3MDd2Mzk2aDI2MC40ODRjMzEuMjEzIDAgNTYuNTE2LTI1LjMwMyA1Ni41MTYtNTYuNTE2VjU2LjUxNUMxMDI0IDI1LjMwMyA5OTguNjk3IDAgOTY3LjQ4NCAwIiBmaWxsPSIjRkZGRkZFIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.ck-media__wrapper[data-oembed-url*=\\\"facebook.com\\\"] .ck-media__placeholder .ck-media__placeholder__url__text{color:#cdf}.ck-media__wrapper[data-oembed-url*=\\\"facebook.com\\\"] .ck-media__placeholder .ck-media__placeholder__url__text:hover{color:#fff}.ck-media__wrapper[data-oembed-url*=\\\"instagram.com\\\"] .ck-media__placeholder{background:linear-gradient(-135deg,#1400c8,#b900b4,#f50000)}.ck-media__wrapper[data-oembed-url*=\\\"instagram.com\\\"] .ck-media__placeholder .ck-media__placeholder__icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTA0IiBoZWlnaHQ9IjUwNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGRlZnM+PHBhdGggaWQ9ImEiIGQ9Ik0wIC4xNTloNTAzLjg0MVY1MDMuOTRIMHoiLz48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48bWFzayBpZD0iYiIgZmlsbD0iI2ZmZiI+PHVzZSB4bGluazpocmVmPSIjYSIvPjwvbWFzaz48cGF0aCBkPSJNMjUxLjkyMS4xNTljLTY4LjQxOCAwLTc2Ljk5Ny4yOS0xMDMuODY3IDEuNTE2LTI2LjgxNCAxLjIyMy00NS4xMjcgNS40ODItNjEuMTUxIDExLjcxLTE2LjU2NiA2LjQzNy0zMC42MTUgMTUuMDUxLTQ0LjYyMSAyOS4wNTYtMTQuMDA1IDE0LjAwNi0yMi42MTkgMjguMDU1LTI5LjA1NiA0NC42MjEtNi4yMjggMTYuMDI0LTEwLjQ4NyAzNC4zMzctMTEuNzEgNjEuMTUxQy4yOSAxNzUuMDgzIDAgMTgzLjY2MiAwIDI1Mi4wOGMwIDY4LjQxNy4yOSA3Ni45OTYgMS41MTYgMTAzLjg2NiAxLjIyMyAyNi44MTQgNS40ODIgNDUuMTI3IDExLjcxIDYxLjE1MSA2LjQzNyAxNi41NjYgMTUuMDUxIDMwLjYxNSAyOS4wNTYgNDQuNjIxIDE0LjAwNiAxNC4wMDUgMjguMDU1IDIyLjYxOSA0NC42MjEgMjkuMDU3IDE2LjAyNCA2LjIyNyAzNC4zMzcgMTAuNDg2IDYxLjE1MSAxMS43MDkgMjYuODcgMS4yMjYgMzUuNDQ5IDEuNTE2IDEwMy44NjcgMS41MTYgNjguNDE3IDAgNzYuOTk2LS4yOSAxMDMuODY2LTEuNTE2IDI2LjgxNC0xLjIyMyA0NS4xMjctNS40ODIgNjEuMTUxLTExLjcwOSAxNi41NjYtNi40MzggMzAuNjE1LTE1LjA1MiA0NC42MjEtMjkuMDU3IDE0LjAwNS0xNC4wMDYgMjIuNjE5LTI4LjA1NSAyOS4wNTctNDQuNjIxIDYuMjI3LTE2LjAyNCAxMC40ODYtMzQuMzM3IDExLjcwOS02MS4xNTEgMS4yMjYtMjYuODcgMS41MTYtMzUuNDQ5IDEuNTE2LTEwMy44NjYgMC02OC40MTgtLjI5LTc2Ljk5Ny0xLjUxNi0xMDMuODY3LTEuMjIzLTI2LjgxNC01LjQ4Mi00NS4xMjctMTEuNzA5LTYxLjE1MS02LjQzOC0xNi41NjYtMTUuMDUyLTMwLjYxNS0yOS4wNTctNDQuNjIxLTE0LjAwNi0xNC4wMDUtMjguMDU1LTIyLjYxOS00NC42MjEtMjkuMDU2LTE2LjAyNC02LjIyOC0zNC4zMzctMTAuNDg3LTYxLjE1MS0xMS43MUMzMjguOTE3LjQ0OSAzMjAuMzM4LjE1OSAyNTEuOTIxLjE1OXptMCA0NS4zOTFjNjcuMjY1IDAgNzUuMjMzLjI1NyAxMDEuNzk3IDEuNDY5IDI0LjU2MiAxLjEyIDM3LjkwMSA1LjIyNCA0Ni43NzggOC42NzQgMTEuNzU5IDQuNTcgMjAuMTUxIDEwLjAyOSAyOC45NjYgMTguODQ1IDguODE2IDguODE1IDE0LjI3NSAxNy4yMDcgMTguODQ1IDI4Ljk2NiAzLjQ1IDguODc3IDcuNTU0IDIyLjIxNiA4LjY3NCA0Ni43NzggMS4yMTIgMjYuNTY0IDEuNDY5IDM0LjUzMiAxLjQ2OSAxMDEuNzk4IDAgNjcuMjY1LS4yNTcgNzUuMjMzLTEuNDY5IDEwMS43OTctMS4xMiAyNC41NjItNS4yMjQgMzcuOTAxLTguNjc0IDQ2Ljc3OC00LjU3IDExLjc1OS0xMC4wMjkgMjAuMTUxLTE4Ljg0NSAyOC45NjYtOC44MTUgOC44MTYtMTcuMjA3IDE0LjI3NS0yOC45NjYgMTguODQ1LTguODc3IDMuNDUtMjIuMjE2IDcuNTU0LTQ2Ljc3OCA4LjY3NC0yNi41NiAxLjIxMi0zNC41MjcgMS40NjktMTAxLjc5NyAxLjQ2OS02Ny4yNzEgMC03NS4yMzctLjI1Ny0xMDEuNzk4LTEuNDY5LTI0LjU2Mi0xLjEyLTM3LjkwMS01LjIyNC00Ni43NzgtOC42NzQtMTEuNzU5LTQuNTctMjAuMTUxLTEwLjAyOS0yOC45NjYtMTguODQ1LTguODE1LTguODE1LTE0LjI3NS0xNy4yMDctMTguODQ1LTI4Ljk2Ni0zLjQ1LTguODc3LTcuNTU0LTIyLjIxNi04LjY3NC00Ni43NzgtMS4yMTItMjYuNTY0LTEuNDY5LTM0LjUzMi0xLjQ2OS0xMDEuNzk3IDAtNjcuMjY2LjI1Ny03NS4yMzQgMS40NjktMTAxLjc5OCAxLjEyLTI0LjU2MiA1LjIyNC0zNy45MDEgOC42NzQtNDYuNzc4IDQuNTctMTEuNzU5IDEwLjAyOS0yMC4xNTEgMTguODQ1LTI4Ljk2NiA4LjgxNS04LjgxNiAxNy4yMDctMTQuMjc1IDI4Ljk2Ni0xOC44NDUgOC44NzctMy40NSAyMi4yMTYtNy41NTQgNDYuNzc4LTguNjc0IDI2LjU2NC0xLjIxMiAzNC41MzItMS40NjkgMTAxLjc5OC0xLjQ2OXoiIGZpbGw9IiNGRkYiIG1hc2s9InVybCgjYikiLz48cGF0aCBkPSJNMjUxLjkyMSAzMzYuMDUzYy00Ni4zNzggMC04My45NzQtMzcuNTk2LTgzLjk3NC04My45NzMgMC00Ni4zNzggMzcuNTk2LTgzLjk3NCA4My45NzQtODMuOTc0IDQ2LjM3NyAwIDgzLjk3MyAzNy41OTYgODMuOTczIDgzLjk3NCAwIDQ2LjM3Ny0zNy41OTYgODMuOTczLTgzLjk3MyA4My45NzN6bTAtMjEzLjMzOGMtNzEuNDQ3IDAtMTI5LjM2NSA1Ny45MTgtMTI5LjM2NSAxMjkuMzY1IDAgNzEuNDQ2IDU3LjkxOCAxMjkuMzY0IDEyOS4zNjUgMTI5LjM2NCA3MS40NDYgMCAxMjkuMzY0LTU3LjkxOCAxMjkuMzY0LTEyOS4zNjQgMC03MS40NDctNTcuOTE4LTEyOS4zNjUtMTI5LjM2NC0xMjkuMzY1ek00MTYuNjI3IDExNy42MDRjMCAxNi42OTYtMTMuNTM1IDMwLjIzLTMwLjIzMSAzMC4yMy0xNi42OTUgMC0zMC4yMy0xMy41MzQtMzAuMjMtMzAuMjMgMC0xNi42OTYgMTMuNTM1LTMwLjIzMSAzMC4yMy0zMC4yMzEgMTYuNjk2IDAgMzAuMjMxIDEzLjUzNSAzMC4yMzEgMzAuMjMxIiBmaWxsPSIjRkZGIi8+PC9nPjwvc3ZnPg==)}.ck-media__wrapper[data-oembed-url*=\\\"instagram.com\\\"] .ck-media__placeholder .ck-media__placeholder__url__text{color:#ffe0fe}.ck-media__wrapper[data-oembed-url*=\\\"instagram.com\\\"] .ck-media__placeholder .ck-media__placeholder__url__text:hover{color:#fff}.ck-media__wrapper[data-oembed-url*=\\\"twitter.com\\\"] .ck.ck-media__placeholder{background:linear-gradient(90deg,#71c6f4,#0d70a5)}.ck-media__wrapper[data-oembed-url*=\\\"twitter.com\\\"] .ck.ck-media__placeholder .ck-media__placeholder__icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MDAgNDAwIj48cGF0aCBkPSJNNDAwIDIwMGMwIDExMC41LTg5LjUgMjAwLTIwMCAyMDBTMCAzMTAuNSAwIDIwMCA4OS41IDAgMjAwIDBzMjAwIDg5LjUgMjAwIDIwMHpNMTYzLjQgMzA1LjVjODguNyAwIDEzNy4yLTczLjUgMTM3LjItMTM3LjIgMC0yLjEgMC00LjItLjEtNi4yIDkuNC02LjggMTcuNi0xNS4zIDI0LjEtMjUtOC42IDMuOC0xNy45IDYuNC0yNy43IDcuNiAxMC02IDE3LjYtMTUuNCAyMS4yLTI2LjctOS4zIDUuNS0xOS42IDkuNS0zMC42IDExLjctOC44LTkuNC0yMS4zLTE1LjItMzUuMi0xNS4yLTI2LjYgMC00OC4yIDIxLjYtNDguMiA0OC4yIDAgMy44LjQgNy41IDEuMyAxMS00MC4xLTItNzUuNi0yMS4yLTk5LjQtNTAuNC00LjEgNy4xLTYuNSAxNS40LTYuNSAyNC4yIDAgMTYuNyA4LjUgMzEuNSAyMS41IDQwLjEtNy45LS4yLTE1LjMtMi40LTIxLjgtNnYuNmMwIDIzLjQgMTYuNiA0Mi44IDM4LjcgNDcuMy00IDEuMS04LjMgMS43LTEyLjcgMS43LTMuMSAwLTYuMS0uMy05LjEtLjkgNi4xIDE5LjIgMjMuOSAzMy4xIDQ1IDMzLjUtMTYuNSAxMi45LTM3LjMgMjAuNi01OS45IDIwLjYtMy45IDAtNy43LS4yLTExLjUtLjcgMjEuMSAxMy44IDQ2LjUgMjEuOCA3My43IDIxLjgiIGZpbGw9IiNmZmYiLz48L3N2Zz4=)}.ck-media__wrapper[data-oembed-url*=\\\"twitter.com\\\"] .ck.ck-media__placeholder .ck-media__placeholder__url__text{color:#b8e6ff}.ck-media__wrapper[data-oembed-url*=\\\"twitter.com\\\"] .ck.ck-media__placeholder .ck-media__placeholder__url__text:hover{color:#fff}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./mediaform.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-media-form{display:flex;align-items:flex-start;flex-direction:row;flex-wrap:nowrap}.ck.ck-media-form .ck-labeled-input{display:inline-block}.ck.ck-media-form .ck-label{display:none}@media screen and (max-width:600px){.ck.ck-media-form{flex-wrap:wrap}.ck.ck-media-form .ck-labeled-input{flex-basis:100%}.ck.ck-media-form .ck-button{flex-basis:50%}}.ck.ck-media-form{padding:var(--ck-spacing-standard)}.ck.ck-media-form:focus{outline:none}[dir=ltr] .ck.ck-media-form>:not(:first-child),[dir=rtl] .ck.ck-media-form>:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-media-form{padding:0;width:calc(0.8*var(--ck-input-text-width))}.ck.ck-media-form .ck-labeled-input{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) 0}.ck.ck-media-form .ck-labeled-input .ck-input-text{min-width:0;width:100%}.ck.ck-media-form .ck-labeled-input .ck-labeled-input__error{white-space:normal}.ck.ck-media-form .ck-button{padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-standard);border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border)}[dir=ltr] .ck.ck-media-form .ck-button{margin-left:0}[dir=ltr] .ck.ck-media-form .ck-button:first-of-type{border-right:1px solid var(--ck-color-base-border)}[dir=rtl] .ck.ck-media-form .ck-button{margin-left:0}[dir=rtl] .ck.ck-media-form .ck-button:last-of-type{border-right:1px solid var(--ck-color-base-border)}}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./mediaembed.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck-content .media{clear:both;margin:1em 0;display:block;min-width:15em}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./tableediting.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \":root{--ck-color-table-focused-cell-background:#f5fafe}.ck-widget.table td.ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck-widget.table th.ck-editor__nested-editable.ck-editor__nested-editable_focused{background:var(--ck-color-table-focused-cell-background);border-style:none;outline:1px solid var(--ck-color-focus-border);outline-offset:-1px}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./inserttable.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck .ck-insert-table-dropdown__grid{display:flex;flex-direction:row;flex-wrap:wrap}:root{--ck-insert-table-dropdown-padding:10px;--ck-insert-table-dropdown-box-height:11px;--ck-insert-table-dropdown-box-width:12px;--ck-insert-table-dropdown-box-margin:1px}.ck .ck-insert-table-dropdown__grid{width:calc(var(--ck-insert-table-dropdown-box-width)*10 + var(--ck-insert-table-dropdown-box-margin)*20 + var(--ck-insert-table-dropdown-padding)*2);padding:var(--ck-insert-table-dropdown-padding) var(--ck-insert-table-dropdown-padding) 0}.ck .ck-insert-table-dropdown__label{text-align:center}.ck .ck-insert-table-dropdown-grid-box{width:var(--ck-insert-table-dropdown-box-width);height:var(--ck-insert-table-dropdown-box-height);margin:var(--ck-insert-table-dropdown-box-margin);border:1px solid var(--ck-color-base-border);border-radius:1px}.ck .ck-insert-table-dropdown-grid-box.ck-on{border-color:var(--ck-color-focus-border);background:var(--ck-color-focus-outer-shadow)}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./table.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck-content .table{margin:1em auto;display:table}.ck-content .table table{border-collapse:collapse;border-spacing:0;width:100%;height:100%;border:1px double #b3b3b3}.ck-content .table table td,.ck-content .table table th{min-width:2em;padding:.4em;border-color:#d9d9d9}.ck-content .table table th{font-weight:700;background:#fafafa}\"","module.exports = \".ck-content code{background-color:hsla(0,0%,78%,.3);padding:.15em;border-radius:2px}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./horizontalline.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck-editor__editable .ck-horizontal-line{overflow:hidden}.ck-content hr{border:solid #5e5e5e;border-width:1px 0 0;margin:0}.ck-editor__editable .ck-horizontal-line{padding:5px 0}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./widgetresize.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck .ck-widget_with-resizer{position:relative}.ck .ck-widget__resizer{display:none;position:absolute;pointer-events:none;left:0;top:0;outline:1px solid var(--ck-color-resizer)}.ck-focused .ck-widget_with-resizer.ck-widget_selected>.ck-widget__resizer{display:block}.ck .ck-widget__resizer__handle{position:absolute;pointer-events:all;width:var(--ck-resizer-size);height:var(--ck-resizer-size);background:var(--ck-color-focus-border);border:var(--ck-resizer-border-width) solid #fff;border-radius:var(--ck-resizer-border-radius)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-left{top:var(--ck-resizer-offset);left:var(--ck-resizer-offset);cursor:nwse-resize}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-right{top:var(--ck-resizer-offset);right:var(--ck-resizer-offset);cursor:nesw-resize}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-right{bottom:var(--ck-resizer-offset);right:var(--ck-resizer-offset);cursor:nwse-resize}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-left{bottom:var(--ck-resizer-offset);left:var(--ck-resizer-offset);cursor:nesw-resize}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./imageresize.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck-content .image.image_resized{max-width:100%;display:block;box-sizing:border-box}.ck-content .image.image_resized img{width:100%}.ck-content .image.image_resized>figcaption{display:block}\"","var api = require(\"!../../../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../postcss-loader/src/index.js??ref--5-1!./colorgrid.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck.ck-color-grid{display:grid}:root{--ck-color-grid-tile-size:24px;--ck-color-color-grid-check-icon:#000}.ck.ck-color-grid{grid-gap:5px;padding:8px}.ck.ck-color-grid__tile{width:var(--ck-color-grid-tile-size);height:var(--ck-color-grid-tile-size);min-width:var(--ck-color-grid-tile-size);min-height:var(--ck-color-grid-tile-size);padding:0;transition:box-shadow .2s ease;border:0}.ck.ck-color-grid__tile.ck-disabled{cursor:unset;transition:unset}.ck.ck-color-grid__tile.ck-color-table__color-tile_bordered{box-shadow:0 0 0 1px var(--ck-color-base-border)}.ck.ck-color-grid__tile .ck.ck-icon{display:none;color:var(--ck-color-color-grid-check-icon)}.ck.ck-color-grid__tile.ck-on{box-shadow:inset 0 0 0 1px var(--ck-color-base-background),0 0 0 2px var(--ck-color-base-text)}.ck.ck-color-grid__tile.ck-on .ck.ck-icon{display:block}.ck.ck-color-grid__tile.ck-on,.ck.ck-color-grid__tile:focus:not(.ck-disabled),.ck.ck-color-grid__tile:hover:not(.ck-disabled){border:0}.ck.ck-color-grid__tile:focus:not(.ck-disabled),.ck.ck-color-grid__tile:hover:not(.ck-disabled){box-shadow:inset 0 0 0 1px var(--ck-color-base-background),0 0 0 2px var(--ck-color-focus-border)}.ck.ck-color-grid__label{padding:0 var(--ck-spacing-standard)}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./fontcolor.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".ck .ck-button.ck-color-table__remove-color{display:flex;align-items:center;width:100%}label.ck.ck-color-grid__label{font-weight:unset}.ck .ck-button.ck-color-table__remove-color{padding:calc(var(--ck-spacing-standard)/2) var(--ck-spacing-standard);border-bottom-left-radius:0;border-bottom-right-radius:0}.ck .ck-button.ck-color-table__remove-color:not(:focus){border-bottom:1px solid var(--ck-color-base-border)}[dir=ltr] .ck .ck-button.ck-color-table__remove-color .ck.ck-icon{margin-right:var(--ck-spacing-standard)}[dir=rtl] .ck .ck-button.ck-color-table__remove-color .ck.ck-icon{margin-left:var(--ck-spacing-standard)}\"","var api = require(\"!../../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../postcss-loader/src/index.js??ref--5-1!./fontsize.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\"};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\nvar exported = content.locals ? content.locals : {};\n\n\n\nmodule.exports = exported;","module.exports = \".text-tiny{font-size:.7em}.text-small{font-size:.85em}.text-big{font-size:1.4em}.text-huge{font-size:1.8em}\"","import root from './_root.js';\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nexport default Symbol;\n","import Symbol from './_Symbol.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nexport default getRawTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","import Symbol from './_Symbol.js';\nimport getRawTag from './_getRawTag.js';\nimport objectToString from './_objectToString.js';\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nexport default baseGetTag;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","import overArg from './_overArg.js';\n\n/** Built-in value references. */\nvar getPrototype = overArg(Object.getPrototypeOf, Object);\n\nexport default getPrototype;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","import baseGetTag from './_baseGetTag.js';\nimport getPrototype from './_getPrototype.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar objectTag = '[object Object]';\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to infer the `Object` constructor. */\nvar objectCtorString = funcToString.call(Object);\n\n/**\n * Checks if `value` is a plain object, that is, an object created by the\n * `Object` constructor or one with a `[[Prototype]]` of `null`.\n *\n * @static\n * @memberOf _\n * @since 0.8.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * _.isPlainObject(new Foo);\n * // => false\n *\n * _.isPlainObject([1, 2, 3]);\n * // => false\n *\n * _.isPlainObject({ 'x': 0, 'y': 0 });\n * // => true\n *\n * _.isPlainObject(Object.create(null));\n * // => true\n */\nfunction isPlainObject(value) {\n if (!isObjectLike(value) || baseGetTag(value) != objectTag) {\n return false;\n }\n var proto = getPrototype(value);\n if (proto === null) {\n return true;\n }\n var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;\n return typeof Ctor == 'function' && Ctor instanceof Ctor &&\n funcToString.call(Ctor) == objectCtorString;\n}\n\nexport default isPlainObject;\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","import eq from './eq.js';\n\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n var length = array.length;\n while (length--) {\n if (eq(array[length][0], key)) {\n return length;\n }\n }\n return -1;\n}\n\nexport default assocIndexOf;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype;\n\n/** Built-in value references. */\nvar splice = arrayProto.splice;\n\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n return false;\n }\n var lastIndex = data.length - 1;\n if (index == lastIndex) {\n data.pop();\n } else {\n splice.call(data, index, 1);\n }\n --this.size;\n return true;\n}\n\nexport default listCacheDelete;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n return index < 0 ? undefined : data[index][1];\n}\n\nexport default listCacheGet;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n return assocIndexOf(this.__data__, key) > -1;\n}\n\nexport default listCacheHas;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n ++this.size;\n data.push([key, value]);\n } else {\n data[index][1] = value;\n }\n return this;\n}\n\nexport default listCacheSet;\n","import listCacheClear from './_listCacheClear.js';\nimport listCacheDelete from './_listCacheDelete.js';\nimport listCacheGet from './_listCacheGet.js';\nimport listCacheHas from './_listCacheHas.js';\nimport listCacheSet from './_listCacheSet.js';\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\nexport default ListCache;\n","import ListCache from './_ListCache.js';\n\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n this.__data__ = new ListCache;\n this.size = 0;\n}\n\nexport default stackClear;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","import baseGetTag from './_baseGetTag.js';\nimport isObject from './isObject.js';\n\n/** `Object#toString` result references. */\nvar asyncTag = '[object AsyncFunction]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n proxyTag = '[object Proxy]';\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n if (!isObject(value)) {\n return false;\n }\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\nexport default isFunction;\n","import coreJsData from './_coreJsData.js';\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n return !!maskSrcKey && (maskSrcKey in func);\n}\n\nexport default isMasked;\n","import root from './_root.js';\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\nexport default coreJsData;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","import isFunction from './isFunction.js';\nimport isMasked from './_isMasked.js';\nimport isObject from './isObject.js';\nimport toSource from './_toSource.js';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n * else `false`.\n */\nfunction baseIsNative(value) {\n if (!isObject(value) || isMasked(value)) {\n return false;\n }\n var pattern = isFunction(value) ? reIsNative : reIsHostCtor;\n return pattern.test(toSource(value));\n}\n\nexport default baseIsNative;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","import baseIsNative from './_baseIsNative.js';\nimport getValue from './_getValue.js';\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n var value = getValue(object, key);\n return baseIsNative(value) ? value : undefined;\n}\n\nexport default getNative;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Map = getNative(root, 'Map');\n\nexport default Map;\n","import getNative from './_getNative.js';\n\n/* Built-in method references that are verified to be native. */\nvar nativeCreate = getNative(Object, 'create');\n\nexport default nativeCreate;\n","import nativeCreate from './_nativeCreate.js';\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n this.__data__ = nativeCreate ? nativeCreate(null) : {};\n this.size = 0;\n}\n\nexport default hashClear;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n var data = this.__data__;\n if (nativeCreate) {\n var result = data[key];\n return result === HASH_UNDEFINED ? undefined : result;\n }\n return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\nexport default hashGet;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n var data = this.__data__;\n return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);\n}\n\nexport default hashHas;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n var data = this.__data__;\n this.size += this.has(key) ? 0 : 1;\n data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n return this;\n}\n\nexport default hashSet;\n","import hashClear from './_hashClear.js';\nimport hashDelete from './_hashDelete.js';\nimport hashGet from './_hashGet.js';\nimport hashHas from './_hashHas.js';\nimport hashSet from './_hashSet.js';\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\nexport default Hash;\n","import Hash from './_Hash.js';\nimport ListCache from './_ListCache.js';\nimport Map from './_Map.js';\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n this.size = 0;\n this.__data__ = {\n 'hash': new Hash,\n 'map': new (Map || ListCache),\n 'string': new Hash\n };\n}\n\nexport default mapCacheClear;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","import isKeyable from './_isKeyable.js';\n\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n var data = map.__data__;\n return isKeyable(key)\n ? data[typeof key == 'string' ? 'string' : 'hash']\n : data.map;\n}\n\nexport default getMapData;\n","import getMapData from './_getMapData.js';\n\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n var result = getMapData(this, key)['delete'](key);\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default mapCacheDelete;\n","import getMapData from './_getMapData.js';\n\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n return getMapData(this, key).get(key);\n}\n\nexport default mapCacheGet;\n","import getMapData from './_getMapData.js';\n\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n return getMapData(this, key).has(key);\n}\n\nexport default mapCacheHas;\n","import getMapData from './_getMapData.js';\n\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n var data = getMapData(this, key),\n size = data.size;\n\n data.set(key, value);\n this.size += data.size == size ? 0 : 1;\n return this;\n}\n\nexport default mapCacheSet;\n","import mapCacheClear from './_mapCacheClear.js';\nimport mapCacheDelete from './_mapCacheDelete.js';\nimport mapCacheGet from './_mapCacheGet.js';\nimport mapCacheHas from './_mapCacheHas.js';\nimport mapCacheSet from './_mapCacheSet.js';\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\nexport default MapCache;\n","import ListCache from './_ListCache.js';\nimport Map from './_Map.js';\nimport MapCache from './_MapCache.js';\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/**\n * Sets the stack `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n var data = this.__data__;\n if (data instanceof ListCache) {\n var pairs = data.__data__;\n if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n pairs.push([key, value]);\n this.size = ++data.size;\n return this;\n }\n data = this.__data__ = new MapCache(pairs);\n }\n data.set(key, value);\n this.size = data.size;\n return this;\n}\n\nexport default stackSet;\n","import ListCache from './_ListCache.js';\nimport stackClear from './_stackClear.js';\nimport stackDelete from './_stackDelete.js';\nimport stackGet from './_stackGet.js';\nimport stackHas from './_stackHas.js';\nimport stackSet from './_stackSet.js';\n\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n var data = this.__data__ = new ListCache(entries);\n this.size = data.size;\n}\n\n// Add methods to `Stack`.\nStack.prototype.clear = stackClear;\nStack.prototype['delete'] = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n\nexport default Stack;\n","/**\n * A specialized version of `_.forEach` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns `array`.\n */\nfunction arrayEach(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (iteratee(array[index], index, array) === false) {\n break;\n }\n }\n return array;\n}\n\nexport default arrayEach;\n","import getNative from './_getNative.js';\n\nvar defineProperty = (function() {\n try {\n var func = getNative(Object, 'defineProperty');\n func({}, '', {});\n return func;\n } catch (e) {}\n}());\n\nexport default defineProperty;\n","import defineProperty from './_defineProperty.js';\n\n/**\n * The base implementation of `assignValue` and `assignMergeValue` without\n * value checks.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction baseAssignValue(object, key, value) {\n if (key == '__proto__' && defineProperty) {\n defineProperty(object, key, {\n 'configurable': true,\n 'enumerable': true,\n 'value': value,\n 'writable': true\n });\n } else {\n object[key] = value;\n }\n}\n\nexport default baseAssignValue;\n","import baseAssignValue from './_baseAssignValue.js';\nimport eq from './eq.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Assigns `value` to `key` of `object` if the existing value is not equivalent\n * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction assignValue(object, key, value) {\n var objValue = object[key];\n if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||\n (value === undefined && !(key in object))) {\n baseAssignValue(object, key, value);\n }\n}\n\nexport default assignValue;\n","import assignValue from './_assignValue.js';\nimport baseAssignValue from './_baseAssignValue.js';\n\n/**\n * Copies properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy properties from.\n * @param {Array} props The property identifiers to copy.\n * @param {Object} [object={}] The object to copy properties to.\n * @param {Function} [customizer] The function to customize copied values.\n * @returns {Object} Returns `object`.\n */\nfunction copyObject(source, props, object, customizer) {\n var isNew = !object;\n object || (object = {});\n\n var index = -1,\n length = props.length;\n\n while (++index < length) {\n var key = props[index];\n\n var newValue = customizer\n ? customizer(object[key], source[key], key, object, source)\n : undefined;\n\n if (newValue === undefined) {\n newValue = source[key];\n }\n if (isNew) {\n baseAssignValue(object, key, newValue);\n } else {\n assignValue(object, key, newValue);\n }\n }\n return object;\n}\n\nexport default copyObject;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]';\n\n/**\n * The base implementation of `_.isArguments`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n */\nfunction baseIsArguments(value) {\n return isObjectLike(value) && baseGetTag(value) == argsTag;\n}\n\nexport default baseIsArguments;\n","import baseIsArguments from './_baseIsArguments.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n * else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nvar isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&\n !propertyIsEnumerable.call(value, 'callee');\n};\n\nexport default isArguments;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","import baseGetTag from './_baseGetTag.js';\nimport isLength from './isLength.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n funcTag = '[object Function]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n objectTag = '[object Object]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values of typed arrays. */\nvar typedArrayTags = {};\ntypedArrayTags[float32Tag] = typedArrayTags[float64Tag] =\ntypedArrayTags[int8Tag] = typedArrayTags[int16Tag] =\ntypedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =\ntypedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =\ntypedArrayTags[uint32Tag] = true;\ntypedArrayTags[argsTag] = typedArrayTags[arrayTag] =\ntypedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =\ntypedArrayTags[dataViewTag] = typedArrayTags[dateTag] =\ntypedArrayTags[errorTag] = typedArrayTags[funcTag] =\ntypedArrayTags[mapTag] = typedArrayTags[numberTag] =\ntypedArrayTags[objectTag] = typedArrayTags[regexpTag] =\ntypedArrayTags[setTag] = typedArrayTags[stringTag] =\ntypedArrayTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.isTypedArray` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n */\nfunction baseIsTypedArray(value) {\n return isObjectLike(value) &&\n isLength(value.length) && !!typedArrayTags[baseGetTag(value)];\n}\n\nexport default baseIsTypedArray;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","import baseIsTypedArray from './_baseIsTypedArray.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;\n\n/**\n * Checks if `value` is classified as a typed array.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n * @example\n *\n * _.isTypedArray(new Uint8Array);\n * // => true\n *\n * _.isTypedArray([]);\n * // => false\n */\nvar isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;\n\nexport default isTypedArray;\n","import baseTimes from './_baseTimes.js';\nimport isArguments from './isArguments.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isIndex from './_isIndex.js';\nimport isTypedArray from './isTypedArray.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n var isArr = isArray(value),\n isArg = !isArr && isArguments(value),\n isBuff = !isArr && !isArg && isBuffer(value),\n isType = !isArr && !isArg && !isBuff && isTypedArray(value),\n skipIndexes = isArr || isArg || isBuff || isType,\n result = skipIndexes ? baseTimes(value.length, String) : [],\n length = result.length;\n\n for (var key in value) {\n if ((inherited || hasOwnProperty.call(value, key)) &&\n !(skipIndexes && (\n // Safari 9 has enumerable `arguments.length` in strict mode.\n key == 'length' ||\n // Node.js 0.10 has enumerable non-index properties on buffers.\n (isBuff && (key == 'offset' || key == 'parent')) ||\n // PhantomJS 2 has enumerable non-index properties on typed arrays.\n (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||\n // Skip index properties.\n isIndex(key, length)\n ))) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default arrayLikeKeys;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","import overArg from './_overArg.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeKeys = overArg(Object.keys, Object);\n\nexport default nativeKeys;\n","import isPrototype from './_isPrototype.js';\nimport nativeKeys from './_nativeKeys.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n if (!isPrototype(object)) {\n return nativeKeys(object);\n }\n var result = [];\n for (var key in Object(object)) {\n if (hasOwnProperty.call(object, key) && key != 'constructor') {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default baseKeys;\n","import isFunction from './isFunction.js';\nimport isLength from './isLength.js';\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n return value != null && isLength(value.length) && !isFunction(value);\n}\n\nexport default isArrayLike;\n","import arrayLikeKeys from './_arrayLikeKeys.js';\nimport baseKeys from './_baseKeys.js';\nimport isArrayLike from './isArrayLike.js';\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\nexport default keys;\n","import copyObject from './_copyObject.js';\nimport keys from './keys.js';\n\n/**\n * The base implementation of `_.assign` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssign(object, source) {\n return object && copyObject(source, keys(source), object);\n}\n\nexport default baseAssign;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","import isObject from './isObject.js';\nimport isPrototype from './_isPrototype.js';\nimport nativeKeysIn from './_nativeKeysIn.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeysIn(object) {\n if (!isObject(object)) {\n return nativeKeysIn(object);\n }\n var isProto = isPrototype(object),\n result = [];\n\n for (var key in object) {\n if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default baseKeysIn;\n","import arrayLikeKeys from './_arrayLikeKeys.js';\nimport baseKeysIn from './_baseKeysIn.js';\nimport isArrayLike from './isArrayLike.js';\n\n/**\n * Creates an array of the own and inherited enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keysIn(new Foo);\n * // => ['a', 'b', 'c'] (iteration order is not guaranteed)\n */\nfunction keysIn(object) {\n return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);\n}\n\nexport default keysIn;\n","import copyObject from './_copyObject.js';\nimport keysIn from './keysIn.js';\n\n/**\n * The base implementation of `_.assignIn` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssignIn(object, source) {\n return object && copyObject(source, keysIn(source), object);\n}\n\nexport default baseAssignIn;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nexport default stubArray;\n","import arrayFilter from './_arrayFilter.js';\nimport stubArray from './stubArray.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = !nativeGetSymbols ? stubArray : function(object) {\n if (object == null) {\n return [];\n }\n object = Object(object);\n return arrayFilter(nativeGetSymbols(object), function(symbol) {\n return propertyIsEnumerable.call(object, symbol);\n });\n};\n\nexport default getSymbols;\n","import copyObject from './_copyObject.js';\nimport getSymbols from './_getSymbols.js';\n\n/**\n * Copies own symbols of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbols(source, object) {\n return copyObject(source, getSymbols(source), object);\n}\n\nexport default copySymbols;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nexport default arrayPush;\n","import arrayPush from './_arrayPush.js';\nimport getPrototype from './_getPrototype.js';\nimport getSymbols from './_getSymbols.js';\nimport stubArray from './stubArray.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own and inherited enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {\n var result = [];\n while (object) {\n arrayPush(result, getSymbols(object));\n object = getPrototype(object);\n }\n return result;\n};\n\nexport default getSymbolsIn;\n","import copyObject from './_copyObject.js';\nimport getSymbolsIn from './_getSymbolsIn.js';\n\n/**\n * Copies own and inherited symbols of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbolsIn(source, object) {\n return copyObject(source, getSymbolsIn(source), object);\n}\n\nexport default copySymbolsIn;\n","import arrayPush from './_arrayPush.js';\nimport isArray from './isArray.js';\n\n/**\n * The base implementation of `getAllKeys` and `getAllKeysIn` which uses\n * `keysFunc` and `symbolsFunc` to get the enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @param {Function} symbolsFunc The function to get the symbols of `object`.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n var result = keysFunc(object);\n return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n\nexport default baseGetAllKeys;\n","import baseGetAllKeys from './_baseGetAllKeys.js';\nimport getSymbols from './_getSymbols.js';\nimport keys from './keys.js';\n\n/**\n * Creates an array of own enumerable property names and symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n return baseGetAllKeys(object, keys, getSymbols);\n}\n\nexport default getAllKeys;\n","import baseGetAllKeys from './_baseGetAllKeys.js';\nimport getSymbolsIn from './_getSymbolsIn.js';\nimport keysIn from './keysIn.js';\n\n/**\n * Creates an array of own and inherited enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeysIn(object) {\n return baseGetAllKeys(object, keysIn, getSymbolsIn);\n}\n\nexport default getAllKeysIn;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView');\n\nexport default DataView;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Promise = getNative(root, 'Promise');\n\nexport default Promise;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Set = getNative(root, 'Set');\n\nexport default Set;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar WeakMap = getNative(root, 'WeakMap');\n\nexport default WeakMap;\n","import DataView from './_DataView.js';\nimport Map from './_Map.js';\nimport Promise from './_Promise.js';\nimport Set from './_Set.js';\nimport WeakMap from './_WeakMap.js';\nimport baseGetTag from './_baseGetTag.js';\nimport toSource from './_toSource.js';\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]',\n objectTag = '[object Object]',\n promiseTag = '[object Promise]',\n setTag = '[object Set]',\n weakMapTag = '[object WeakMap]';\n\nvar dataViewTag = '[object DataView]';\n\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView),\n mapCtorString = toSource(Map),\n promiseCtorString = toSource(Promise),\n setCtorString = toSource(Set),\n weakMapCtorString = toSource(WeakMap);\n\n/**\n * Gets the `toStringTag` of `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nvar getTag = baseGetTag;\n\n// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n (Map && getTag(new Map) != mapTag) ||\n (Promise && getTag(Promise.resolve()) != promiseTag) ||\n (Set && getTag(new Set) != setTag) ||\n (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n getTag = function(value) {\n var result = baseGetTag(value),\n Ctor = result == objectTag ? value.constructor : undefined,\n ctorString = Ctor ? toSource(Ctor) : '';\n\n if (ctorString) {\n switch (ctorString) {\n case dataViewCtorString: return dataViewTag;\n case mapCtorString: return mapTag;\n case promiseCtorString: return promiseTag;\n case setCtorString: return setTag;\n case weakMapCtorString: return weakMapTag;\n }\n }\n return result;\n };\n}\n\nexport default getTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Initializes an array clone.\n *\n * @private\n * @param {Array} array The array to clone.\n * @returns {Array} Returns the initialized clone.\n */\nfunction initCloneArray(array) {\n var length = array.length,\n result = new array.constructor(length);\n\n // Add properties assigned by `RegExp#exec`.\n if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {\n result.index = array.index;\n result.input = array.input;\n }\n return result;\n}\n\nexport default initCloneArray;\n","import root from './_root.js';\n\n/** Built-in value references. */\nvar Uint8Array = root.Uint8Array;\n\nexport default Uint8Array;\n","import Uint8Array from './_Uint8Array.js';\n\n/**\n * Creates a clone of `arrayBuffer`.\n *\n * @private\n * @param {ArrayBuffer} arrayBuffer The array buffer to clone.\n * @returns {ArrayBuffer} Returns the cloned array buffer.\n */\nfunction cloneArrayBuffer(arrayBuffer) {\n var result = new arrayBuffer.constructor(arrayBuffer.byteLength);\n new Uint8Array(result).set(new Uint8Array(arrayBuffer));\n return result;\n}\n\nexport default cloneArrayBuffer;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\n\n/**\n * Creates a clone of `dataView`.\n *\n * @private\n * @param {Object} dataView The data view to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned data view.\n */\nfunction cloneDataView(dataView, isDeep) {\n var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;\n return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);\n}\n\nexport default cloneDataView;\n","/** Used to match `RegExp` flags from their coerced string values. */\nvar reFlags = /\\w*$/;\n\n/**\n * Creates a clone of `regexp`.\n *\n * @private\n * @param {Object} regexp The regexp to clone.\n * @returns {Object} Returns the cloned regexp.\n */\nfunction cloneRegExp(regexp) {\n var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));\n result.lastIndex = regexp.lastIndex;\n return result;\n}\n\nexport default cloneRegExp;\n","import Symbol from './_Symbol.js';\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * Creates a clone of the `symbol` object.\n *\n * @private\n * @param {Object} symbol The symbol object to clone.\n * @returns {Object} Returns the cloned symbol object.\n */\nfunction cloneSymbol(symbol) {\n return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};\n}\n\nexport default cloneSymbol;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\n\n/**\n * Creates a clone of `typedArray`.\n *\n * @private\n * @param {Object} typedArray The typed array to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned typed array.\n */\nfunction cloneTypedArray(typedArray, isDeep) {\n var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;\n return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);\n}\n\nexport default cloneTypedArray;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\nimport cloneDataView from './_cloneDataView.js';\nimport cloneRegExp from './_cloneRegExp.js';\nimport cloneSymbol from './_cloneSymbol.js';\nimport cloneTypedArray from './_cloneTypedArray.js';\n\n/** `Object#toString` result references. */\nvar boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/**\n * Initializes an object clone based on its `toStringTag`.\n *\n * **Note:** This function only supports cloning values with tags of\n * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.\n *\n * @private\n * @param {Object} object The object to clone.\n * @param {string} tag The `toStringTag` of the object to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneByTag(object, tag, isDeep) {\n var Ctor = object.constructor;\n switch (tag) {\n case arrayBufferTag:\n return cloneArrayBuffer(object);\n\n case boolTag:\n case dateTag:\n return new Ctor(+object);\n\n case dataViewTag:\n return cloneDataView(object, isDeep);\n\n case float32Tag: case float64Tag:\n case int8Tag: case int16Tag: case int32Tag:\n case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:\n return cloneTypedArray(object, isDeep);\n\n case mapTag:\n return new Ctor;\n\n case numberTag:\n case stringTag:\n return new Ctor(object);\n\n case regexpTag:\n return cloneRegExp(object);\n\n case setTag:\n return new Ctor;\n\n case symbolTag:\n return cloneSymbol(object);\n }\n}\n\nexport default initCloneByTag;\n","import isObject from './isObject.js';\n\n/** Built-in value references. */\nvar objectCreate = Object.create;\n\n/**\n * The base implementation of `_.create` without support for assigning\n * properties to the created object.\n *\n * @private\n * @param {Object} proto The object to inherit from.\n * @returns {Object} Returns the new object.\n */\nvar baseCreate = (function() {\n function object() {}\n return function(proto) {\n if (!isObject(proto)) {\n return {};\n }\n if (objectCreate) {\n return objectCreate(proto);\n }\n object.prototype = proto;\n var result = new object;\n object.prototype = undefined;\n return result;\n };\n}());\n\nexport default baseCreate;\n","import baseCreate from './_baseCreate.js';\nimport getPrototype from './_getPrototype.js';\nimport isPrototype from './_isPrototype.js';\n\n/**\n * Initializes an object clone.\n *\n * @private\n * @param {Object} object The object to clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneObject(object) {\n return (typeof object.constructor == 'function' && !isPrototype(object))\n ? baseCreate(getPrototype(object))\n : {};\n}\n\nexport default initCloneObject;\n","import getTag from './_getTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]';\n\n/**\n * The base implementation of `_.isMap` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n */\nfunction baseIsMap(value) {\n return isObjectLike(value) && getTag(value) == mapTag;\n}\n\nexport default baseIsMap;\n","import baseIsMap from './_baseIsMap.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsMap = nodeUtil && nodeUtil.isMap;\n\n/**\n * Checks if `value` is classified as a `Map` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n * @example\n *\n * _.isMap(new Map);\n * // => true\n *\n * _.isMap(new WeakMap);\n * // => false\n */\nvar isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;\n\nexport default isMap;\n","import getTag from './_getTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar setTag = '[object Set]';\n\n/**\n * The base implementation of `_.isSet` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n */\nfunction baseIsSet(value) {\n return isObjectLike(value) && getTag(value) == setTag;\n}\n\nexport default baseIsSet;\n","import baseIsSet from './_baseIsSet.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsSet = nodeUtil && nodeUtil.isSet;\n\n/**\n * Checks if `value` is classified as a `Set` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n * @example\n *\n * _.isSet(new Set);\n * // => true\n *\n * _.isSet(new WeakSet);\n * // => false\n */\nvar isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;\n\nexport default isSet;\n","import Stack from './_Stack.js';\nimport arrayEach from './_arrayEach.js';\nimport assignValue from './_assignValue.js';\nimport baseAssign from './_baseAssign.js';\nimport baseAssignIn from './_baseAssignIn.js';\nimport cloneBuffer from './_cloneBuffer.js';\nimport copyArray from './_copyArray.js';\nimport copySymbols from './_copySymbols.js';\nimport copySymbolsIn from './_copySymbolsIn.js';\nimport getAllKeys from './_getAllKeys.js';\nimport getAllKeysIn from './_getAllKeysIn.js';\nimport getTag from './_getTag.js';\nimport initCloneArray from './_initCloneArray.js';\nimport initCloneByTag from './_initCloneByTag.js';\nimport initCloneObject from './_initCloneObject.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isMap from './isMap.js';\nimport isObject from './isObject.js';\nimport isSet from './isSet.js';\nimport keys from './keys.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n CLONE_FLAT_FLAG = 2,\n CLONE_SYMBOLS_FLAG = 4;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n objectTag = '[object Object]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]',\n weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values supported by `_.clone`. */\nvar cloneableTags = {};\ncloneableTags[argsTag] = cloneableTags[arrayTag] =\ncloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =\ncloneableTags[boolTag] = cloneableTags[dateTag] =\ncloneableTags[float32Tag] = cloneableTags[float64Tag] =\ncloneableTags[int8Tag] = cloneableTags[int16Tag] =\ncloneableTags[int32Tag] = cloneableTags[mapTag] =\ncloneableTags[numberTag] = cloneableTags[objectTag] =\ncloneableTags[regexpTag] = cloneableTags[setTag] =\ncloneableTags[stringTag] = cloneableTags[symbolTag] =\ncloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =\ncloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;\ncloneableTags[errorTag] = cloneableTags[funcTag] =\ncloneableTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.clone` and `_.cloneDeep` which tracks\n * traversed objects.\n *\n * @private\n * @param {*} value The value to clone.\n * @param {boolean} bitmask The bitmask flags.\n * 1 - Deep clone\n * 2 - Flatten inherited properties\n * 4 - Clone symbols\n * @param {Function} [customizer] The function to customize cloning.\n * @param {string} [key] The key of `value`.\n * @param {Object} [object] The parent object of `value`.\n * @param {Object} [stack] Tracks traversed objects and their clone counterparts.\n * @returns {*} Returns the cloned value.\n */\nfunction baseClone(value, bitmask, customizer, key, object, stack) {\n var result,\n isDeep = bitmask & CLONE_DEEP_FLAG,\n isFlat = bitmask & CLONE_FLAT_FLAG,\n isFull = bitmask & CLONE_SYMBOLS_FLAG;\n\n if (customizer) {\n result = object ? customizer(value, key, object, stack) : customizer(value);\n }\n if (result !== undefined) {\n return result;\n }\n if (!isObject(value)) {\n return value;\n }\n var isArr = isArray(value);\n if (isArr) {\n result = initCloneArray(value);\n if (!isDeep) {\n return copyArray(value, result);\n }\n } else {\n var tag = getTag(value),\n isFunc = tag == funcTag || tag == genTag;\n\n if (isBuffer(value)) {\n return cloneBuffer(value, isDeep);\n }\n if (tag == objectTag || tag == argsTag || (isFunc && !object)) {\n result = (isFlat || isFunc) ? {} : initCloneObject(value);\n if (!isDeep) {\n return isFlat\n ? copySymbolsIn(value, baseAssignIn(result, value))\n : copySymbols(value, baseAssign(result, value));\n }\n } else {\n if (!cloneableTags[tag]) {\n return object ? value : {};\n }\n result = initCloneByTag(value, tag, isDeep);\n }\n }\n // Check for circular references and return its corresponding clone.\n stack || (stack = new Stack);\n var stacked = stack.get(value);\n if (stacked) {\n return stacked;\n }\n stack.set(value, result);\n\n if (isSet(value)) {\n value.forEach(function(subValue) {\n result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));\n });\n } else if (isMap(value)) {\n value.forEach(function(subValue, key) {\n result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));\n });\n }\n\n var keysFunc = isFull\n ? (isFlat ? getAllKeysIn : getAllKeys)\n : (isFlat ? keysIn : keys);\n\n var props = isArr ? undefined : keysFunc(value);\n arrayEach(props || value, function(subValue, key) {\n if (props) {\n key = subValue;\n subValue = value[key];\n }\n // Recursively populate clone (susceptible to call stack limits).\n assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));\n });\n return result;\n}\n\nexport default baseClone;\n","import baseClone from './_baseClone.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n CLONE_SYMBOLS_FLAG = 4;\n\n/**\n * This method is like `_.cloneWith` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @param {Function} [customizer] The function to customize cloning.\n * @returns {*} Returns the deep cloned value.\n * @see _.cloneWith\n * @example\n *\n * function customizer(value) {\n * if (_.isElement(value)) {\n * return value.cloneNode(true);\n * }\n * }\n *\n * var el = _.cloneDeepWith(document.body, customizer);\n *\n * console.log(el === document.body);\n * // => false\n * console.log(el.nodeName);\n * // => 'BODY'\n * console.log(el.childNodes.length);\n * // => 20\n */\nfunction cloneDeepWith(value, customizer) {\n customizer = typeof customizer == 'function' ? customizer : undefined;\n return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);\n}\n\nexport default cloneDeepWith;\n","import isObjectLike from './isObjectLike.js';\nimport isPlainObject from './isPlainObject.js';\n\n/**\n * Checks if `value` is likely a DOM element.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.\n * @example\n *\n * _.isElement(document.body);\n * // => true\n *\n * _.isElement('<body>');\n * // => false\n */\nfunction isElement(value) {\n return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);\n}\n\nexport default isElement;\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/config\n */\n\nimport { isPlainObject, isElement, cloneDeepWith } from 'lodash-es';\n\n/**\n * Handles a configuration dictionary.\n */\nexport default class Config {\n\t/**\n\t * Creates an instance of the {@link ~Config} class.\n\t *\n\t * @param {Object} [configurations] The initial configurations to be set. Usually, provided by the user.\n\t * @param {Object} [defaultConfigurations] The default configurations. Usually, provided by the system.\n\t */\n\tconstructor( configurations, defaultConfigurations ) {\n\t\t/**\n\t\t * Store for the whole configuration.\n\t\t *\n\t\t * @private\n\t\t * @member {Object}\n\t\t */\n\t\tthis._config = {};\n\n\t\t// Set default configuration.\n\t\tif ( defaultConfigurations ) {\n\t\t\t// Clone the configuration to make sure that the properties will not be shared\n\t\t\t// between editors and make the watchdog feature work correctly.\n\t\t\tthis.define( cloneConfig( defaultConfigurations ) );\n\t\t}\n\n\t\t// Set initial configuration.\n\t\tif ( configurations ) {\n\t\t\tthis._setObjectToTarget( this._config, configurations );\n\t\t}\n\t}\n\n\t/**\n\t * Set configuration values.\n\t *\n\t * It accepts both a name/value pair or an object, which properties and values will be used to set\n\t * configurations.\n\t *\n\t * It also accepts setting a \"deep configuration\" by using dots in the name. For example, `'resize.width'` sets\n\t * the value for the `width` configuration in the `resize` subset.\n\t *\n\t *\t\tconfig.set( 'width', 500 );\n\t *\t\tconfig.set( 'toolbar.collapsed', true );\n\t *\n\t *\t\t// Equivalent to:\n\t *\t\tconfig.set( {\n\t *\t\t\twidth: 500\n\t *\t\t\ttoolbar: {\n\t *\t\t\t\tcollapsed: true\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Passing an object as the value will amend the configuration, not replace it.\n\t *\n\t *\t\tconfig.set( 'toolbar', {\n\t *\t\t\tcollapsed: true,\n\t *\t\t} );\n\t *\n\t *\t\tconfig.set( 'toolbar', {\n\t *\t\t\tcolor: 'red',\n\t *\t\t} );\n\t *\n\t *\t\tconfig.get( 'toolbar.collapsed' ); // true\n\t *\t\tconfig.get( 'toolbar.color' ); // 'red'\n\t *\n\t * @param {String|Object} name The configuration name or an object from which take properties as\n\t * configuration entries. Configuration names are case-sensitive.\n\t * @param {*} value The configuration value. Used if a name is passed.\n\t */\n\tset( name, value ) {\n\t\tthis._setToTarget( this._config, name, value );\n\t}\n\n\t/**\n\t * Does exactly the same as {@link #set} with one exception – passed configuration extends\n\t * existing one, but does not overwrite already defined values.\n\t *\n\t * This method is supposed to be called by plugin developers to setup plugin's configurations. It would be\n\t * rarely used for other needs.\n\t *\n\t * @param {String|Object} name The configuration name or an object from which take properties as\n\t * configuration entries. Configuration names are case-sensitive.\n\t * @param {*} value The configuration value. Used if a name is passed.\n\t */\n\tdefine( name, value ) {\n\t\tconst isDefine = true;\n\n\t\tthis._setToTarget( this._config, name, value, isDefine );\n\t}\n\n\t/**\n\t * Gets the value for a configuration entry.\n\t *\n\t *\t\tconfig.get( 'name' );\n\t *\n\t * Deep configurations can be retrieved by separating each part with a dot.\n\t *\n\t *\t\tconfig.get( 'toolbar.collapsed' );\n\t *\n\t * @param {String} name The configuration name. Configuration names are case-sensitive.\n\t * @returns {*} The configuration value or `undefined` if the configuration entry was not found.\n\t */\n\tget( name ) {\n\t\treturn this._getFromSource( this._config, name );\n\t}\n\n\t/**\n\t * Iterates over all top level configuration names.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\t* names() {\n\t\tfor ( const name of Object.keys( this._config ) ) {\n\t\t\tyield name;\n\t\t}\n\t}\n\n\t/**\n\t * Saves passed configuration to the specified target (nested object).\n\t *\n\t * @private\n\t * @param {Object} target Nested config object.\n\t * @param {String|Object} name The configuration name or an object from which take properties as\n\t * configuration entries. Configuration names are case-sensitive.\n\t * @param {*} value The configuration value. Used if a name is passed.\n\t * @param {Boolean} [isDefine=false] Define if passed configuration should overwrite existing one.\n\t */\n\t_setToTarget( target, name, value, isDefine = false ) {\n\t\t// In case of an object, iterate through it and call `_setToTarget` again for each property.\n\t\tif ( isPlainObject( name ) ) {\n\t\t\tthis._setObjectToTarget( target, name, isDefine );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`].\n\t\tconst parts = name.split( '.' );\n\n\t\t// Take the name of the configuration out of the parts. E.g. `resize.width` -> `width`.\n\t\tname = parts.pop();\n\n\t\t// Iterate over parts to check if currently stored configuration has proper structure.\n\t\tfor ( const part of parts ) {\n\t\t\t// If there is no object for specified part then create one.\n\t\t\tif ( !isPlainObject( target[ part ] ) ) {\n\t\t\t\ttarget[ part ] = {};\n\t\t\t}\n\n\t\t\t// Nested object becomes a target.\n\t\t\ttarget = target[ part ];\n\t\t}\n\n\t\t// In case of value is an object.\n\t\tif ( isPlainObject( value ) ) {\n\t\t\t// We take care of proper config structure.\n\t\t\tif ( !isPlainObject( target[ name ] ) ) {\n\t\t\t\ttarget[ name ] = {};\n\t\t\t}\n\n\t\t\ttarget = target[ name ];\n\n\t\t\t// And iterate through this object calling `_setToTarget` again for each property.\n\t\t\tthis._setObjectToTarget( target, value, isDefine );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Do nothing if we are defining configuration for non empty name.\n\t\tif ( isDefine && typeof target[ name ] != 'undefined' ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttarget[ name ] = value;\n\t}\n\n\t/**\n\t * Get specified configuration from specified source (nested object).\n\t *\n\t * @private\n\t * @param {Object} source level of nested object.\n\t * @param {String} name The configuration name. Configuration names are case-sensitive.\n\t * @returns {*} The configuration value or `undefined` if the configuration entry was not found.\n\t */\n\t_getFromSource( source, name ) {\n\t\t// The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`].\n\t\tconst parts = name.split( '.' );\n\n\t\t// Take the name of the configuration out of the parts. E.g. `resize.width` -> `width`.\n\t\tname = parts.pop();\n\n\t\t// Iterate over parts to check if currently stored configuration has proper structure.\n\t\tfor ( const part of parts ) {\n\t\t\tif ( !isPlainObject( source[ part ] ) ) {\n\t\t\t\tsource = null;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Nested object becomes a source.\n\t\t\tsource = source[ part ];\n\t\t}\n\n\t\t// Always returns undefined for non existing configuration.\n\t\treturn source ? cloneConfig( source[ name ] ) : undefined;\n\t}\n\n\t/**\n\t * Iterates through passed object and calls {@link #_setToTarget} method with object key and value for each property.\n\t *\n\t * @private\n\t * @param {Object} target Nested config object.\n\t * @param {Object} configuration Configuration data set\n\t * @param {Boolean} [isDefine] Defines if passed configuration is default configuration or not.\n\t */\n\t_setObjectToTarget( target, configuration, isDefine ) {\n\t\tObject.keys( configuration ).forEach( key => {\n\t\t\tthis._setToTarget( target, key, configuration[ key ], isDefine );\n\t\t} );\n\t}\n}\n\n// Clones configuration object or value.\n// @param {*} source Source configuration\n// @returns {*} Cloned configuration value.\nfunction cloneConfig( source ) {\n\treturn cloneDeepWith( source, leaveDOMReferences );\n}\n\n// A customized function for cloneDeepWith.\n// It will leave references to DOM Elements instead of cloning them.\n//\n// @param {*} value\n// @returns {Element|undefined}\nfunction leaveDOMReferences( value ) {\n\treturn isElement( value ) ? value : undefined;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/spy\n */\n\n/**\n * Creates a spy function (ala Sinon.js) that can be used to inspect call to it.\n *\n * The following are the present features:\n *\n * * spy.called: property set to `true` if the function has been called at least once.\n *\n * @returns {Function} The spy function.\n */\nfunction spy() {\n\treturn function spy() {\n\t\tspy.called = true;\n\t};\n}\n\nexport default spy;\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/eventinfo\n */\n\nimport spy from './spy';\n\n/**\n * The event object passed to event callbacks. It is used to provide information about the event as well as a tool to\n * manipulate it.\n */\nexport default class EventInfo {\n\t/**\n\t * @param {Object} source The emitter.\n\t * @param {String} name The event name.\n\t */\n\tconstructor( source, name ) {\n\t\t/**\n\t\t * The object that fired the event.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Object}\n\t\t */\n\t\tthis.source = source;\n\n\t\t/**\n\t\t * The event name.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Path this event has followed. See {@link module:utils/emittermixin~EmitterMixin#delegate}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<Object>}\n\t\t */\n\t\tthis.path = [];\n\n\t\t// The following methods are defined in the constructor because they must be re-created per instance.\n\n\t\t/**\n\t\t * Stops the event emitter to call further callbacks for this event interaction.\n\t\t *\n\t\t * @method #stop\n\t\t */\n\t\tthis.stop = spy();\n\n\t\t/**\n\t\t * Removes the current callback from future interactions of this event.\n\t\t *\n\t\t * @method #off\n\t\t */\n\t\tthis.off = spy();\n\n\t\t/**\n\t\t * The value which will be returned by {@link module:utils/emittermixin~EmitterMixin#fire}.\n\t\t *\n\t\t * It's `undefined` by default and can be changed by an event listener:\n\t\t *\n\t\t *\t\tdataController.fire( 'getSelectedContent', ( evt ) => {\n\t\t *\t\t\t// This listener will make `dataController.fire( 'getSelectedContent' )`\n\t\t *\t\t\t// always return an empty DocumentFragment.\n\t\t *\t\t\tevt.return = new DocumentFragment();\n\t\t *\n\t\t *\t\t\t// Make sure no other listeners are executed.\n\t\t *\t\t\tevt.stop();\n\t\t *\t\t} );\n\t\t *\n\t\t * @member #return\n\t\t */\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/uid\n */\n\n// A hash table of hex numbers to avoid using toString() in uid() which is costly.\n// [ '00', '01', '02', ..., 'fe', 'ff' ]\nconst HEX_NUMBERS = new Array( 256 ).fill()\n\t.map( ( val, index ) => ( '0' + ( index ).toString( 16 ) ).slice( -2 ) );\n\n/**\n * Returns a unique id. The id starts with an \"e\" character and a randomly generated string of\n * 32 alphanumeric characters.\n *\n * **Note**: The characters the unique id is built from correspond to the hex number notation\n * (from \"0\" to \"9\", from \"a\" to \"f\"). In other words, each id corresponds to an \"e\" followed\n * by 16 8-bit numbers next to each other.\n *\n * @returns {String} An unique id string.\n */\nexport default function uid() {\n\t// Let's create some positive random 32bit integers first.\n\t//\n\t// 1. Math.random() is a float between 0 and 1.\n\t// 2. 0x100000000 is 2^32 = 4294967296.\n\t// 3. >>> 0 enforces integer (in JS all numbers are floating point).\n\t//\n\t// For instance:\n\t//\t\tMath.random() * 0x100000000 = 3366450031.853859\n\t// but\n\t//\t\tMath.random() * 0x100000000 >>> 0 = 3366450031.\n\tconst r1 = Math.random() * 0x100000000 >>> 0;\n\tconst r2 = Math.random() * 0x100000000 >>> 0;\n\tconst r3 = Math.random() * 0x100000000 >>> 0;\n\tconst r4 = Math.random() * 0x100000000 >>> 0;\n\n\t// Make sure that id does not start with number.\n\treturn 'e' +\n\t\tHEX_NUMBERS[ r1 >> 0 & 0xFF ] +\n\t\tHEX_NUMBERS[ r1 >> 8 & 0xFF ] +\n\t\tHEX_NUMBERS[ r1 >> 16 & 0xFF ] +\n\t\tHEX_NUMBERS[ r1 >> 24 & 0xFF ] +\n\t\tHEX_NUMBERS[ r2 >> 0 & 0xFF ] +\n\t\tHEX_NUMBERS[ r2 >> 8 & 0xFF ] +\n\t\tHEX_NUMBERS[ r2 >> 16 & 0xFF ] +\n\t\tHEX_NUMBERS[ r2 >> 24 & 0xFF ] +\n\t\tHEX_NUMBERS[ r3 >> 0 & 0xFF ] +\n\t\tHEX_NUMBERS[ r3 >> 8 & 0xFF ] +\n\t\tHEX_NUMBERS[ r3 >> 16 & 0xFF ] +\n\t\tHEX_NUMBERS[ r3 >> 24 & 0xFF ] +\n\t\tHEX_NUMBERS[ r4 >> 0 & 0xFF ] +\n\t\tHEX_NUMBERS[ r4 >> 8 & 0xFF ] +\n\t\tHEX_NUMBERS[ r4 >> 16 & 0xFF ] +\n\t\tHEX_NUMBERS[ r4 >> 24 & 0xFF ];\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/priorities\n */\n\n/**\n * String representing a priority value.\n *\n * @typedef {'highest'|'high'|'normal'|'low'|'lowest'} module:utils/priorities~PriorityString\n */\n\n/**\n * Provides group of constants to use instead of hardcoding numeric priority values.\n *\n * @namespace\n */\nconst priorities = {\n\t/**\n\t * Converts a string with priority name to it's numeric value. If `Number` is given, it just returns it.\n\t *\n\t * @static\n\t * @param {module:utils/priorities~PriorityString|Number} priority Priority to convert.\n\t * @returns {Number} Converted priority.\n\t */\n\tget( priority ) {\n\t\tif ( typeof priority != 'number' ) {\n\t\t\treturn this[ priority ] || this.normal;\n\t\t} else {\n\t\t\treturn priority;\n\t\t}\n\t},\n\n\thighest: 100000,\n\thigh: 1000,\n\tnormal: 0,\n\tlow: -1000,\n\tlowest: -100000\n};\n\nexport default priorities;\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/emittermixin\n */\n\nimport EventInfo from './eventinfo';\nimport uid from './uid';\nimport priorities from './priorities';\n\n// To check if component is loaded more than once.\nimport './version';\nimport CKEditorError from './ckeditorerror';\n\nconst _listeningTo = Symbol( 'listeningTo' );\nconst _emitterId = Symbol( 'emitterId' );\n\n/**\n * Mixin that injects the {@link ~Emitter events API} into its host.\n *\n * @mixin EmitterMixin\n * @implements module:utils/emittermixin~Emitter\n */\nconst EmitterMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\ton( event, callback, options = {} ) {\n\t\tthis.listenTo( this, event, callback, options );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tonce( event, callback, options ) {\n\t\tlet wasFired = false;\n\n\t\tconst onceCallback = function( event, ...args ) {\n\t\t\t// Ensure the callback is called only once even if the callback itself leads to re-firing the event\n\t\t\t// (which would call the callback again).\n\t\t\tif ( !wasFired ) {\n\t\t\t\twasFired = true;\n\n\t\t\t\t// Go off() at the first call.\n\t\t\t\tevent.off();\n\n\t\t\t\t// Go with the original callback.\n\t\t\t\tcallback.call( this, event, ...args );\n\t\t\t}\n\t\t};\n\n\t\t// Make a similar on() call, simply replacing the callback.\n\t\tthis.listenTo( this, event, onceCallback, options );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\toff( event, callback ) {\n\t\tthis.stopListening( this, event, callback );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tlistenTo( emitter, event, callback, options = {} ) {\n\t\tlet emitterInfo, eventCallbacks;\n\n\t\t// _listeningTo contains a list of emitters that this object is listening to.\n\t\t// This list has the following format:\n\t\t//\n\t\t// _listeningTo: {\n\t\t// emitterId: {\n\t\t// emitter: emitter,\n\t\t// callbacks: {\n\t\t// event1: [ callback1, callback2, ... ]\n\t\t// ....\n\t\t// }\n\t\t// },\n\t\t// ...\n\t\t// }\n\n\t\tif ( !this[ _listeningTo ] ) {\n\t\t\tthis[ _listeningTo ] = {};\n\t\t}\n\n\t\tconst emitters = this[ _listeningTo ];\n\n\t\tif ( !_getEmitterId( emitter ) ) {\n\t\t\t_setEmitterId( emitter );\n\t\t}\n\n\t\tconst emitterId = _getEmitterId( emitter );\n\n\t\tif ( !( emitterInfo = emitters[ emitterId ] ) ) {\n\t\t\temitterInfo = emitters[ emitterId ] = {\n\t\t\t\temitter,\n\t\t\t\tcallbacks: {}\n\t\t\t};\n\t\t}\n\n\t\tif ( !( eventCallbacks = emitterInfo.callbacks[ event ] ) ) {\n\t\t\teventCallbacks = emitterInfo.callbacks[ event ] = [];\n\t\t}\n\n\t\teventCallbacks.push( callback );\n\n\t\t// Finally register the callback to the event.\n\t\tcreateEventNamespace( emitter, event );\n\t\tconst lists = getCallbacksListsForNamespace( emitter, event );\n\t\tconst priority = priorities.get( options.priority );\n\n\t\tconst callbackDefinition = {\n\t\t\tcallback,\n\t\t\tpriority\n\t\t};\n\n\t\t// Add the callback to all callbacks list.\n\t\tfor ( const callbacks of lists ) {\n\t\t\t// Add the callback to the list in the right priority position.\n\t\t\tlet added = false;\n\n\t\t\tfor ( let i = 0; i < callbacks.length; i++ ) {\n\t\t\t\tif ( callbacks[ i ].priority < priority ) {\n\t\t\t\t\tcallbacks.splice( i, 0, callbackDefinition );\n\t\t\t\t\tadded = true;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add at the end, if right place was not found.\n\t\t\tif ( !added ) {\n\t\t\t\tcallbacks.push( callbackDefinition );\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstopListening( emitter, event, callback ) {\n\t\tconst emitters = this[ _listeningTo ];\n\t\tlet emitterId = emitter && _getEmitterId( emitter );\n\t\tconst emitterInfo = emitters && emitterId && emitters[ emitterId ];\n\t\tconst eventCallbacks = emitterInfo && event && emitterInfo.callbacks[ event ];\n\n\t\t// Stop if nothing has been listened.\n\t\tif ( !emitters || ( emitter && !emitterInfo ) || ( event && !eventCallbacks ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// All params provided. off() that single callback.\n\t\tif ( callback ) {\n\t\t\tremoveCallback( emitter, event, callback );\n\t\t}\n\t\t// Only `emitter` and `event` provided. off() all callbacks for that event.\n\t\telse if ( eventCallbacks ) {\n\t\t\twhile ( ( callback = eventCallbacks.pop() ) ) {\n\t\t\t\tremoveCallback( emitter, event, callback );\n\t\t\t}\n\n\t\t\tdelete emitterInfo.callbacks[ event ];\n\t\t}\n\t\t// Only `emitter` provided. off() all events for that emitter.\n\t\telse if ( emitterInfo ) {\n\t\t\tfor ( event in emitterInfo.callbacks ) {\n\t\t\t\tthis.stopListening( emitter, event );\n\t\t\t}\n\t\t\tdelete emitters[ emitterId ];\n\t\t}\n\t\t// No params provided. off() all emitters.\n\t\telse {\n\t\t\tfor ( emitterId in emitters ) {\n\t\t\t\tthis.stopListening( emitters[ emitterId ].emitter );\n\t\t\t}\n\t\t\tdelete this[ _listeningTo ];\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tfire( eventOrInfo, ...args ) {\n\t\ttry {\n\t\t\tconst eventInfo = eventOrInfo instanceof EventInfo ? eventOrInfo : new EventInfo( this, eventOrInfo );\n\t\t\tconst event = eventInfo.name;\n\t\t\tlet callbacks = getCallbacksForEvent( this, event );\n\n\t\t\t// Record that the event passed this emitter on its path.\n\t\t\teventInfo.path.push( this );\n\n\t\t\t// Handle event listener callbacks first.\n\t\t\tif ( callbacks ) {\n\t\t\t\t// Arguments passed to each callback.\n\t\t\t\tconst callbackArgs = [ eventInfo, ...args ];\n\n\t\t\t\t// Copying callbacks array is the easiest and most secure way of preventing infinite loops, when event callbacks\n\t\t\t\t// are added while processing other callbacks. Previous solution involved adding counters (unique ids) but\n\t\t\t\t// failed if callbacks were added to the queue before currently processed callback.\n\t\t\t\t// If this proves to be too inefficient, another method is to change `.on()` so callbacks are stored if same\n\t\t\t\t// event is currently processed. Then, `.fire()` at the end, would have to add all stored events.\n\t\t\t\tcallbacks = Array.from( callbacks );\n\n\t\t\t\tfor ( let i = 0; i < callbacks.length; i++ ) {\n\t\t\t\t\tcallbacks[ i ].callback.apply( this, callbackArgs );\n\n\t\t\t\t\t// Remove the callback from future requests if off() has been called.\n\t\t\t\t\tif ( eventInfo.off.called ) {\n\t\t\t\t\t\t// Remove the called mark for the next calls.\n\t\t\t\t\t\tdelete eventInfo.off.called;\n\n\t\t\t\t\t\tremoveCallback( this, event, callbacks[ i ].callback );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Do not execute next callbacks if stop() was called.\n\t\t\t\t\tif ( eventInfo.stop.called ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Delegate event to other emitters if needed.\n\t\t\tif ( this._delegations ) {\n\t\t\t\tconst destinations = this._delegations.get( event );\n\t\t\t\tconst passAllDestinations = this._delegations.get( '*' );\n\n\t\t\t\tif ( destinations ) {\n\t\t\t\t\tfireDelegatedEvents( destinations, eventInfo, args );\n\t\t\t\t}\n\n\t\t\t\tif ( passAllDestinations ) {\n\t\t\t\t\tfireDelegatedEvents( passAllDestinations, eventInfo, args );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn eventInfo.return;\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdelegate( ...events ) {\n\t\treturn {\n\t\t\tto: ( emitter, nameOrFunction ) => {\n\t\t\t\tif ( !this._delegations ) {\n\t\t\t\t\tthis._delegations = new Map();\n\t\t\t\t}\n\n\t\t\t\t// Originally there was a for..of loop which unfortunately caused an error in Babel that didn't allow\n\t\t\t\t// build an application. See: https://github.com/ckeditor/ckeditor5-react/issues/40.\n\t\t\t\tevents.forEach( eventName => {\n\t\t\t\t\tconst destinations = this._delegations.get( eventName );\n\n\t\t\t\t\tif ( !destinations ) {\n\t\t\t\t\t\tthis._delegations.set( eventName, new Map( [ [ emitter, nameOrFunction ] ] ) );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdestinations.set( emitter, nameOrFunction );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstopDelegating( event, emitter ) {\n\t\tif ( !this._delegations ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !event ) {\n\t\t\tthis._delegations.clear();\n\t\t} else if ( !emitter ) {\n\t\t\tthis._delegations.delete( event );\n\t\t} else {\n\t\t\tconst destinations = this._delegations.get( event );\n\n\t\t\tif ( destinations ) {\n\t\t\t\tdestinations.delete( emitter );\n\t\t\t}\n\t\t}\n\t}\n};\n\nexport default EmitterMixin;\n\n/**\n * Emitter/listener interface.\n *\n * Can be easily implemented by a class by mixing the {@link module:utils/emittermixin~EmitterMixin} mixin.\n *\n * @interface Emitter\n */\n\n/**\n * Registers a callback function to be executed when an event is fired.\n *\n * Shorthand for {@link #listenTo `this.listenTo( this, event, callback, options )`} (it makes the emitter\n * listen on itself).\n *\n * @method #on\n * @param {String} event The name of the event.\n * @param {Function} callback The function to be called on event.\n * @param {Object} [options={}] Additional options.\n * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n * order they were added.\n */\n\n/**\n * Registers a callback function to be executed on the next time the event is fired only. This is similar to\n * calling {@link #on} followed by {@link #off} in the callback.\n *\n * @method #once\n * @param {String} event The name of the event.\n * @param {Function} callback The function to be called on event.\n * @param {Object} [options={}] Additional options.\n * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n * order they were added.\n */\n\n/**\n * Stops executing the callback on the given event.\n * Shorthand for {@link #stopListening `this.stopListening( this, event, callback )`}.\n *\n * @method #off\n * @param {String} event The name of the event.\n * @param {Function} callback The function to stop being called.\n */\n\n/**\n * Registers a callback function to be executed when an event is fired in a specific (emitter) object.\n *\n * Events can be grouped in namespaces using `:`.\n * When namespaced event is fired, it additionally fires all callbacks for that namespace.\n *\n *\t\t// myEmitter.on( ... ) is a shorthand for myEmitter.listenTo( myEmitter, ... ).\n *\t\tmyEmitter.on( 'myGroup', genericCallback );\n *\t\tmyEmitter.on( 'myGroup:myEvent', specificCallback );\n *\n *\t\t// genericCallback is fired.\n *\t\tmyEmitter.fire( 'myGroup' );\n *\t\t// both genericCallback and specificCallback are fired.\n *\t\tmyEmitter.fire( 'myGroup:myEvent' );\n *\t\t// genericCallback is fired even though there are no callbacks for \"foo\".\n *\t\tmyEmitter.fire( 'myGroup:foo' );\n *\n * An event callback can {@link module:utils/eventinfo~EventInfo#stop stop the event} and\n * set the {@link module:utils/eventinfo~EventInfo#return return value} of the {@link #fire} method.\n *\n * @method #listenTo\n * @param {module:utils/emittermixin~Emitter} emitter The object that fires the event.\n * @param {String} event The name of the event.\n * @param {Function} callback The function to be called on event.\n * @param {Object} [options={}] Additional options.\n * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n * order they were added.\n */\n\n/**\n * Stops listening for events. It can be used at different levels:\n *\n * * To stop listening to a specific callback.\n * * To stop listening to a specific event.\n * * To stop listening to all events fired by a specific object.\n * * To stop listening to all events fired by all objects.\n *\n * @method #stopListening\n * @param {module:utils/emittermixin~Emitter} [emitter] The object to stop listening to. If omitted, stops it for all objects.\n * @param {String} [event] (Requires the `emitter`) The name of the event to stop listening to. If omitted, stops it\n * for all events from `emitter`.\n * @param {Function} [callback] (Requires the `event`) The function to be removed from the call list for the given\n * `event`.\n */\n\n/**\n * Fires an event, executing all callbacks registered for it.\n *\n * The first parameter passed to callbacks is an {@link module:utils/eventinfo~EventInfo} object,\n * followed by the optional `args` provided in the `fire()` method call.\n *\n * @method #fire\n * @param {String|module:utils/eventinfo~EventInfo} eventOrInfo The name of the event or `EventInfo` object if event is delegated.\n * @param {...*} [args] Additional arguments to be passed to the callbacks.\n * @returns {*} By default the method returns `undefined`. However, the return value can be changed by listeners\n * through modification of the {@link module:utils/eventinfo~EventInfo#return `evt.return`}'s property (the event info\n * is the first param of every callback).\n */\n\n/**\n * Delegates selected events to another {@link module:utils/emittermixin~Emitter}. For instance:\n *\n *\t\temitterA.delegate( 'eventX' ).to( emitterB );\n *\t\temitterA.delegate( 'eventX', 'eventY' ).to( emitterC );\n *\n * then `eventX` is delegated (fired by) `emitterB` and `emitterC` along with `data`:\n *\n *\t\temitterA.fire( 'eventX', data );\n *\n * and `eventY` is delegated (fired by) `emitterC` along with `data`:\n *\n *\t\temitterA.fire( 'eventY', data );\n *\n * @method #delegate\n * @param {...String} events Event names that will be delegated to another emitter.\n * @returns {module:utils/emittermixin~EmitterMixinDelegateChain}\n */\n\n/**\n * Stops delegating events. It can be used at different levels:\n *\n * * To stop delegating all events.\n * * To stop delegating a specific event to all emitters.\n * * To stop delegating a specific event to a specific emitter.\n *\n * @method #stopDelegating\n * @param {String} [event] The name of the event to stop delegating. If omitted, stops it all delegations.\n * @param {module:utils/emittermixin~Emitter} [emitter] (requires `event`) The object to stop delegating a particular event to.\n * If omitted, stops delegation of `event` to all emitters.\n */\n\n/**\n * Checks if `listeningEmitter` listens to an emitter with given `listenedToEmitterId` and if so, returns that emitter.\n * If not, returns `null`.\n *\n * @protected\n * @param {module:utils/emittermixin~Emitter} listeningEmitter An emitter that listens.\n * @param {String} listenedToEmitterId Unique emitter id of emitter listened to.\n * @returns {module:utils/emittermixin~Emitter|null}\n */\nexport function _getEmitterListenedTo( listeningEmitter, listenedToEmitterId ) {\n\tif ( listeningEmitter[ _listeningTo ] && listeningEmitter[ _listeningTo ][ listenedToEmitterId ] ) {\n\t\treturn listeningEmitter[ _listeningTo ][ listenedToEmitterId ].emitter;\n\t}\n\n\treturn null;\n}\n\n/**\n * Sets emitter's unique id.\n *\n * **Note:** `_emitterId` can be set only once.\n *\n * @protected\n * @param {module:utils/emittermixin~Emitter} emitter An emitter for which id will be set.\n * @param {String} [id] Unique id to set. If not passed, random unique id will be set.\n */\nexport function _setEmitterId( emitter, id ) {\n\tif ( !emitter[ _emitterId ] ) {\n\t\temitter[ _emitterId ] = id || uid();\n\t}\n}\n\n/**\n * Returns emitter's unique id.\n *\n * @protected\n * @param {module:utils/emittermixin~Emitter} emitter An emitter which id will be returned.\n */\nexport function _getEmitterId( emitter ) {\n\treturn emitter[ _emitterId ];\n}\n\n// Gets the internal `_events` property of the given object.\n// `_events` property store all lists with callbacks for registered event names.\n// If there were no events registered on the object, empty `_events` object is created.\nfunction getEvents( source ) {\n\tif ( !source._events ) {\n\t\tObject.defineProperty( source, '_events', {\n\t\t\tvalue: {}\n\t\t} );\n\t}\n\n\treturn source._events;\n}\n\n// Creates event node for generic-specific events relation architecture.\nfunction makeEventNode() {\n\treturn {\n\t\tcallbacks: [],\n\t\tchildEvents: []\n\t};\n}\n\n// Creates an architecture for generic-specific events relation.\n// If needed, creates all events for given eventName, i.e. if the first registered event\n// is foo:bar:abc, it will create foo:bar:abc, foo:bar and foo event and tie them together.\n// It also copies callbacks from more generic events to more specific events when\n// specific events are created.\nfunction createEventNamespace( source, eventName ) {\n\tconst events = getEvents( source );\n\n\t// First, check if the event we want to add to the structure already exists.\n\tif ( events[ eventName ] ) {\n\t\t// If it exists, we don't have to do anything.\n\t\treturn;\n\t}\n\n\t// In other case, we have to create the structure for the event.\n\t// Note, that we might need to create intermediate events too.\n\t// I.e. if foo:bar:abc is being registered and we only have foo in the structure,\n\t// we need to also register foo:bar.\n\n\t// Currently processed event name.\n\tlet name = eventName;\n\t// Name of the event that is a child event for currently processed event.\n\tlet childEventName = null;\n\n\t// Array containing all newly created specific events.\n\tconst newEventNodes = [];\n\n\t// While loop can't check for ':' index because we have to handle generic events too.\n\t// In each loop, we truncate event name, going from the most specific name to the generic one.\n\t// I.e. foo:bar:abc -> foo:bar -> foo.\n\twhile ( name !== '' ) {\n\t\tif ( events[ name ] ) {\n\t\t\t// If the currently processed event name is already registered, we can be sure\n\t\t\t// that it already has all the structure created, so we can break the loop here\n\t\t\t// as no more events need to be registered.\n\t\t\tbreak;\n\t\t}\n\n\t\t// If this event is not yet registered, create a new object for it.\n\t\tevents[ name ] = makeEventNode();\n\t\t// Add it to the array with newly created events.\n\t\tnewEventNodes.push( events[ name ] );\n\n\t\t// Add previously processed event name as a child of this event.\n\t\tif ( childEventName ) {\n\t\t\tevents[ name ].childEvents.push( childEventName );\n\t\t}\n\n\t\tchildEventName = name;\n\t\t// If `.lastIndexOf()` returns -1, `.substr()` will return '' which will break the loop.\n\t\tname = name.substr( 0, name.lastIndexOf( ':' ) );\n\t}\n\n\tif ( name !== '' ) {\n\t\t// If name is not empty, we found an already registered event that was a parent of the\n\t\t// event we wanted to register.\n\n\t\t// Copy that event's callbacks to newly registered events.\n\t\tfor ( const node of newEventNodes ) {\n\t\t\tnode.callbacks = events[ name ].callbacks.slice();\n\t\t}\n\n\t\t// Add last newly created event to the already registered event.\n\t\tevents[ name ].childEvents.push( childEventName );\n\t}\n}\n\n// Gets an array containing callbacks list for a given event and it's more specific events.\n// I.e. if given event is foo:bar and there is also foo:bar:abc event registered, this will\n// return callback list of foo:bar and foo:bar:abc (but not foo).\nfunction getCallbacksListsForNamespace( source, eventName ) {\n\tconst eventNode = getEvents( source )[ eventName ];\n\n\tif ( !eventNode ) {\n\t\treturn [];\n\t}\n\n\tlet callbacksLists = [ eventNode.callbacks ];\n\n\tfor ( let i = 0; i < eventNode.childEvents.length; i++ ) {\n\t\tconst childCallbacksLists = getCallbacksListsForNamespace( source, eventNode.childEvents[ i ] );\n\n\t\tcallbacksLists = callbacksLists.concat( childCallbacksLists );\n\t}\n\n\treturn callbacksLists;\n}\n\n// Get the list of callbacks for a given event, but only if there any callbacks have been registered.\n// If there are no callbacks registered for given event, it checks if this is a specific event and looks\n// for callbacks for it's more generic version.\nfunction getCallbacksForEvent( source, eventName ) {\n\tlet event;\n\n\tif ( !source._events || !( event = source._events[ eventName ] ) || !event.callbacks.length ) {\n\t\t// There are no callbacks registered for specified eventName.\n\t\t// But this could be a specific-type event that is in a namespace.\n\t\tif ( eventName.indexOf( ':' ) > -1 ) {\n\t\t\t// If the eventName is specific, try to find callback lists for more generic event.\n\t\t\treturn getCallbacksForEvent( source, eventName.substr( 0, eventName.lastIndexOf( ':' ) ) );\n\t\t} else {\n\t\t\t// If this is a top-level generic event, return null;\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn event.callbacks;\n}\n\n// Fires delegated events for given map of destinations.\n//\n// @private\n// * @param {Map.<utils.Emitter>} destinations A map containing\n// `[ {@link module:utils/emittermixin~Emitter}, \"event name\" ]` pair destinations.\n// * @param {utils.EventInfo} eventInfo The original event info object.\n// * @param {Array.<*>} fireArgs Arguments the original event was fired with.\nfunction fireDelegatedEvents( destinations, eventInfo, fireArgs ) {\n\tfor ( let [ emitter, name ] of destinations ) {\n\t\tif ( !name ) {\n\t\t\tname = eventInfo.name;\n\t\t} else if ( typeof name == 'function' ) {\n\t\t\tname = name( eventInfo.name );\n\t\t}\n\n\t\tconst delegatedInfo = new EventInfo( eventInfo.source, name );\n\n\t\tdelegatedInfo.path = [ ...eventInfo.path ];\n\n\t\temitter.fire( delegatedInfo, ...fireArgs );\n\t}\n}\n\n// Removes callback from emitter for given event.\n//\n// @param {module:utils/emittermixin~Emitter} emitter\n// @param {String} event\n// @param {Function} callback\nfunction removeCallback( emitter, event, callback ) {\n\tconst lists = getCallbacksListsForNamespace( emitter, event );\n\n\tfor ( const callbacks of lists ) {\n\t\tfor ( let i = 0; i < callbacks.length; i++ ) {\n\t\t\tif ( callbacks[ i ].callback == callback ) {\n\t\t\t\t// Remove the callback from the list (fixing the next index).\n\t\t\t\tcallbacks.splice( i, 1 );\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * The return value of {@link ~EmitterMixin#delegate}.\n *\n * @interface module:utils/emittermixin~EmitterMixinDelegateChain\n */\n\n/**\n * Selects destination for {@link module:utils/emittermixin~EmitterMixin#delegate} events.\n *\n * @method #to\n * @param {module:utils/emittermixin~Emitter} emitter An `EmitterMixin` instance which is the destination for delegated events.\n * @param {String|Function} [nameOrFunction] A custom event name or function which converts the original name string.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/mix\n */\n\n/**\n * Copies enumerable properties and symbols from the objects given as 2nd+ parameters to the\n * prototype of first object (a constructor).\n *\n *\t\tclass Editor {\n *\t\t\t...\n *\t\t}\n *\n *\t\tconst SomeMixin = {\n *\t\t\ta() {\n *\t\t\t\treturn 'a';\n *\t\t\t}\n *\t\t};\n *\n *\t\tmix( Editor, SomeMixin, ... );\n *\n *\t\tnew Editor().a(); // -> 'a'\n *\n * Note: Properties which already exist in the base class will not be overriden.\n *\n * @param {Function} [baseClass] Class which prototype will be extended.\n * @param {Object} [...mixins] Objects from which to get properties.\n */\nexport default function mix( baseClass, ...mixins ) {\n\tmixins.forEach( mixin => {\n\t\tObject.getOwnPropertyNames( mixin ).concat( Object.getOwnPropertySymbols( mixin ) )\n\t\t\t.forEach( key => {\n\t\t\t\tif ( key in baseClass.prototype ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst sourceDescriptor = Object.getOwnPropertyDescriptor( mixin, key );\n\t\t\t\tsourceDescriptor.enumerable = false;\n\n\t\t\t\tObject.defineProperty( baseClass.prototype, key, sourceDescriptor );\n\t\t\t} );\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/collection\n */\n\nimport EmitterMixin from './emittermixin';\nimport CKEditorError from './ckeditorerror';\nimport uid from './uid';\nimport mix from './mix';\n\n/**\n * Collections are ordered sets of objects. Items in the collection can be retrieved by their indexes\n * in the collection (like in an array) or by their ids.\n *\n * If an object without an `id` property is being added to the collection, the `id` property will be generated\n * automatically. Note that the automatically generated id is unique only within this single collection instance.\n *\n * By default an item in the collection is identified by its `id` property. The name of the identifier can be\n * configured through the constructor of the collection.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Collection {\n\t/**\n\t * Creates a new Collection instance.\n\t *\n\t * @param {Object} [options={}] The options object.\n\t * @param {String} [options.idProperty='id'] The name of the property which is considered to identify an item.\n\t */\n\tconstructor( options = {} ) {\n\t\t/**\n\t\t * The internal list of items in the collection.\n\t\t *\n\t\t * @private\n\t\t * @member {Object[]}\n\t\t */\n\t\tthis._items = [];\n\n\t\t/**\n\t\t * The internal map of items in the collection.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._itemMap = new Map();\n\n\t\t/**\n\t\t * The name of the property which is considered to identify an item.\n\t\t *\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._idProperty = options.idProperty || 'id';\n\n\t\t/**\n\t\t * A helper mapping external items of a bound collection ({@link #bindTo})\n\t\t * and actual items of this collection. It provides information\n\t\t * necessary to properly remove items bound to another collection.\n\t\t *\n\t\t * See {@link #_bindToInternalToExternalMap}.\n\t\t *\n\t\t * @protected\n\t\t * @member {WeakMap}\n\t\t */\n\t\tthis._bindToExternalToInternalMap = new WeakMap();\n\n\t\t/**\n\t\t * A helper mapping items of this collection to external items of a bound collection\n\t\t * ({@link #bindTo}). It provides information necessary to manage the bindings, e.g.\n\t\t * to avoid loops in two–way bindings.\n\t\t *\n\t\t * See {@link #_bindToExternalToInternalMap}.\n\t\t *\n\t\t * @protected\n\t\t * @member {WeakMap}\n\t\t */\n\t\tthis._bindToInternalToExternalMap = new WeakMap();\n\n\t\t/**\n\t\t * Stores indexes of skipped items from bound external collection.\n\t\t *\n\t\t * @private\n\t\t * @member {Array}\n\t\t */\n\t\tthis._skippedIndexesFromExternal = [];\n\n\t\t/**\n\t\t * A collection instance this collection is bound to as a result\n\t\t * of calling {@link #bindTo} method.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:utils/collection~Collection} #_bindToCollection\n\t\t */\n\t}\n\n\t/**\n\t * The number of items available in the collection.\n\t *\n\t * @member {Number} #length\n\t */\n\tget length() {\n\t\treturn this._items.length;\n\t}\n\n\t/**\n\t * Returns the first item from the collection or null when collection is empty.\n\t *\n\t * @returns {Object|null} The first item or `null` if collection is empty.\n\t */\n\tget first() {\n\t\treturn this._items[ 0 ] || null;\n\t}\n\n\t/**\n\t * Returns the last item from the collection or null when collection is empty.\n\t *\n\t * @returns {Object|null} The last item or `null` if collection is empty.\n\t */\n\tget last() {\n\t\treturn this._items[ this.length - 1 ] || null;\n\t}\n\n\t/**\n\t * Adds an item into the collection.\n\t *\n\t * If the item does not have an id, then it will be automatically generated and set on the item.\n\t *\n\t * @chainable\n\t * @param {Object} item\n\t * @param {Number} [index] The position of the item in the collection. The item\n\t * is pushed to the collection when `index` not specified.\n\t * @fires add\n\t */\n\tadd( item, index ) {\n\t\tlet itemId;\n\t\tconst idProperty = this._idProperty;\n\n\t\tif ( ( idProperty in item ) ) {\n\t\t\titemId = item[ idProperty ];\n\n\t\t\tif ( typeof itemId != 'string' ) {\n\t\t\t\t/**\n\t\t\t\t * This item's id should be a string.\n\t\t\t\t *\n\t\t\t\t * @error collection-add-invalid-id\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'collection-add-invalid-id', this );\n\t\t\t}\n\n\t\t\tif ( this.get( itemId ) ) {\n\t\t\t\t/**\n\t\t\t\t * This item already exists in the collection.\n\t\t\t\t *\n\t\t\t\t * @error collection-add-item-already-exists\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'collection-add-item-already-exists', this );\n\t\t\t}\n\t\t} else {\n\t\t\titem[ idProperty ] = itemId = uid();\n\t\t}\n\n\t\t// TODO: Use ES6 default function argument.\n\t\tif ( index === undefined ) {\n\t\t\tindex = this._items.length;\n\t\t} else if ( index > this._items.length || index < 0 ) {\n\t\t\t/**\n\t\t\t * The index number has invalid value.\n\t\t\t *\n\t\t\t * @error collection-add-item-bad-index\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'collection-add-item-invalid-index', this );\n\t\t}\n\n\t\tthis._items.splice( index, 0, item );\n\n\t\tthis._itemMap.set( itemId, item );\n\n\t\tthis.fire( 'add', item, index );\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets item by its id or index.\n\t *\n\t * @param {String|Number} idOrIndex The item id or index in the collection.\n\t * @returns {Object|null} The requested item or `null` if such item does not exist.\n\t */\n\tget( idOrIndex ) {\n\t\tlet item;\n\n\t\tif ( typeof idOrIndex == 'string' ) {\n\t\t\titem = this._itemMap.get( idOrIndex );\n\t\t} else if ( typeof idOrIndex == 'number' ) {\n\t\t\titem = this._items[ idOrIndex ];\n\t\t} else {\n\t\t\t/**\n\t\t\t * Index or id must be given.\n\t\t\t *\n\t\t\t * @error collection-get-invalid-arg\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'collection-get-invalid-arg: Index or id must be given.', this );\n\t\t}\n\n\t\treturn item || null;\n\t}\n\n\t/**\n\t * Returns a boolean indicating whether the collection contains an item.\n\t *\n\t * @param {Object|String} itemOrId The item or its id in the collection.\n\t * @returns {Boolean} `true` if the collection contains the item, `false` otherwise.\n\t */\n\thas( itemOrId ) {\n\t\tif ( typeof itemOrId == 'string' ) {\n\t\t\treturn this._itemMap.has( itemOrId );\n\t\t} else { // Object\n\t\t\tconst idProperty = this._idProperty;\n\t\t\tconst id = itemOrId[ idProperty ];\n\n\t\t\treturn this._itemMap.has( id );\n\t\t}\n\t}\n\n\t/**\n\t * Gets index of item in the collection.\n\t * When item is not defined in the collection then index will be equal -1.\n\t *\n\t * @param {Object|String} itemOrId The item or its id in the collection.\n\t * @returns {Number} Index of given item.\n\t */\n\tgetIndex( itemOrId ) {\n\t\tlet item;\n\n\t\tif ( typeof itemOrId == 'string' ) {\n\t\t\titem = this._itemMap.get( itemOrId );\n\t\t} else {\n\t\t\titem = itemOrId;\n\t\t}\n\n\t\treturn this._items.indexOf( item );\n\t}\n\n\t/**\n\t * Removes an item from the collection.\n\t *\n\t * @param {Object|Number|String} subject The item to remove, its id or index in the collection.\n\t * @returns {Object} The removed item.\n\t * @fires remove\n\t */\n\tremove( subject ) {\n\t\tlet index, id, item;\n\t\tlet itemDoesNotExist = false;\n\t\tconst idProperty = this._idProperty;\n\n\t\tif ( typeof subject == 'string' ) {\n\t\t\tid = subject;\n\t\t\titem = this._itemMap.get( id );\n\t\t\titemDoesNotExist = !item;\n\n\t\t\tif ( item ) {\n\t\t\t\tindex = this._items.indexOf( item );\n\t\t\t}\n\t\t} else if ( typeof subject == 'number' ) {\n\t\t\tindex = subject;\n\t\t\titem = this._items[ index ];\n\t\t\titemDoesNotExist = !item;\n\n\t\t\tif ( item ) {\n\t\t\t\tid = item[ idProperty ];\n\t\t\t}\n\t\t} else {\n\t\t\titem = subject;\n\t\t\tid = item[ idProperty ];\n\t\t\tindex = this._items.indexOf( item );\n\t\t\titemDoesNotExist = ( index == -1 || !this._itemMap.get( id ) );\n\t\t}\n\n\t\tif ( itemDoesNotExist ) {\n\t\t\t/**\n\t\t\t * Item not found.\n\t\t\t *\n\t\t\t * @error collection-remove-404\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'collection-remove-404: Item not found.', this );\n\t\t}\n\n\t\tthis._items.splice( index, 1 );\n\t\tthis._itemMap.delete( id );\n\n\t\tconst externalItem = this._bindToInternalToExternalMap.get( item );\n\t\tthis._bindToInternalToExternalMap.delete( item );\n\t\tthis._bindToExternalToInternalMap.delete( externalItem );\n\n\t\tthis.fire( 'remove', item, index );\n\n\t\treturn item;\n\t}\n\n\t/**\n\t * Executes the callback for each item in the collection and composes an array or values returned by this callback.\n\t *\n\t * @param {Function} callback\n\t * @param {Object} callback.item\n\t * @param {Number} callback.index\n\t * @param {Object} ctx Context in which the `callback` will be called.\n\t * @returns {Array} The result of mapping.\n\t */\n\tmap( callback, ctx ) {\n\t\treturn this._items.map( callback, ctx );\n\t}\n\n\t/**\n\t * Finds the first item in the collection for which the `callback` returns a true value.\n\t *\n\t * @param {Function} callback\n\t * @param {Object} callback.item\n\t * @param {Number} callback.index\n\t * @param {Object} ctx Context in which the `callback` will be called.\n\t * @returns {Object} The item for which `callback` returned a true value.\n\t */\n\tfind( callback, ctx ) {\n\t\treturn this._items.find( callback, ctx );\n\t}\n\n\t/**\n\t * Returns an array with items for which the `callback` returned a true value.\n\t *\n\t * @param {Function} callback\n\t * @param {Object} callback.item\n\t * @param {Number} callback.index\n\t * @param {Object} ctx Context in which the `callback` will be called.\n\t * @returns {Object[]} The array with matching items.\n\t */\n\tfilter( callback, ctx ) {\n\t\treturn this._items.filter( callback, ctx );\n\t}\n\n\t/**\n\t * Removes all items from the collection and destroys the binding created using\n\t * {@link #bindTo}.\n\t */\n\tclear() {\n\t\tif ( this._bindToCollection ) {\n\t\t\tthis.stopListening( this._bindToCollection );\n\t\t\tthis._bindToCollection = null;\n\t\t}\n\n\t\twhile ( this.length ) {\n\t\t\tthis.remove( 0 );\n\t\t}\n\t}\n\n\t/**\n\t * Binds and synchronizes the collection with another one.\n\t *\n\t * The binding can be a simple factory:\n\t *\n\t *\t\tclass FactoryClass {\n\t *\t\t\tconstructor( data ) {\n\t *\t\t\t\tthis.label = data.label;\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst source = new Collection( { idProperty: 'label' } );\n\t *\t\tconst target = new Collection();\n\t *\n\t *\t\ttarget.bindTo( source ).as( FactoryClass );\n\t *\n\t *\t\tsource.add( { label: 'foo' } );\n\t *\t\tsource.add( { label: 'bar' } );\n\t *\n\t *\t\tconsole.log( target.length ); // 2\n\t *\t\tconsole.log( target.get( 1 ).label ); // 'bar'\n\t *\n\t *\t\tsource.remove( 0 );\n\t *\t\tconsole.log( target.length ); // 1\n\t *\t\tconsole.log( target.get( 0 ).label ); // 'bar'\n\t *\n\t * or the factory driven by a custom callback:\n\t *\n\t *\t\tclass FooClass {\n\t *\t\t\tconstructor( data ) {\n\t *\t\t\t\tthis.label = data.label;\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tclass BarClass {\n\t *\t\t\tconstructor( data ) {\n\t *\t\t\t\tthis.label = data.label;\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst source = new Collection( { idProperty: 'label' } );\n\t *\t\tconst target = new Collection();\n\t *\n\t *\t\ttarget.bindTo( source ).using( ( item ) => {\n\t *\t\t\tif ( item.label == 'foo' ) {\n\t *\t\t\t\treturn new FooClass( item );\n\t *\t\t\t} else {\n\t *\t\t\t\treturn new BarClass( item );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\tsource.add( { label: 'foo' } );\n\t *\t\tsource.add( { label: 'bar' } );\n\t *\n\t *\t\tconsole.log( target.length ); // 2\n\t *\t\tconsole.log( target.get( 0 ) instanceof FooClass ); // true\n\t *\t\tconsole.log( target.get( 1 ) instanceof BarClass ); // true\n\t *\n\t * or the factory out of property name:\n\t *\n\t *\t\tconst source = new Collection( { idProperty: 'label' } );\n\t *\t\tconst target = new Collection();\n\t *\n\t *\t\ttarget.bindTo( source ).using( 'label' );\n\t *\n\t *\t\tsource.add( { label: { value: 'foo' } } );\n\t *\t\tsource.add( { label: { value: 'bar' } } );\n\t *\n\t *\t\tconsole.log( target.length ); // 2\n\t *\t\tconsole.log( target.get( 0 ).value ); // 'foo'\n\t *\t\tconsole.log( target.get( 1 ).value ); // 'bar'\n\t *\n\t * It's possible to skip specified items by returning falsy value:\n\t *\n\t *\t\tconst source = new Collection();\n\t *\t\tconst target = new Collection();\n\t *\n\t *\t\ttarget.bindTo( source ).using( item => {\n\t *\t\t\tif ( item.hidden ) {\n\t *\t\t\t\treturn null;\n\t *\t\t\t}\n\t *\n\t *\t\t\treturn item;\n\t *\t\t} );\n\t *\n\t *\t\tsource.add( { hidden: true } );\n\t *\t\tsource.add( { hidden: false } );\n\t *\n\t *\t\tconsole.log( source.length ); // 2\n\t *\t\tconsole.log( target.length ); // 1\n\t *\n\t * **Note**: {@link #clear} can be used to break the binding.\n\t *\n\t * @param {module:utils/collection~Collection} externalCollection A collection to be bound.\n\t * @returns {Object}\n\t * @returns {module:utils/collection~CollectionBindToChain} The binding chain object.\n\t */\n\tbindTo( externalCollection ) {\n\t\tif ( this._bindToCollection ) {\n\t\t\t/**\n\t\t\t * The collection cannot be bound more than once.\n\t\t\t *\n\t\t\t * @error collection-bind-to-rebind\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'collection-bind-to-rebind: The collection cannot be bound more than once.', this );\n\t\t}\n\n\t\tthis._bindToCollection = externalCollection;\n\n\t\treturn {\n\t\t\tas: Class => {\n\t\t\t\tthis._setUpBindToBinding( item => new Class( item ) );\n\t\t\t},\n\n\t\t\tusing: callbackOrProperty => {\n\t\t\t\tif ( typeof callbackOrProperty == 'function' ) {\n\t\t\t\t\tthis._setUpBindToBinding( item => callbackOrProperty( item ) );\n\t\t\t\t} else {\n\t\t\t\t\tthis._setUpBindToBinding( item => item[ callbackOrProperty ] );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Finalizes and activates a binding initiated by {#bindTo}.\n\t *\n\t * @protected\n\t * @param {Function} factory A function which produces collection items.\n\t */\n\t_setUpBindToBinding( factory ) {\n\t\tconst externalCollection = this._bindToCollection;\n\n\t\t// Adds the item to the collection once a change has been done to the external collection.\n\t\t//\n\t\t// @private\n\t\tconst addItem = ( evt, externalItem, index ) => {\n\t\t\tconst isExternalBoundToThis = externalCollection._bindToCollection == this;\n\t\t\tconst externalItemBound = externalCollection._bindToInternalToExternalMap.get( externalItem );\n\n\t\t\t// If an external collection is bound to this collection, which makes it a 2–way binding,\n\t\t\t// and the particular external collection item is already bound, don't add it here.\n\t\t\t// The external item has been created **out of this collection's item** and (re)adding it will\n\t\t\t// cause a loop.\n\t\t\tif ( isExternalBoundToThis && externalItemBound ) {\n\t\t\t\tthis._bindToExternalToInternalMap.set( externalItem, externalItemBound );\n\t\t\t\tthis._bindToInternalToExternalMap.set( externalItemBound, externalItem );\n\t\t\t} else {\n\t\t\t\tconst item = factory( externalItem );\n\n\t\t\t\t// When there is no item we need to remember skipped index first and then we can skip this item.\n\t\t\t\tif ( !item ) {\n\t\t\t\t\tthis._skippedIndexesFromExternal.push( index );\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Lets try to put item at the same index as index in external collection\n\t\t\t\t// but when there are a skipped items in one or both collections we need to recalculate this index.\n\t\t\t\tlet finalIndex = index;\n\n\t\t\t\t// When we try to insert item after some skipped items from external collection we need\n\t\t\t\t// to include this skipped items and decrease index.\n\t\t\t\t//\n\t\t\t\t// For the following example:\n\t\t\t\t// external -> [ 'A', 'B - skipped for internal', 'C - skipped for internal' ]\n\t\t\t\t// internal -> [ A ]\n\t\t\t\t//\n\t\t\t\t// Another item is been added at the end of external collection:\n\t\t\t\t// external.add( 'D' )\n\t\t\t\t// external -> [ 'A', 'B - skipped for internal', 'C - skipped for internal', 'D' ]\n\t\t\t\t//\n\t\t\t\t// We can't just add 'D' to internal at the same index as index in external because\n\t\t\t\t// this will produce empty indexes what is invalid:\n\t\t\t\t// internal -> [ 'A', empty, empty, 'D' ]\n\t\t\t\t//\n\t\t\t\t// So we need to include skipped items and decrease index\n\t\t\t\t// internal -> [ 'A', 'D' ]\n\t\t\t\tfor ( const skipped of this._skippedIndexesFromExternal ) {\n\t\t\t\t\tif ( index > skipped ) {\n\t\t\t\t\t\tfinalIndex--;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// We need to take into consideration that external collection could skip some items from\n\t\t\t\t// internal collection.\n\t\t\t\t//\n\t\t\t\t// For the following example:\n\t\t\t\t// internal -> [ 'A', 'B - skipped for external', 'C - skipped for external' ]\n\t\t\t\t// external -> [ A ]\n\t\t\t\t//\n\t\t\t\t// Another item is been added at the end of external collection:\n\t\t\t\t// external.add( 'D' )\n\t\t\t\t// external -> [ 'A', 'D' ]\n\t\t\t\t//\n\t\t\t\t// We need to include skipped items and place new item after them:\n\t\t\t\t// internal -> [ 'A', 'B - skipped for external', 'C - skipped for external', 'D' ]\n\t\t\t\tfor ( const skipped of externalCollection._skippedIndexesFromExternal ) {\n\t\t\t\t\tif ( finalIndex >= skipped ) {\n\t\t\t\t\t\tfinalIndex++;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis._bindToExternalToInternalMap.set( externalItem, item );\n\t\t\t\tthis._bindToInternalToExternalMap.set( item, externalItem );\n\t\t\t\tthis.add( item, finalIndex );\n\n\t\t\t\t// After adding new element to internal collection we need update indexes\n\t\t\t\t// of skipped items in external collection.\n\t\t\t\tfor ( let i = 0; i < externalCollection._skippedIndexesFromExternal.length; i++ ) {\n\t\t\t\t\tif ( finalIndex <= externalCollection._skippedIndexesFromExternal[ i ] ) {\n\t\t\t\t\t\texternalCollection._skippedIndexesFromExternal[ i ]++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Load the initial content of the collection.\n\t\tfor ( const externalItem of externalCollection ) {\n\t\t\taddItem( null, externalItem, externalCollection.getIndex( externalItem ) );\n\t\t}\n\n\t\t// Synchronize the with collection as new items are added.\n\t\tthis.listenTo( externalCollection, 'add', addItem );\n\n\t\t// Synchronize the with collection as new items are removed.\n\t\tthis.listenTo( externalCollection, 'remove', ( evt, externalItem, index ) => {\n\t\t\tconst item = this._bindToExternalToInternalMap.get( externalItem );\n\n\t\t\tif ( item ) {\n\t\t\t\tthis.remove( item );\n\t\t\t}\n\n\t\t\t// After removing element from external collection we need update/remove indexes\n\t\t\t// of skipped items in internal collection.\n\t\t\tthis._skippedIndexesFromExternal = this._skippedIndexesFromExternal.reduce( ( result, skipped ) => {\n\t\t\t\tif ( index < skipped ) {\n\t\t\t\t\tresult.push( skipped - 1 );\n\t\t\t\t}\n\n\t\t\t\tif ( index > skipped ) {\n\t\t\t\t\tresult.push( skipped );\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}, [] );\n\t\t} );\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._items[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Fired when an item is added to the collection.\n\t *\n\t * @event add\n\t * @param {Object} item The added item.\n\t */\n\n\t/**\n\t * Fired when an item is removed from the collection.\n\t *\n\t * @event remove\n\t * @param {Object} item The removed item.\n\t * @param {Number} index Index from which item was removed.\n\t */\n}\n\nmix( Collection, EmitterMixin );\n\n/**\n * An object returned by the {@link module:utils/collection~Collection#bindTo `bindTo()`} method\n * providing functions that specify the type of the binding.\n *\n * See the {@link module:utils/collection~Collection#bindTo `bindTo()`} documentation for examples.\n *\n * @interface module:utils/collection~CollectionBindToChain\n */\n\n/**\n * Creates a callback or a property binding.\n *\n * @method #using\n * @param {Function|String} callbackOrProperty When the function is passed, it should return\n * the collection items. When the string is provided, the property value is used to create the bound collection items.\n */\n\n/**\n * Creates the class factory binding in which items of the source collection are passed to\n * the constructor of the specified class.\n *\n * @method #as\n * @param {Function} Class The class constructor used to create instances in the factory.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 core/plugincollection\n */\n\n/* globals console */\n\nimport CKEditorError, { attachLinkToDocumentation } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Manages a list of CKEditor plugins, including loading, resolving dependencies and initialization.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class PluginCollection {\n\t/**\n\t * Creates an instance of the plugin collection class.\n\t * Allows loading and initializing plugins and their dependencies.\n\t * Allows to provide a list of already loaded plugins. These plugins will not be destroyed along with this collection.\n\t *\n\t * @param {module:core/editor/editor~Editor|module:core/context~Context} context\n\t * @param {Array.<Function>} [availablePlugins] Plugins (constructors) which the collection will be able to use\n\t * when {@link module:core/plugincollection~PluginCollection#init} is used with plugin names (strings, instead of constructors).\n\t * Usually, the editor will pass its built-in plugins to the collection so they can later be\n\t * used in `config.plugins` or `config.removePlugins` by names.\n\t * @param {Iterable.<Array>} contextPlugins A list of already initialized plugins represented by a\n\t * `[ PluginConstructor, pluginInstance ]` pair.\n\t */\n\tconstructor( context, availablePlugins = [], contextPlugins = [] ) {\n\t\t/**\n\t\t * @protected\n\t\t * @type {module:core/editor/editor~Editor|module:core/context~Context}\n\t\t */\n\t\tthis._context = context;\n\n\t\t/**\n\t\t * @protected\n\t\t * @type {Map}\n\t\t */\n\t\tthis._plugins = new Map();\n\n\t\t/**\n\t\t * A map of plugin constructors that can be retrieved by their names.\n\t\t *\n\t\t * @protected\n\t\t * @type {Map.<String|Function,Function>}\n\t\t */\n\t\tthis._availablePlugins = new Map();\n\n\t\tfor ( const PluginConstructor of availablePlugins ) {\n\t\t\tif ( PluginConstructor.pluginName ) {\n\t\t\t\tthis._availablePlugins.set( PluginConstructor.pluginName, PluginConstructor );\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Map of {@link module:core/contextplugin~ContextPlugin context plugins} which can be retrieved by their constructors or instances.\n\t\t *\n\t\t * @protected\n\t\t * @type {Map<Function,Function>}\n\t\t */\n\t\tthis._contextPlugins = new Map();\n\n\t\tfor ( const [ PluginConstructor, pluginInstance ] of contextPlugins ) {\n\t\t\tthis._contextPlugins.set( PluginConstructor, pluginInstance );\n\t\t\tthis._contextPlugins.set( pluginInstance, PluginConstructor );\n\n\t\t\t// To make it possible to require a plugin by its name.\n\t\t\tif ( PluginConstructor.pluginName ) {\n\t\t\t\tthis._availablePlugins.set( PluginConstructor.pluginName, PluginConstructor );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Returns `[ PluginConstructor, pluginInstance ]` pairs.\n\t *\n\t * @returns {Iterable.<Array>}\n\t */\n\t* [ Symbol.iterator ]() {\n\t\tfor ( const entry of this._plugins ) {\n\t\t\tif ( typeof entry[ 0 ] == 'function' ) {\n\t\t\t\tyield entry;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Gets the plugin instance by its constructor or name.\n\t *\n\t *\t\t// Check if 'Clipboard' plugin was loaded.\n\t *\t\tif ( editor.plugins.has( 'Clipboard' ) ) {\n\t *\t\t\t// Get clipboard plugin instance\n\t *\t\t\tconst clipboard = editor.plugins.get( 'Clipboard' );\n\t *\n\t *\t\t\tthis.listenTo( clipboard, 'inputTransformation', ( evt, data ) => {\n\t *\t\t\t\t// Do something on clipboard input.\n\t *\t\t\t} );\n\t *\t\t}\n\t *\n\t * **Note**: This method will throw error if plugin is not loaded. Use `{@link #has editor.plugins.has()}`\n\t * to check if plugin is available.\n\t *\n\t * @param {Function|String} key The plugin constructor or {@link module:core/plugin~PluginInterface.pluginName name}.\n\t * @returns {module:core/plugin~PluginInterface}\n\t */\n\tget( key ) {\n\t\tconst plugin = this._plugins.get( key );\n\n\t\tif ( !plugin ) {\n\t\t\t/**\n\t\t\t * The plugin is not loaded and could not be obtained.\n\t\t\t *\n\t\t\t * Plugin classes (constructors) need to be provided to the editor and must be loaded before they can be obtained from\n\t\t\t * the plugin collection.\n\t\t\t * This is usually done in CKEditor 5 builds by setting the {@link module:core/editor/editor~Editor.builtinPlugins}\n\t\t\t * property.\n\t\t\t *\n\t\t\t * **Note**: You can use `{@link module:core/plugincollection~PluginCollection#has editor.plugins.has()}`\n\t\t\t * to check if plugin was loaded.\n\t\t\t *\n\t\t\t * @error plugincollection-plugin-not-loaded\n\t\t\t * @param {String} plugin The name of the plugin which is not loaded.\n\t\t\t */\n\t\t\tconst errorMsg = 'plugincollection-plugin-not-loaded: The requested plugin is not loaded.';\n\n\t\t\tlet pluginName = key;\n\n\t\t\tif ( typeof key == 'function' ) {\n\t\t\t\tpluginName = key.pluginName || key.name;\n\t\t\t}\n\n\t\t\tthrow new CKEditorError( errorMsg, this._context, { plugin: pluginName } );\n\t\t}\n\n\t\treturn plugin;\n\t}\n\n\t/**\n\t * Checks if a plugin is loaded.\n\t *\n\t *\t\t// Check if the 'Clipboard' plugin was loaded.\n\t *\t\tif ( editor.plugins.has( 'Clipboard' ) ) {\n\t *\t\t\t// Now use the clipboard plugin instance:\n\t *\t\t\tconst clipboard = editor.plugins.get( 'Clipboard' );\n\t *\n\t *\t\t\t// ...\n\t *\t\t}\n\t *\n\t * @param {Function|String} key The plugin constructor or {@link module:core/plugin~PluginInterface.pluginName name}.\n\t * @returns {Boolean}\n\t */\n\thas( key ) {\n\t\treturn this._plugins.has( key );\n\t}\n\n\t/**\n\t * Initializes a set of plugins and adds them to the collection.\n\t *\n\t * @param {Array.<Function|String>} plugins An array of {@link module:core/plugin~PluginInterface plugin constructors}\n\t * or {@link module:core/plugin~PluginInterface.pluginName plugin names}. The second option (names) works only if\n\t * `availablePlugins` were passed to the {@link #constructor}.\n\t * @param {Array.<String|Function>} [removePlugins] Names of plugins or plugin constructors\n\t * that should not be loaded (despite being specified in the `plugins` array).\n\t * @returns {Promise.<module:core/plugin~LoadedPlugins>} A promise which gets resolved once all plugins are loaded\n\t * and available in the collection.\n\t */\n\tinit( plugins, removePlugins = [] ) {\n\t\tconst that = this;\n\t\tconst context = this._context;\n\t\tconst loading = new Set();\n\t\tconst loaded = [];\n\n\t\tconst pluginConstructors = mapToAvailableConstructors( plugins );\n\t\tconst removePluginConstructors = mapToAvailableConstructors( removePlugins );\n\t\tconst missingPlugins = getMissingPluginNames( plugins );\n\n\t\tif ( missingPlugins ) {\n\t\t\t/**\n\t\t\t * Some plugins are not available and could not be loaded.\n\t\t\t *\n\t\t\t * Plugin classes (constructors) need to be provided to the editor before they can be loaded by name.\n\t\t\t * This is usually done in CKEditor 5 builds by setting the {@link module:core/editor/editor~Editor.builtinPlugins}\n\t\t\t * property.\n\t\t\t *\n\t\t\t * **If you see this warning when using one of the {@glink builds/index CKEditor 5 Builds}**, it means\n\t\t\t * that you try to enable a plugin which was not included in that build. This may be due to a typo\n\t\t\t * in the plugin name or simply because that plugin is not a part of this build. In the latter scenario,\n\t\t\t * read more about {@glink builds/guides/development/custom-builds custom builds}.\n\t\t\t *\n\t\t\t * **If you see this warning when using one of the editor creators directly** (not a build), then it means\n\t\t\t * that you tried loading plugins by name. However, unlike CKEditor 4, CKEditor 5 does not implement a \"plugin loader\".\n\t\t\t * This means that CKEditor 5 does not know where to load the plugin modules from. Therefore, you need to\n\t\t\t * provide each plugin through reference (as a constructor function). Check out the examples in\n\t\t\t * {@glink builds/guides/integration/advanced-setup#scenario-2-building-from-source \"Building from source\"}.\n\t\t\t *\n\t\t\t * @error plugincollection-plugin-not-found\n\t\t\t * @param {Array.<String>} plugins The name of the plugins which could not be loaded.\n\t\t\t */\n\t\t\tconst errorMsg = 'plugincollection-plugin-not-found: Some plugins are not available and could not be loaded.';\n\n\t\t\t// Log the error so it's more visible on the console. Hopefully, for better DX.\n\t\t\tconsole.error( attachLinkToDocumentation( errorMsg ), { plugins: missingPlugins } );\n\n\t\t\treturn Promise.reject( new CKEditorError( errorMsg, context, { plugins: missingPlugins } ) );\n\t\t}\n\n\t\treturn Promise.all( pluginConstructors.map( loadPlugin ) )\n\t\t\t.then( () => initPlugins( loaded, 'init' ) )\n\t\t\t.then( () => initPlugins( loaded, 'afterInit' ) )\n\t\t\t.then( () => loaded );\n\n\t\tfunction loadPlugin( PluginConstructor ) {\n\t\t\tif ( removePluginConstructors.includes( PluginConstructor ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The plugin is already loaded or being loaded - do nothing.\n\t\t\tif ( that._plugins.has( PluginConstructor ) || loading.has( PluginConstructor ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn instantiatePlugin( PluginConstructor )\n\t\t\t\t.catch( err => {\n\t\t\t\t\t/**\n\t\t\t\t\t * It was not possible to load the plugin.\n\t\t\t\t\t *\n\t\t\t\t\t * This is a generic error logged to the console when a JavaSript error is thrown during the initialization\n\t\t\t\t\t * of one of the plugins.\n\t\t\t\t\t *\n\t\t\t\t\t * If you correctly handled the promise returned by the editor's `create()` method (like shown below),\n\t\t\t\t\t * you will find the original error logged to the console, too:\n\t\t\t\t\t *\n\t\t\t\t\t *\t\tClassicEditor.create( document.getElementById( 'editor' ) )\n\t\t\t\t\t *\t\t\t.then( editor => {\n\t\t\t\t\t *\t\t\t\t// ...\n\t\t\t\t\t * \t\t\t} )\n\t\t\t\t\t *\t\t\t.catch( error => {\n\t\t\t\t\t *\t\t\t\tconsole.error( error );\n\t\t\t\t\t *\t\t\t} );\n\t\t\t\t\t *\n\t\t\t\t\t * @error plugincollection-load\n\t\t\t\t\t * @param {String} plugin The name of the plugin that could not be loaded.\n\t\t\t\t\t */\n\t\t\t\t\tconsole.error( attachLinkToDocumentation(\n\t\t\t\t\t\t'plugincollection-load: It was not possible to load the plugin.'\n\t\t\t\t\t), { plugin: PluginConstructor } );\n\n\t\t\t\t\tthrow err;\n\t\t\t\t} );\n\t\t}\n\n\t\tfunction initPlugins( loadedPlugins, method ) {\n\t\t\treturn loadedPlugins.reduce( ( promise, plugin ) => {\n\t\t\t\tif ( !plugin[ method ] ) {\n\t\t\t\t\treturn promise;\n\t\t\t\t}\n\n\t\t\t\tif ( that._contextPlugins.has( plugin ) ) {\n\t\t\t\t\treturn promise;\n\t\t\t\t}\n\n\t\t\t\treturn promise.then( plugin[ method ].bind( plugin ) );\n\t\t\t}, Promise.resolve() );\n\t\t}\n\n\t\tfunction instantiatePlugin( PluginConstructor ) {\n\t\t\treturn new Promise( resolve => {\n\t\t\t\tloading.add( PluginConstructor );\n\n\t\t\t\tif ( PluginConstructor.requires ) {\n\t\t\t\t\tPluginConstructor.requires.forEach( RequiredPluginConstructorOrName => {\n\t\t\t\t\t\tconst RequiredPluginConstructor = getPluginConstructor( RequiredPluginConstructorOrName );\n\n\t\t\t\t\t\tif ( PluginConstructor.isContextPlugin && !RequiredPluginConstructor.isContextPlugin ) {\n\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t * If a plugin is a context plugin, all plugins it requires should also be context plugins\n\t\t\t\t\t\t\t * instead of plugins. In other words, if one plugin can be used in the context,\n\t\t\t\t\t\t\t * all its requirements should also be ready to be used in the context. Note that the context\n\t\t\t\t\t\t\t * provides only a part of the API provided by the editor. If one plugin needs a full\n\t\t\t\t\t\t\t * editor API, all plugins which require it are considered as plugins that need a full\n\t\t\t\t\t\t\t * editor API.\n\t\t\t\t\t\t\t *\n\t\t\t\t\t\t\t * @error plugincollection-context-required\n\t\t\t\t\t\t\t * @param {String} plugin The name of the required plugin.\n\t\t\t\t\t\t\t * @param {String} requiredBy The name of the parent plugin.\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t\t\t'plugincollection-context-required: Context plugin can not require plugin which is not a context plugin',\n\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t{ plugin: RequiredPluginConstructor.name, requiredBy: PluginConstructor.name }\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( removePlugins.includes( RequiredPluginConstructor ) ) {\n\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t * Cannot load a plugin because one of its dependencies is listed in the `removePlugins` option.\n\t\t\t\t\t\t\t *\n\t\t\t\t\t\t\t * @error plugincollection-required\n\t\t\t\t\t\t\t * @param {String} plugin The name of the required plugin.\n\t\t\t\t\t\t\t * @param {String} requiredBy The name of the parent plugin.\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t\t\t'plugincollection-required: Cannot load a plugin because one of its dependencies is listed in' +\n\t\t\t\t\t\t\t\t'the `removePlugins` option.',\n\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t{ plugin: RequiredPluginConstructor.name, requiredBy: PluginConstructor.name }\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tloadPlugin( RequiredPluginConstructor );\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\tconst plugin = that._contextPlugins.get( PluginConstructor ) || new PluginConstructor( context );\n\t\t\t\tthat._add( PluginConstructor, plugin );\n\t\t\t\tloaded.push( plugin );\n\n\t\t\t\tresolve();\n\t\t\t} );\n\t\t}\n\n\t\tfunction getPluginConstructor( PluginConstructorOrName ) {\n\t\t\tif ( typeof PluginConstructorOrName == 'function' ) {\n\t\t\t\treturn PluginConstructorOrName;\n\t\t\t}\n\n\t\t\treturn that._availablePlugins.get( PluginConstructorOrName );\n\t\t}\n\n\t\tfunction getMissingPluginNames( plugins ) {\n\t\t\tconst missingPlugins = [];\n\n\t\t\tfor ( const pluginNameOrConstructor of plugins ) {\n\t\t\t\tif ( !getPluginConstructor( pluginNameOrConstructor ) ) {\n\t\t\t\t\tmissingPlugins.push( pluginNameOrConstructor );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn missingPlugins.length ? missingPlugins : null;\n\t\t}\n\n\t\tfunction mapToAvailableConstructors( plugins ) {\n\t\t\treturn plugins\n\t\t\t\t.map( pluginNameOrConstructor => getPluginConstructor( pluginNameOrConstructor ) )\n\t\t\t\t.filter( PluginConstructor => !!PluginConstructor );\n\t\t}\n\t}\n\n\t/**\n\t * Destroys all loaded plugins.\n\t *\n\t * @returns {Promise}\n\t */\n\tdestroy() {\n\t\tconst promises = [];\n\n\t\tfor ( const [ , pluginInstance ] of this ) {\n\t\t\tif ( typeof pluginInstance.destroy == 'function' && !this._contextPlugins.has( pluginInstance ) ) {\n\t\t\t\tpromises.push( pluginInstance.destroy() );\n\t\t\t}\n\t\t}\n\n\t\treturn Promise.all( promises );\n\t}\n\n\t/**\n\t * Adds the plugin to the collection. Exposed mainly for testing purposes.\n\t *\n\t * @protected\n\t * @param {Function} PluginConstructor The plugin constructor.\n\t * @param {module:core/plugin~PluginInterface} plugin The instance of the plugin.\n\t */\n\t_add( PluginConstructor, plugin ) {\n\t\tthis._plugins.set( PluginConstructor, plugin );\n\n\t\tconst pluginName = PluginConstructor.pluginName;\n\n\t\tif ( !pluginName ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this._plugins.has( pluginName ) ) {\n\t\t\t/**\n\t\t\t * Two plugins with the same {@link module:core/plugin~PluginInterface.pluginName} were loaded.\n\t\t\t * This will lead to runtime conflicts between these plugins.\n\t\t\t *\n\t\t\t * In practice, this warning usually means that new plugins were added to an existing CKEditor 5 build.\n\t\t\t * Plugins should always be added to a source version of the editor (`@ckeditor/ckeditor5-editor-*`),\n\t\t\t * not to an editor imported from one of the `@ckeditor/ckeditor5-build-*` packages.\n\t\t\t *\n\t\t\t * Check your import paths and the list of plugins passed to\n\t\t\t * {@link module:core/editor/editor~Editor.create `Editor.create()`}\n\t\t\t * or specified in {@link module:core/editor/editor~Editor.builtinPlugins `Editor.builtinPlugins`}.\n\t\t\t *\n\t\t\t * The second option is that your `node_modules/` directory contains duplicated versions of the same\n\t\t\t * CKEditor 5 packages. Normally, on clean installations, npm deduplicates packages in `node_modules/`, so\n\t\t\t * it may be enough to call `rm -rf node_modules && npm i`. However, if you installed conflicting versions\n\t\t\t * of packages, their dependencies may need to be installed in more than one version which may lead to this\n\t\t\t * warning.\n\t\t\t *\n\t\t\t * Technically speaking, this error occurs because after adding a plugin to an existing editor build\n\t\t\t * dependencies of this plugin are being duplicated.\n\t\t\t * They are already built into that editor build and now get added for the second time as dependencies\n\t\t\t * of the plugin you are installing.\n\t\t\t *\n\t\t\t * Read more about {@glink builds/guides/integration/installing-plugins installing plugins}.\n\t\t\t *\n\t\t\t * @error plugincollection-plugin-name-conflict\n\t\t\t * @param {String} pluginName The duplicated plugin name.\n\t\t\t * @param {Function} plugin1 The first plugin constructor.\n\t\t\t * @param {Function} plugin2 The second plugin constructor.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'plugincollection-plugin-name-conflict: Two plugins with the same name were loaded.',\n\t\t\t\tnull,\n\t\t\t\t{ pluginName, plugin1: this._plugins.get( pluginName ).constructor, plugin2: PluginConstructor }\n\t\t\t);\n\t\t}\n\n\t\tthis._plugins.set( pluginName, plugin );\n\t}\n}\n\nmix( PluginCollection, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals window */\n\n/**\n * @module utils/translation-service\n */\n\n/* istanbul ignore else */\nif ( !window.CKEDITOR_TRANSLATIONS ) {\n\twindow.CKEDITOR_TRANSLATIONS = {};\n}\n\n/**\n * Adds translations to existing ones.\n * These translations will later be available for the {@link module:utils/translation-service~translate `translate()`} function.\n *\n *\t\tadd( 'pl', {\n *\t\t\t'OK': 'OK',\n *\t\t\t'Cancel [context: reject]': 'Anuluj'\n *\t\t} );\n *\n * If you cannot import this function from this module (e.g. because you use a CKEditor 5 build), then you can\n * still add translations by extending the global `window.CKEDITOR_TRANSLATIONS` object by using a function like\n * the one below:\n *\n *\t\tfunction addTranslations( language, translations ) {\n *\t\t\tif ( !window.CKEDITOR_TRANSLATIONS ) {\n *\t\t\t\twindow.CKEDITOR_TRANSLATIONS = {};\n *\t\t\t}\n *\n *\t\t\tconst dictionary = window.CKEDITOR_TRANSLATIONS[ language ] || ( window.CKEDITOR_TRANSLATIONS[ language ] = {} );\n *\n *\t\t\t// Extend the dictionary for the given language.\n *\t\t\tObject.assign( dictionary, translations );\n *\t\t}\n *\n * @param {String} language Target language.\n * @param {Object.<String, String>} translations Translations which will be added to the dictionary.\n */\nexport function add( language, translations ) {\n\tconst dictionary = window.CKEDITOR_TRANSLATIONS[ language ] || ( window.CKEDITOR_TRANSLATIONS[ language ] = {} );\n\n\tObject.assign( dictionary, translations );\n}\n\n/**\n * Translates string if the translation of the string was previously added to the dictionary.\n * See {@link module:utils/translation-service Translation Service}.\n * This happens in a multi-language mode were translation modules are created by the bundler.\n *\n * When no translation is defined in the dictionary or the dictionary doesn't exist this function returns\n * the original string without the `'[context: ]'` (happens in development and single-language modes).\n *\n * In a single-language mode (when values passed to `t()` were replaced with target language strings) the dictionary\n * is left empty, so this function will return the original strings always.\n *\n *\t\ttranslate( 'pl', 'Cancel [context: reject]' );\n *\n * @param {String} language Target language.\n * @param {String} translationKey String that will be translated.\n * @returns {String} Translated sentence.\n */\nexport function translate( language, translationKey ) {\n\tconst numberOfLanguages = getNumberOfLanguages();\n\n\tif ( numberOfLanguages === 1 ) {\n\t\t// Override the language to the only supported one.\n\t\t// This can't be done in the `Locale` class, because the translations comes after the `Locale` class initialization.\n\t\tlanguage = Object.keys( window.CKEDITOR_TRANSLATIONS )[ 0 ];\n\t}\n\n\tif ( numberOfLanguages === 0 || !hasTranslation( language, translationKey ) ) {\n\t\treturn translationKey.replace( / \\[context: [^\\]]+\\]$/, '' );\n\t}\n\n\tconst dictionary = window.CKEDITOR_TRANSLATIONS[ language ];\n\n\t// In case of missing translations we still need to cut off the `[context: ]` parts.\n\treturn dictionary[ translationKey ].replace( / \\[context: [^\\]]+\\]$/, '' );\n}\n\n/**\n * Clears dictionaries for test purposes.\n *\n * @protected\n */\nexport function _clear() {\n\twindow.CKEDITOR_TRANSLATIONS = {};\n}\n\n// Checks whether the dictionary exists and translation in that dictionary exists.\nfunction hasTranslation( language, translationKey ) {\n\treturn (\n\t\t( language in window.CKEDITOR_TRANSLATIONS ) &&\n\t\t( translationKey in window.CKEDITOR_TRANSLATIONS[ language ] )\n\t);\n}\n\nfunction getNumberOfLanguages() {\n\treturn Object.keys( window.CKEDITOR_TRANSLATIONS ).length;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/locale\n */\n\n/* globals console */\n\nimport { translate } from './translation-service';\n\nconst RTL_LANGUAGE_CODES = [ 'ar', 'fa', 'he', 'ku', 'ug' ];\n\n/**\n * Represents the localization services.\n */\nexport default class Locale {\n\t/**\n\t * Creates a new instance of the Locale class. Learn more about\n\t * {@glink features/ui-language configuring language of the editor}.\n\t *\n\t * @param {Object} [options] Locale configuration.\n\t * @param {String} [options.uiLanguage='en'] The editor UI language code in the\n\t * [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. See {@link #uiLanguage}.\n\t * @param {String} [options.contentLanguage] The editor content language code in the\n\t * [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. If not specified, the same as `options.language`.\n\t * See {@link #contentLanguage}.\n\t */\n\tconstructor( options = {} ) {\n\t\t/**\n\t\t * The editor UI language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.\n\t\t *\n\t\t * If the {@link #contentLanguage content language} was not specified in the `Locale` constructor,\n\t\t * it also defines the language of the content.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.uiLanguage = options.uiLanguage || 'en';\n\n\t\t/**\n\t\t * The editor content language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.\n\t\t *\n\t\t * Usually the same as {@link #uiLanguage editor language}, it can be customized by passing an optional\n\t\t * argument to the `Locale` constructor.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.contentLanguage = options.contentLanguage || this.uiLanguage;\n\n\t\t/**\n\t\t * Text direction of the {@link #uiLanguage editor UI language}. Either `'ltr'` or `'rtl'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.uiLanguageDirection = getLanguageDirection( this.uiLanguage );\n\n\t\t/**\n\t\t * Text direction of the {@link #contentLanguage editor content language}.\n\t\t *\n\t\t * If the content language was passed directly to the `Locale` constructor, this property represents the\n\t\t * direction of that language.\n\t\t *\n\t\t * If the {@link #contentLanguage editor content language} was derived from the {@link #uiLanguage editor language},\n\t\t * the content language direction is the same as the {@link #uiLanguageDirection UI language direction}.\n\t\t *\n\t\t * The value is either `'ltr'` or `'rtl'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.contentLanguageDirection = getLanguageDirection( this.contentLanguage );\n\n\t\t/**\n\t\t * Translates the given string to the {@link #uiLanguage}. This method is also available in\n\t\t * {@link module:core/editor/editor~Editor#t} and {@link module:ui/view~View#t}.\n\t\t *\n\t\t * The strings may contain placeholders (`%<index>`) for values which are passed as the second argument.\n\t\t * `<index>` is the index in the `values` array.\n\t\t *\n\t\t *\t\teditor.t( 'Created file \"%0\" in %1ms.', [ fileName, timeTaken ] );\n\t\t *\n\t\t * This method's context is statically bound to Locale instance,\n\t\t * so it can be called as a function:\n\t\t *\n\t\t *\t\tconst t = this.t;\n\t\t *\t\tt( 'Label' );\n\t\t *\n\t\t * @method #t\n\t\t * @param {String} str The string to translate.\n\t\t * @param {String[]} [values] Values that should be used to interpolate the string.\n\t\t */\n\t\tthis.t = ( ...args ) => this._t( ...args );\n\t}\n\n\t/**\n\t * The editor UI language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.\n\t *\n\t * **Note**: This property has been deprecated. Please use {@link #uiLanguage} and {@link #contentLanguage}\n\t * properties instead.\n\t *\n\t * @deprecated\n\t * @member {String}\n\t */\n\tget language() {\n\t\t/**\n\t\t * The {@link module:utils/locale~Locale#language `Locale#language`} property has been deprecated and will\n\t\t * be removed in the near future. Please use {@link #uiLanguage} and {@link #contentLanguage} properties instead.\n\t\t *\n\t\t * @error locale-deprecated-language-property\n\t\t */\n\t\tconsole.warn(\n\t\t\t'locale-deprecated-language-property: ' +\n\t\t\t'The Locale#language property has been deprecated and will be removed in the near future. ' +\n\t\t\t'Please use #uiLanguage and #contentLanguage properties instead.' );\n\n\t\treturn this.uiLanguage;\n\t}\n\n\t/**\n\t * Base for the {@link #t} method.\n\t *\n\t * @private\n\t */\n\t_t( str, values ) {\n\t\tlet translatedString = translate( this.uiLanguage, str );\n\n\t\tif ( values ) {\n\t\t\ttranslatedString = translatedString.replace( /%(\\d+)/g, ( match, index ) => {\n\t\t\t\treturn ( index < values.length ) ? values[ index ] : match;\n\t\t\t} );\n\t\t}\n\n\t\treturn translatedString;\n\t}\n}\n\n// Helps determine whether a language is LTR or RTL.\n//\n// @param {String} language The ISO 639-1 language code.\n// @returns {String} 'ltr' or 'rtl\nfunction getLanguageDirection( languageCode ) {\n\treturn RTL_LANGUAGE_CODES.includes( languageCode ) ? 'rtl' : 'ltr';\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 core/context\n */\n\nimport Config from '@ckeditor/ckeditor5-utils/src/config';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport PluginCollection from './plugincollection';\nimport Locale from '@ckeditor/ckeditor5-utils/src/locale';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Provides a common, higher-level environment for solutions that use multiple {@link module:core/editor/editor~Editor editors}\n * or plugins that work outside the editor. Use it instead of {@link module:core/editor/editor~Editor.create `Editor.create()`}\n * in advanced application integrations.\n *\n * All configuration options passed to a context will be used as default options for editor instances initialized in that context.\n *\n * {@link module:core/contextplugin~ContextPlugin Context plugins} passed to a context instance will be shared among all\n * editor instances initialized in this context. These will be the same plugin instances for all the editors.\n *\n * **Note:** The context can only be initialized with {@link module:core/contextplugin~ContextPlugin context plugins}\n * (e.g. [comments](https://ckeditor.com/collaboration/comments/)). Regular {@link module:core/plugin~Plugin plugins} require an\n * editor instance to work and cannot be added to a context.\n *\n * **Note:** You can add a context plugin to an editor instance, though.\n *\n * If you are using multiple editor instances on one page and use any context plugins, create a context to share the configuration and\n * plugins among these editors. Some plugins will use the information about all existing editors to better integrate between them.\n *\n * If you are using plugins that do not require an editor to work (e.g. [comments](https://ckeditor.com/collaboration/comments/)),\n * enable and configure them using the context.\n *\n * If you are using only a single editor on each page, use {@link module:core/editor/editor~Editor.create `Editor.create()`} instead.\n * In such case, a context instance will be created by the editor instance in a transparent way.\n *\n * See {@link module:core/context~Context.create `Context.create()`} for usage examples.\n */\nexport default class Context {\n\t/**\n\t * Creates a context instance with a given configuration.\n\t *\n\t * Usually not to be used directly. See the static {@link module:core/context~Context.create `create()`} method.\n\t *\n\t * @param {Object} [config={}] The context configuration.\n\t */\n\tconstructor( config ) {\n\t\t/**\n\t\t * Stores all the configurations specific to this context instance.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/config~Config}\n\t\t */\n\t\tthis.config = new Config( config, this.constructor.defaultConfig );\n\n\t\tconst availablePlugins = this.constructor.builtinPlugins;\n\n\t\tthis.config.define( 'plugins', availablePlugins );\n\n\t\t/**\n\t\t * The plugins loaded and in use by this context instance.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:core/plugincollection~PluginCollection}\n\t\t */\n\t\tthis.plugins = new PluginCollection( this, availablePlugins );\n\n\t\tconst languageConfig = this.config.get( 'language' ) || {};\n\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = new Locale( {\n\t\t\tuiLanguage: typeof languageConfig === 'string' ? languageConfig : languageConfig.ui,\n\t\t\tcontentLanguage: this.config.get( 'language.content' )\n\t\t} );\n\n\t\t/**\n\t\t * Shorthand for {@link module:utils/locale~Locale#t}.\n\t\t *\n\t\t * @see module:utils/locale~Locale#t\n\t\t * @method #t\n\t\t */\n\t\tthis.t = this.locale.t;\n\n\t\t/**\n\t\t * A list of editors that this context instance is injected to.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/collection~Collection}\n\t\t */\n\t\tthis.editors = new Collection();\n\n\t\t/**\n\t\t * Reference to the editor which created the context.\n\t\t * Null when the context was created outside of the editor.\n\t\t *\n\t\t * It is used to destroy the context when removing the editor that has created the context.\n\t\t *\n\t\t * @private\n\t\t * @type {module:core/editor/editor~Editor|null}\n\t\t */\n\t\tthis._contextOwner = null;\n\t}\n\n\t/**\n\t * Loads and initializes plugins specified in the configuration.\n\t *\n\t * @returns {Promise.<module:core/plugin~LoadedPlugins>} A promise which resolves\n\t * once the initialization is completed, providing an array of loaded plugins.\n\t */\n\tinitPlugins() {\n\t\tconst plugins = this.config.get( 'plugins' ) || [];\n\n\t\tfor ( const Plugin of plugins ) {\n\t\t\tif ( typeof Plugin != 'function' ) {\n\t\t\t\t/**\n\t\t\t\t * Only a constructor function is allowed as a {@link module:core/contextplugin~ContextPlugin context plugin}.\n\t\t\t\t *\n\t\t\t\t * @error context-initplugins-constructor-only\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'context-initplugins-constructor-only: Only a constructor function is allowed as a context plugin.',\n\t\t\t\t\tnull,\n\t\t\t\t\t{ Plugin }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( Plugin.isContextPlugin !== true ) {\n\t\t\t\t/**\n\t\t\t\t * Only a plugin marked as a {@link module:core/contextplugin~ContextPlugin.isContextPlugin context plugin}\n\t\t\t\t * is allowed to be used with a context.\n\t\t\t\t *\n\t\t\t\t * @error context-initplugins-invalid-plugin\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'context-initplugins-invalid-plugin: Only a plugin marked as a context plugin is allowed to be used with a context.',\n\t\t\t\t\tnull,\n\t\t\t\t\t{ Plugin }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn this.plugins.init( plugins );\n\t}\n\n\t/**\n\t * Destroys the context instance and all editors used with the context,\n\t * releasing all resources used by the context.\n\t *\n\t * @returns {Promise} A promise that resolves once the context instance is fully destroyed.\n\t */\n\tdestroy() {\n\t\treturn Promise.all( Array.from( this.editors, editor => editor.destroy() ) )\n\t\t\t.then( () => this.plugins.destroy() );\n\t}\n\n\t/**\n\t * Adds a reference to the editor which is used with this context.\n\t *\n\t * When the given editor has created the context, the reference to this editor will be stored\n\t * as a {@link ~Context#_contextOwner}.\n\t *\n\t * This method should only be used by the editor.\n\t *\n\t * @protected\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {Boolean} isContextOwner Stores the given editor as a context owner.\n\t */\n\t_addEditor( editor, isContextOwner ) {\n\t\tif ( this._contextOwner ) {\n\t\t\t/**\n\t\t\t * Cannot add multiple editors to the context which is created by the editor.\n\t\t\t *\n\t\t\t * @error context-addEditor-private-context\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'context-addEditor-private-context: Cannot add multiple editors to the context which is created by the editor.'\n\t\t\t);\n\t\t}\n\n\t\tthis.editors.add( editor );\n\n\t\tif ( isContextOwner ) {\n\t\t\tthis._contextOwner = editor;\n\t\t}\n\t}\n\n\t/**\n\t * Removes a reference to the editor which was used with this context.\n\t * When the context was created by the given editor, the context will be destroyed.\n\t *\n\t * This method should only be used by the editor.\n\t *\n\t * @protected\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @return {Promise} A promise that resolves once the editor is removed from the context or when the context was destroyed.\n\t */\n\t_removeEditor( editor ) {\n\t\tif ( this.editors.has( editor ) ) {\n\t\t\tthis.editors.remove( editor );\n\t\t}\n\n\t\tif ( this._contextOwner === editor ) {\n\t\t\treturn this.destroy();\n\t\t}\n\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * Returns the context configuration which will be copied to the editors created using this context.\n\t *\n\t * The configuration returned by this method has the plugins configuration removed — plugins are shared with all editors\n\t * through another mechanism.\n\t *\n\t * This method should only be used by the editor.\n\t *\n\t * @protected\n\t * @returns {Object} Configuration as a plain object.\n\t */\n\t_getEditorConfig() {\n\t\tconst result = {};\n\n\t\tfor ( const name of this.config.names() ) {\n\t\t\tif ( ![ 'plugins', 'removePlugins', 'extraPlugins' ].includes( name ) ) {\n\t\t\t\tresult[ name ] = this.config.get( name );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Creates and initializes a new context instance.\n\t *\n\t *\t\tconst commonConfig = { ... }; // Configuration for all the plugins and editors.\n\t *\t\tconst editorPlugins = [ ... ]; // Regular plugins here.\n\t *\n\t *\t\tContext\n\t *\t\t\t.create( {\n\t *\t\t\t\t// Only context plugins here.\n\t *\t\t\t\tplugins: [ ... ],\n\t *\n\t *\t\t\t\t// Configure the language for all the editors (it cannot be overwritten).\n\t *\t\t\t\tlanguage: { ... },\n\t *\n\t *\t\t\t\t// Configuration for context plugins.\n\t *\t\t\t\tcomments: { ... },\n\t *\t\t\t\t...\n\t *\n\t *\t\t\t\t// Default configuration for editor plugins.\n\t *\t\t\t\ttoolbar: { ... },\n\t *\t\t\t\timage: { ... },\n\t *\t\t\t\t...\n\t *\t\t\t} )\n\t *\t\t\t.then( context => {\n\t *\t\t\t\tconst promises = [];\n\t *\n\t *\t\t\t\tpromises.push( ClassicEditor.create(\n\t *\t\t\t\t\tdocument.getElementById( 'editor1' ),\n\t *\t\t\t\t\t{\n\t *\t\t\t\t\t\teditorPlugins,\n\t *\t\t\t\t\t\tcontext\n\t *\t\t\t\t\t}\n\t *\t\t\t\t) );\n\t *\n\t *\t\t\t\tpromises.push( ClassicEditor.create(\n\t *\t\t\t\t\tdocument.getElementById( 'editor2' ),\n\t *\t\t\t\t\t{\n\t *\t\t\t\t\t\teditorPlugins,\n\t *\t\t\t\t\t\tcontext,\n\t *\t\t\t\t\t\ttoolbar: { ... } // You can overwrite the configuration of the context.\n\t *\t\t\t\t\t}\n\t *\t\t\t\t) );\n\t *\n\t *\t\t\t\treturn Promise.all( promises );\n\t *\t\t\t} );\n\t *\n\t * @param {Object} [config] The context configuration.\n\t * @returns {Promise} A promise resolved once the context is ready. The promise resolves with the created context instance.\n\t */\n\tstatic create( config ) {\n\t\treturn new Promise( resolve => {\n\t\t\tconst context = new this( config );\n\n\t\t\tresolve( context.initPlugins().then( () => context ) );\n\t\t} );\n\t}\n}\n\n/**\n * An array of plugins built into the `Context` class.\n *\n * It is used in CKEditor 5 builds featuring `Context` to provide a list of context plugins which are later automatically initialized\n * during the context initialization.\n *\n * They will be automatically initialized by `Context` unless `config.plugins` is passed.\n *\n *\t\t// Build some context plugins into the Context class first.\n *\t\tContext.builtinPlugins = [ FooPlugin, BarPlugin ];\n *\n *\t\t// Normally, you need to define config.plugins, but since Context.builtinPlugins was\n *\t\t// defined, now you can call create() without any configuration.\n *\t\tContext\n *\t\t\t.create()\n *\t\t\t.then( context => {\n *\t\t\t\tcontext.plugins.get( FooPlugin ); // -> An instance of the Foo plugin.\n *\t\t\t\tcontext.plugins.get( BarPlugin ); // -> An instance of the Bar plugin.\n *\t\t\t} );\n *\n * See also {@link module:core/editor/editor~Editor.builtinPlugins} and {@link module:core/context~Context.defaultConfig}.\n *\n * @static\n * @member {Array.<Function>} module:core/context~Context.builtinPlugins\n */\n\n/**\n * The default configuration which is built into the `Context` class.\n *\n * It is used in CKEditor 5 builds featuring `Context` to provide the default configuration options which are later used during the\n * context initialization.\n *\n *\t\tContext.defaultConfig = {\n *\t\t\tfoo: 1,\n *\t\t\tbar: 2\n *\t\t};\n *\n *\t\tContext\n *\t\t\t.create()\n *\t\t\t.then( context => {\n *\t\t\t\tcontext.config.get( 'foo' ); // -> 1\n *\t\t\t\tcontext.config.get( 'bar' ); // -> 2\n *\t\t\t} );\n *\n *\t\t// The default options can be overridden by the configuration passed to create().\n *\t\tContext\n *\t\t\t.create( { bar: 3 } )\n *\t\t\t.then( context => {\n *\t\t\t\tcontext.config.get( 'foo' ); // -> 1\n *\t\t\t\tcontext.config.get( 'bar' ); // -> 3\n *\t\t\t} );\n *\n * See also {@link module:core/editor/editor~Editor.defaultConfig} and {@link module:core/context~Context.builtinPlugins}.\n *\n * @static\n * @member {Object} module:core/context~Context.defaultConfig\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/comparearrays\n */\n\n/**\n * Compares how given arrays relate to each other. One array can be: same as another array, prefix of another array\n * or completely different. If arrays are different, first index at which they differ is returned. Otherwise,\n * a flag specifying the relation is returned. Flags are negative numbers, so whenever a number >= 0 is returned\n * it means that arrays differ.\n *\n *\t\tcompareArrays( [ 0, 2 ], [ 0, 2 ] );\t\t// 'same'\n *\t\tcompareArrays( [ 0, 2 ], [ 0, 2, 1 ] );\t\t// 'prefix'\n *\t\tcompareArrays( [ 0, 2 ], [ 0 ] );\t\t\t// 'extension'\n *\t\tcompareArrays( [ 0, 2 ], [ 1, 2 ] );\t\t// 0\n *\t\tcompareArrays( [ 0, 2 ], [ 0, 1 ] );\t\t// 1\n *\n * @param {Array} a Array that is compared.\n * @param {Array} b Array to compare with.\n * @returns {module:utils/comparearrays~ArrayRelation} How array `a` is related to `b`.\n */\nexport default function compareArrays( a, b ) {\n\tconst minLen = Math.min( a.length, b.length );\n\n\tfor ( let i = 0; i < minLen; i++ ) {\n\t\tif ( a[ i ] != b[ i ] ) {\n\t\t\t// The arrays are different.\n\t\t\treturn i;\n\t\t}\n\t}\n\n\t// Both arrays were same at all points.\n\tif ( a.length == b.length ) {\n\t\t// If their length is also same, they are the same.\n\t\treturn 'same';\n\t} else if ( a.length < b.length ) {\n\t\t// Compared array is shorter so it is a prefix of the other array.\n\t\treturn 'prefix';\n\t} else {\n\t\t// Compared array is longer so it is an extension of the other array.\n\t\treturn 'extension';\n\t}\n}\n\n/**\n * @typedef {'extension'|'same'|'prefix'} module:utils/comparearrays~ArrayRelation\n */\n","import baseClone from './_baseClone.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_SYMBOLS_FLAG = 4;\n\n/**\n * Creates a shallow clone of `value`.\n *\n * **Note:** This method is loosely based on the\n * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)\n * and supports cloning arrays, array buffers, booleans, date objects, maps,\n * numbers, `Object` objects, regexes, sets, strings, symbols, and typed\n * arrays. The own enumerable properties of `arguments` objects are cloned\n * as plain objects. An empty object is returned for uncloneable values such\n * as error objects, functions, DOM nodes, and WeakMaps.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to clone.\n * @returns {*} Returns the cloned value.\n * @see _.cloneDeep\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var shallow = _.clone(objects);\n * console.log(shallow[0] === objects[0]);\n * // => true\n */\nfunction clone(value) {\n return baseClone(value, CLONE_SYMBOLS_FLAG);\n}\n\nexport default clone;\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/node\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport { clone } from 'lodash-es';\n\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Abstract tree view node class.\n *\n * This is an abstract class. Its constructor should not be used directly.\n * Use the {@link module:engine/view/element~Element} class to create view elements\n * or {@link module:engine/view/text~Text} class to create view text nodes.\n *\n * @abstract\n */\nexport default class Node {\n\t/**\n\t * Creates a tree view node.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Parent element. Null by default. Set by {@link module:engine/view/element~Element#_insertChild}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|null}\n\t\t */\n\t\tthis.parent = null;\n\t}\n\n\t/**\n\t * Index of the node in the parent element or null if the node has no parent.\n\t *\n\t * Accessing this property throws an error if this node's parent element does not contain it.\n\t * This means that view tree got broken.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget index() {\n\t\tlet pos;\n\n\t\tif ( !this.parent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// No parent or child doesn't exist in parent's children.\n\t\tif ( ( pos = this.parent.getChildIndex( this ) ) == -1 ) {\n\t\t\t/**\n\t\t\t * The node's parent does not contain this node. It means that the document tree is corrupted.\n\t\t\t *\n\t\t\t * @error view-node-not-found-in-parent\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-node-not-found-in-parent: The node\\'s parent does not contain this node.', this );\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t/**\n\t * Node's next sibling, or `null` if it is the last child.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget nextSibling() {\n\t\tconst index = this.index;\n\n\t\treturn ( index !== null && this.parent.getChild( index + 1 ) ) || null;\n\t}\n\n\t/**\n\t * Node's previous sibling, or `null` if it is the first child.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget previousSibling() {\n\t\tconst index = this.index;\n\n\t\treturn ( index !== null && this.parent.getChild( index - 1 ) ) || null;\n\t}\n\n\t/**\n\t * Top-most ancestor of the node. If the node has no parent it is the root itself.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\tlet root = this; // eslint-disable-line consistent-this\n\n\t\twhile ( root.parent ) {\n\t\t\troot = root.parent;\n\t\t}\n\n\t\treturn root;\n\t}\n\n\t/**\n\t * {@link module:engine/view/document~Document View document} that owns this node, or `null` if the node is inside\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment}.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/document~Document|null}\n\t */\n\tget document() {\n\t\t// Parent might be Node, null or DocumentFragment.\n\t\tif ( this.parent instanceof Node ) {\n\t\t\treturn this.parent.document;\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Gets a path to the node. The path is an array containing indices of consecutive ancestors of this node,\n\t * beginning from {@link module:engine/view/node~Node#root root}, down to this node's index.\n\t *\n\t *\t\tconst abc = downcastWriter.createText( 'abc' );\n\t *\t\tconst foo = downcastWriter.createText( 'foo' );\n\t *\t\tconst h1 = downcastWriter.createElement( 'h1', null, downcastWriter.createText( 'header' ) );\n\t *\t\tconst p = downcastWriter.createElement( 'p', null, [ abc, foo ] );\n\t *\t\tconst div = downcastWriter.createElement( 'div', null, [ h1, p ] );\n\t *\t\tfoo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3.\n\t *\t\th1.getPath(); // Returns [ 0 ].\n\t *\t\tdiv.getPath(); // Returns [].\n\t *\n\t * @returns {Array.<Number>} The path.\n\t */\n\tgetPath() {\n\t\tconst path = [];\n\t\tlet node = this; // eslint-disable-line consistent-this\n\n\t\twhile ( node.parent ) {\n\t\t\tpath.unshift( node.index );\n\t\t\tnode = node.parent;\n\t\t}\n\n\t\treturn path;\n\t}\n\n\t/**\n\t * Returns ancestors array of this node.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` this node will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from node's parent to root element,\n\t * otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this : this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/view/element~Element} or {@link module:engine/view/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both nodes.\n\t *\n\t * @param {module:engine/view/node~Node} node The second node.\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` both nodes will be considered \"ancestors\" too.\n\t * Which means that if e.g. node A is inside B, then their common ancestor will be B.\n\t * @returns {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( node, options = {} ) {\n\t\tconst ancestorsA = this.getAncestors( options );\n\t\tconst ancestorsB = node.getAncestors( options );\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Returns whether this node is before given node. `false` is returned if nodes are in different trees (for example,\n\t * in different {@link module:engine/view/documentfragment~DocumentFragment}s).\n\t *\n\t * @param {module:engine/view/node~Node} node Node to compare with.\n\t * @returns {Boolean}\n\t */\n\tisBefore( node ) {\n\t\t// Given node is not before this node if they are same.\n\t\tif ( this == node ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Return `false` if it is impossible to compare nodes.\n\t\tif ( this.root !== node.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst thisPath = this.getPath();\n\t\tconst nodePath = node.getPath();\n\n\t\tconst result = compareArrays( thisPath, nodePath );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'prefix':\n\t\t\t\treturn true;\n\n\t\t\tcase 'extension':\n\t\t\t\treturn false;\n\n\t\t\tdefault:\n\t\t\t\treturn thisPath[ result ] < nodePath[ result ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns whether this node is after given node. `false` is returned if nodes are in different trees (for example,\n\t * in different {@link module:engine/view/documentfragment~DocumentFragment}s).\n\t *\n\t * @param {module:engine/view/node~Node} node Node to compare with.\n\t * @returns {Boolean}\n\t */\n\tisAfter( node ) {\n\t\t// Given node is not before this node if they are same.\n\t\tif ( this == node ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Return `false` if it is impossible to compare nodes.\n\t\tif ( this.root !== node.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// In other cases, just check if the `node` is before, and return the opposite.\n\t\treturn !this.isBefore( node );\n\t}\n\n\t/**\n\t * Removes node from parent.\n\t *\n\t * @protected\n\t */\n\t_remove() {\n\t\tthis.parent._removeChildren( this.index );\n\t}\n\n\t/**\n\t * @protected\n\t * @param {module:engine/view/document~ChangeType} type Type of the change.\n\t * @param {module:engine/view/node~Node} node Changed node.\n\t * @fires change\n\t */\n\t_fireChange( type, node ) {\n\t\tthis.fire( 'change:' + type, node );\n\n\t\tif ( this.parent ) {\n\t\t\tthis.parent._fireChange( type, node );\n\t\t}\n\t}\n\n\t/**\n\t * Custom toJSON method to solve child-parent circular dependencies.\n\t *\n\t * @returns {Object} Clone of this object with the parent property removed.\n\t */\n\ttoJSON() {\n\t\tconst json = clone( this );\n\n\t\t// Due to circular references we need to remove parent reference.\n\t\tdelete json.parent;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t * This method is useful when processing view objects that are of unknown type. For example, a function\n\t * may return a {@link module:engine/view/documentfragment~DocumentFragment} or a {@link module:engine/view/node~Node}\n\t * that can be either a text node or an element. This method can be used to check what kind of object is returned.\n\t *\n\t *\t\tsomeObject.is( 'element' ); // -> true if this is an element\n\t *\t\tsomeObject.is( 'node' ); // -> true if this is a node (a text node or an element)\n\t *\t\tsomeObject.is( 'documentFragment' ); // -> true if this is a document fragment\n\t *\n\t * Since this method is also available on a range of model objects, you can prefix the type of the object with\n\t * `model:` or `view:` to check, for example, if this is the model's or view's element:\n\t *\n\t *\t\tviewElement.is( 'view:element' ); // -> true\n\t *\t\tviewElement.is( 'model:element' ); // -> false\n\t *\n\t * By using this method it is also possible to check a name of an element:\n\t *\n\t *\t\timgElement.is( 'img' ); // -> true\n\t *\t\timgElement.is( 'element', 'img' ); // -> same as above\n\t *\t\timgElement.is( 'view:element', 'img' ); // -> same as above, but more precise\n\t *\n\t * The list of view objects which implement the `is()` method:\n\t *\n\t * * {@link module:engine/view/attributeelement~AttributeElement#is `AttributeElement#is()`}\n\t * * {@link module:engine/view/containerelement~ContainerElement#is `ContainerElement#is()`}\n\t * * {@link module:engine/view/documentfragment~DocumentFragment#is `DocumentFragment#is()`}\n\t * * {@link module:engine/view/documentselection~DocumentSelection#is `DocumentSelection#is()`}\n\t * * {@link module:engine/view/editableelement~EditableElement#is `EditableElement#is()`}\n\t * * {@link module:engine/view/element~Element#is `Element#is()`}\n\t * * {@link module:engine/view/emptyelement~EmptyElement#is `EmptyElement#is()`}\n\t * * {@link module:engine/view/node~Node#is `Node#is()`}\n\t * * {@link module:engine/view/position~Position#is `Position#is()`}\n\t * * {@link module:engine/view/range~Range#is `Range#is()`}\n\t * * {@link module:engine/view/rooteditableelement~RootEditableElement#is `RootEditableElement#is()`}\n\t * * {@link module:engine/view/selection~Selection#is `Selection#is()`}\n\t * * {@link module:engine/view/text~Text#is `Text#is()`}\n\t * * {@link module:engine/view/textproxy~TextProxy#is `TextProxy#is()`}\n\t * * {@link module:engine/view/uielement~UIElement#is `UIElement#is()`}\n\t *\n\t * @method #is\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'node' || type == 'view:node';\n\t}\n\n\t/**\n\t * Clones this node.\n\t *\n\t * @protected\n\t * @method #_clone\n\t * @returns {module:engine/view/node~Node} Clone of this node.\n\t */\n\n\t/**\n\t * Checks if provided node is similar to this node.\n\t *\n\t * @method #isSimilar\n\t * @returns {Boolean} True if nodes are similar.\n\t */\n}\n\n/**\n * Fired when list of {@link module:engine/view/element~Element elements} children changes.\n *\n * Change event is bubbled – it is fired on all ancestors.\n *\n * @event change:children\n * @param {module:engine/view/node~Node} changedNode\n */\n\n/**\n * Fired when list of {@link module:engine/view/element~Element elements} attributes changes.\n *\n * Change event is bubbled – it is fired on all ancestors.\n *\n * @event change:attributes\n * @param {module:engine/view/node~Node} changedNode\n */\n\n/**\n * Fired when {@link module:engine/view/text~Text text nodes} data changes.\n *\n * Change event is bubbled – it is fired on all ancestors.\n *\n * @event change:text\n * @param {module:engine/view/node~Node} changedNode\n */\n\n/**\n * @event change\n */\n\nmix( Node, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/text\n */\n\nimport Node from './node';\n\n/**\n * Tree view text node.\n *\n * The constructor of this class shouldn't be used directly. To create new Text instances\n * use the {@link module:engine/view/downcastwriter~DowncastWriter#createText `DowncastWriter#createText()`}\n * method when working on data downcasted from the model or the\n * {@link module:engine/view/upcastwriter~UpcastWriter#createText `UpcastWriter#createText()`}\n * method when working on non-semantic views.\n *\n * @extends module:engine/view/node~Node\n */\nexport default class Text extends Node {\n\t/**\n\t * Creates a tree view text node.\n\t *\n\t * @protected\n\t * @param {String} data The text's data.\n\t */\n\tconstructor( data ) {\n\t\tsuper();\n\n\t\t/**\n\t\t * The text content.\n\t\t *\n\t\t * Setting the data fires the {@link module:engine/view/node~Node#event:change:text change event}.\n\t\t *\n\t\t * @protected\n\t\t * @member {String} module:engine/view/text~Text#_textData\n\t\t */\n\t\tthis._textData = data;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\ttext.is( 'text' ); // -> true\n\t *\t\ttext.is( 'node' ); // -> true\n\t *\t\ttext.is( 'view:text' ); // -> true\n\t *\t\ttext.is( 'view:node' ); // -> true\n\t *\n\t *\t\ttext.is( 'model:text' ); // -> false\n\t *\t\ttext.is( 'element' ); // -> false\n\t *\t\ttext.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'text' || type == 'view:text' || super.is( type );\n\t}\n\n\t/**\n\t * The text content.\n\t *\n\t * @readonly\n\t * @type {String}\n\t */\n\tget data() {\n\t\treturn this._textData;\n\t}\n\n\t/**\n\t * This getter is required when using the addition assignment operator on protected property:\n\t *\n\t *\t\tconst foo = downcastWriter.createText( 'foo' );\n\t *\t\tconst bar = downcastWriter.createText( 'bar' );\n\t *\n\t *\t\tfoo._data += bar.data; // executes: `foo._data = foo._data + bar.data`\n\t *\t\tconsole.log( foo.data ); // prints: 'foobar'\n\t *\n\t * If the protected getter didn't exist, `foo._data` will return `undefined` and result of the merge will be invalid.\n\t *\n\t * @protected\n\t * @type {String}\n\t */\n\tget _data() {\n\t\treturn this.data;\n\t}\n\n\t/**\n\t * Sets data and fires the {@link module:engine/view/node~Node#event:change:text change event}.\n\t *\n\t * @protected\n\t * @fires change:text\n\t * @param {String} data New data for the text node.\n\t */\n\tset _data( data ) {\n\t\tthis._fireChange( 'text', this );\n\n\t\tthis._textData = data;\n\t}\n\n\t/**\n\t * Checks if this text node is similar to other text node.\n\t * Both nodes should have the same data to be considered as similar.\n\t *\n\t * @param {module:engine/view/text~Text} otherNode Node to check if it is same as this node.\n\t * @returns {Boolean}\n\t */\n\tisSimilar( otherNode ) {\n\t\tif ( !( otherNode instanceof Text ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this === otherNode || this.data === otherNode.data;\n\t}\n\n\t/**\n\t * Clones this node.\n\t *\n\t * @protected\n\t * @returns {module:engine/view/text~Text} Text node that is a clone of this node.\n\t */\n\t_clone() {\n\t\treturn new Text( this.data );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ViewText: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ViewText: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/textproxy\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * TextProxy is a wrapper for substring of {@link module:engine/view/text~Text}. Instance of this class is created by\n * {@link module:engine/view/treewalker~TreeWalker} when only a part of {@link module:engine/view/text~Text} needs to be returned.\n *\n * `TextProxy` has an API similar to {@link module:engine/view/text~Text Text} and allows to do most of the common tasks performed\n * on view nodes.\n *\n * **Note:** Some `TextProxy` instances may represent whole text node, not just a part of it.\n * See {@link module:engine/view/textproxy~TextProxy#isPartial}.\n *\n * **Note:** `TextProxy` is a readonly interface.\n *\n * **Note:** `TextProxy` instances are created on the fly basing on the current state of parent {@link module:engine/view/text~Text}.\n * Because of this it is highly unrecommended to store references to `TextProxy instances because they might get\n * invalidated due to operations on Document. Also TextProxy is not a {@link module:engine/view/node~Node} so it can not be\n * inserted as a child of {@link module:engine/view/element~Element}.\n *\n * `TextProxy` instances are created by {@link module:engine/view/treewalker~TreeWalker view tree walker}. You should not need to create\n * an instance of this class by your own.\n */\nexport default class TextProxy {\n\t/**\n\t * Creates a text proxy.\n\t *\n\t * @protected\n\t * @param {module:engine/view/text~Text} textNode Text node which part is represented by this text proxy.\n\t * @param {Number} offsetInText Offset in {@link module:engine/view/textproxy~TextProxy#textNode text node}\n\t * from which the text proxy starts.\n\t * @param {Number} length Text proxy length, that is how many text node's characters, starting from `offsetInText` it represents.\n\t * @constructor\n\t */\n\tconstructor( textNode, offsetInText, length ) {\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/text~Text} element which TextProxy is a substring.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/text~Text} module:engine/view/textproxy~TextProxy#textNode\n\t\t */\n\t\tthis.textNode = textNode;\n\n\t\tif ( offsetInText < 0 || offsetInText > textNode.data.length ) {\n\t\t\t/**\n\t\t\t * Given offsetInText value is incorrect.\n\t\t\t *\n\t\t\t * @error view-textproxy-wrong-offsetintext\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-textproxy-wrong-offsetintext: Given offsetInText value is incorrect.', this );\n\t\t}\n\n\t\tif ( length < 0 || offsetInText + length > textNode.data.length ) {\n\t\t\t/**\n\t\t\t * Given length value is incorrect.\n\t\t\t *\n\t\t\t * @error view-textproxy-wrong-length\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-textproxy-wrong-length: Given length value is incorrect.', this );\n\t\t}\n\n\t\t/**\n\t\t * Text data represented by this text proxy.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} module:engine/view/textproxy~TextProxy#data\n\t\t */\n\t\tthis.data = textNode.data.substring( offsetInText, offsetInText + length );\n\n\t\t/**\n\t\t * Offset in the `textNode` where this `TextProxy` instance starts.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} module:engine/view/textproxy~TextProxy#offsetInText\n\t\t */\n\t\tthis.offsetInText = offsetInText;\n\t}\n\n\t/**\n\t * Offset size of this node.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget offsetSize() {\n\t\treturn this.data.length;\n\t}\n\n\t/**\n\t * Flag indicating whether `TextProxy` instance covers only part of the original {@link module:engine/view/text~Text text node}\n\t * (`true`) or the whole text node (`false`).\n\t *\n\t * This is `false` when text proxy starts at the very beginning of {@link module:engine/view/textproxy~TextProxy#textNode textNode}\n\t * ({@link module:engine/view/textproxy~TextProxy#offsetInText offsetInText} equals `0`) and text proxy sizes is equal to\n\t * text node size.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isPartial() {\n\t\treturn this.data.length !== this.textNode.data.length;\n\t}\n\n\t/**\n\t * Parent of this text proxy, which is same as parent of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tget parent() {\n\t\treturn this.textNode.parent;\n\t}\n\n\t/**\n\t * Root of this text proxy, which is same as root of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.textNode.root;\n\t}\n\n\t/**\n\t * {@link module:engine/view/document~Document View document} that owns this text proxy, or `null` if the text proxy is inside\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment}.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/document~Document|null}\n\t */\n\tget document() {\n\t\treturn this.textNode.document;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\ttextProxy.is( 'textProxy' ); // -> true\n\t *\t\ttextProxy.is( 'view:textProxy' ); // -> true\n\t *\n\t *\t\ttextProxy.is( 'model:textProxy' ); // -> false\n\t *\t\ttextProxy.is( 'element' ); // -> false\n\t *\t\ttextProxy.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'textProxy' || type == 'view:textProxy';\n\t}\n\n\t/**\n\t * Returns ancestors array of this text proxy.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` {#textNode} will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from text proxy parent to\n\t * root element, otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this.textNode : this.parent;\n\n\t\twhile ( parent !== null ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ViewTextProxy: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ViewTextProxy: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/isiterable\n */\n\n/**\n * Checks if value implements iterator interface.\n *\n * @param {*} value The value to check.\n * @returns {Boolean} True if value implements iterator interface.\n */\nexport default function isIterable( value ) {\n\treturn !!( value && value[ Symbol.iterator ] );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/tomap\n */\n\nimport objectToMap from './objecttomap';\nimport isIterable from './isiterable';\n\n/**\n * Transforms object or iterable to map. Iterable needs to be in the format acceptable by the `Map` constructor.\n *\n *\t\tmap = toMap( { 'foo': 1, 'bar': 2 } );\n *\t\tmap = toMap( [ [ 'foo', 1 ], [ 'bar', 2 ] ] );\n *\t\tmap = toMap( anotherMap );\n *\n * @param {Object|Iterable} data Object or iterable to transform.\n * @returns {Map} Map created from data.\n */\nexport default function toMap( data ) {\n\tif ( isIterable( data ) ) {\n\t\treturn new Map( data );\n\t} else {\n\t\treturn objectToMap( data );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/objecttomap\n */\n\n/**\n * Transforms object to map.\n *\n *\t\tconst map = objectToMap( { 'foo': 1, 'bar': 2 } );\n *\t\tmap.get( 'foo' ); // 1\n *\n * **Note**: For mixed data (`Object` or `Iterable`) there's a dedicated {@link module:utils/tomap~toMap} function.\n *\n * @param {Object} obj Object to transform.\n * @returns {Map} Map created from object.\n */\nexport default function objectToMap( obj ) {\n\tconst map = new Map();\n\n\tfor ( const key in obj ) {\n\t\tmap.set( key, obj[ key ] );\n\t}\n\n\treturn map;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/matcher\n */\n\n/**\n * View matcher class.\n * Instance of this class can be used to find {@link module:engine/view/element~Element elements} that match given pattern.\n */\nexport default class Matcher {\n\t/**\n\t * Creates new instance of Matcher.\n\t *\n\t * @param {String|RegExp|Object} [pattern] Match patterns. See {@link module:engine/view/matcher~Matcher#add add method} for\n\t * more information.\n\t */\n\tconstructor( ...pattern ) {\n\t\t/**\n\t\t * @private\n\t\t * @type {Array<String|RegExp|Object>}\n\t\t */\n\t\tthis._patterns = [];\n\n\t\tthis.add( ...pattern );\n\t}\n\n\t/**\n\t * Adds pattern or patterns to matcher instance.\n\t *\n\t *\t\t// String.\n\t *\t\tmatcher.add( 'div' );\n\t *\n\t *\t\t// Regular expression.\n\t *\t\tmatcher.add( /^\\w/ );\n\t *\n\t *\t\t// Single class.\n\t *\t\tmatcher.add( {\n\t *\t\t\tclasses: 'foobar'\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/view/matcher~MatcherPattern} for more examples.\n\t *\n\t * Multiple patterns can be added in one call:\n\t *\n\t * \t\tmatcher.add( 'div', { classes: 'foobar' } );\n\t *\n\t * @param {Object|String|RegExp|Function} pattern Object describing pattern details. If string or regular expression\n\t * is provided it will be used to match element's name. Pattern can be also provided in a form\n\t * of a function - then this function will be called with each {@link module:engine/view/element~Element element} as a parameter.\n\t * Function's return value will be stored under `match` key of the object returned from\n\t * {@link module:engine/view/matcher~Matcher#match match} or {@link module:engine/view/matcher~Matcher#matchAll matchAll} methods.\n\t * @param {String|RegExp} [pattern.name] Name or regular expression to match element's name.\n\t * @param {Object} [pattern.attributes] Object with key-value pairs representing attributes to match. Each object key\n\t * represents attribute name. Value under that key can be either:\n\t * * `true` - then attribute is just required (can be empty),\n\t * * a string - then attribute has to be equal, or\n\t * * a regular expression - then attribute has to match the expression.\n\t * @param {String|RegExp|Array} [pattern.classes] Class name or array of class names to match. Each name can be\n\t * provided in a form of string or regular expression.\n\t * @param {Object} [pattern.styles] Object with key-value pairs representing styles to match. Each object key\n\t * represents style name. Value under that key can be either a string or a regular expression and it will be used\n\t * to match style value.\n\t */\n\tadd( ...pattern ) {\n\t\tfor ( let item of pattern ) {\n\t\t\t// String or RegExp pattern is used as element's name.\n\t\t\tif ( typeof item == 'string' || item instanceof RegExp ) {\n\t\t\t\titem = { name: item };\n\t\t\t}\n\n\t\t\t// Single class name/RegExp can be provided.\n\t\t\tif ( item.classes && ( typeof item.classes == 'string' || item.classes instanceof RegExp ) ) {\n\t\t\t\titem.classes = [ item.classes ];\n\t\t\t}\n\n\t\t\tthis._patterns.push( item );\n\t\t}\n\t}\n\n\t/**\n\t * Matches elements for currently stored patterns. Returns match information about first found\n\t * {@link module:engine/view/element~Element element}, otherwise returns `null`.\n\t *\n\t * Example of returned object:\n\t *\n\t *\t\t{\n\t *\t\t\telement: <instance of found element>,\n\t *\t\t\tpattern: <pattern used to match found element>,\n\t *\t\t\tmatch: {\n\t *\t\t\t\tname: true,\n\t *\t\t\t\tattributes: [ 'title', 'href' ],\n\t *\t\t\t\tclasses: [ 'foo' ],\n\t *\t\t\t\tstyles: [ 'color', 'position' ]\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * @see module:engine/view/matcher~Matcher#add\n\t * @see module:engine/view/matcher~Matcher#matchAll\n\t * @param {...module:engine/view/element~Element} element View element to match against stored patterns.\n\t * @returns {Object|null} result\n\t * @returns {module:engine/view/element~Element} result.element Matched view element.\n\t * @returns {Object|String|RegExp|Function} result.pattern Pattern that was used to find matched element.\n\t * @returns {Object} result.match Object representing matched element parts.\n\t * @returns {Boolean} [result.match.name] True if name of the element was matched.\n\t * @returns {Array} [result.match.attributes] Array with matched attribute names.\n\t * @returns {Array} [result.match.classes] Array with matched class names.\n\t * @returns {Array} [result.match.styles] Array with matched style names.\n\t */\n\tmatch( ...element ) {\n\t\tfor ( const singleElement of element ) {\n\t\t\tfor ( const pattern of this._patterns ) {\n\t\t\t\tconst match = isElementMatching( singleElement, pattern );\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\telement: singleElement,\n\t\t\t\t\t\tpattern,\n\t\t\t\t\t\tmatch\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Matches elements for currently stored patterns. Returns array of match information with all found\n\t * {@link module:engine/view/element~Element elements}. If no element is found - returns `null`.\n\t *\n\t * @see module:engine/view/matcher~Matcher#add\n\t * @see module:engine/view/matcher~Matcher#match\n\t * @param {...module:engine/view/element~Element} element View element to match against stored patterns.\n\t * @returns {Array.<Object>|null} Array with match information about found elements or `null`. For more information\n\t * see {@link module:engine/view/matcher~Matcher#match match method} description.\n\t */\n\tmatchAll( ...element ) {\n\t\tconst results = [];\n\n\t\tfor ( const singleElement of element ) {\n\t\t\tfor ( const pattern of this._patterns ) {\n\t\t\t\tconst match = isElementMatching( singleElement, pattern );\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\tresults.push( {\n\t\t\t\t\t\telement: singleElement,\n\t\t\t\t\t\tpattern,\n\t\t\t\t\t\tmatch\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn results.length > 0 ? results : null;\n\t}\n\n\t/**\n\t * Returns the name of the element to match if there is exactly one pattern added to the matcher instance\n\t * and it matches element name defined by `string` (not `RegExp`). Otherwise, returns `null`.\n\t *\n\t * @returns {String|null} Element name trying to match.\n\t */\n\tgetElementName() {\n\t\tif ( this._patterns.length !== 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst pattern = this._patterns[ 0 ];\n\t\tconst name = pattern.name;\n\n\t\treturn ( typeof pattern != 'function' && name && !( name instanceof RegExp ) ) ? name : null;\n\t}\n}\n\n// Returns match information if {@link module:engine/view/element~Element element} is matching provided pattern.\n// If element cannot be matched to provided pattern - returns `null`.\n//\n// @param {module:engine/view/element~Element} element\n// @param {Object|String|RegExp|Function} pattern\n// @returns {Object|null} Returns object with match information or null if element is not matching.\nfunction isElementMatching( element, pattern ) {\n\t// If pattern is provided as function - return result of that function;\n\tif ( typeof pattern == 'function' ) {\n\t\treturn pattern( element );\n\t}\n\n\tconst match = {};\n\t// Check element's name.\n\tif ( pattern.name ) {\n\t\tmatch.name = matchName( pattern.name, element.name );\n\n\t\tif ( !match.name ) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// Check element's attributes.\n\tif ( pattern.attributes ) {\n\t\tmatch.attributes = matchAttributes( pattern.attributes, element );\n\n\t\tif ( !match.attributes ) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// Check element's classes.\n\tif ( pattern.classes ) {\n\t\tmatch.classes = matchClasses( pattern.classes, element );\n\n\t\tif ( !match.classes ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// Check element's styles.\n\tif ( pattern.styles ) {\n\t\tmatch.styles = matchStyles( pattern.styles, element );\n\n\t\tif ( !match.styles ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn match;\n}\n\n// Checks if name can be matched by provided pattern.\n//\n// @param {String|RegExp} pattern\n// @param {String} name\n// @returns {Boolean} Returns `true` if name can be matched, `false` otherwise.\nfunction matchName( pattern, name ) {\n\t// If pattern is provided as RegExp - test against this regexp.\n\tif ( pattern instanceof RegExp ) {\n\t\treturn pattern.test( name );\n\t}\n\n\treturn pattern === name;\n}\n\n// Checks if attributes of provided element can be matched against provided patterns.\n//\n// @param {Object} patterns Object with information about attributes to match. Each key of the object will be\n// used as attribute name. Value of each key can be a string or regular expression to match against attribute value.\n// @param {module:engine/view/element~Element} element Element which attributes will be tested.\n// @returns {Array|null} Returns array with matched attribute names or `null` if no attributes were matched.\nfunction matchAttributes( patterns, element ) {\n\tconst match = [];\n\n\tfor ( const name in patterns ) {\n\t\tconst pattern = patterns[ name ];\n\n\t\tif ( element.hasAttribute( name ) ) {\n\t\t\tconst attribute = element.getAttribute( name );\n\n\t\t\tif ( pattern === true ) {\n\t\t\t\tmatch.push( name );\n\t\t\t} else if ( pattern instanceof RegExp ) {\n\t\t\t\tif ( pattern.test( attribute ) ) {\n\t\t\t\t\tmatch.push( name );\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t} else if ( attribute === pattern ) {\n\t\t\t\tmatch.push( name );\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn match;\n}\n\n// Checks if classes of provided element can be matched against provided patterns.\n//\n// @param {Array.<String|RegExp>} patterns Array of strings or regular expressions to match against element's classes.\n// @param {module:engine/view/element~Element} element Element which classes will be tested.\n// @returns {Array|null} Returns array with matched class names or `null` if no classes were matched.\nfunction matchClasses( patterns, element ) {\n\tconst match = [];\n\n\tfor ( const pattern of patterns ) {\n\t\tif ( pattern instanceof RegExp ) {\n\t\t\tconst classes = element.getClassNames();\n\n\t\t\tfor ( const name of classes ) {\n\t\t\t\tif ( pattern.test( name ) ) {\n\t\t\t\t\tmatch.push( name );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( match.length === 0 ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else if ( element.hasClass( pattern ) ) {\n\t\t\tmatch.push( pattern );\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn match;\n}\n\n// Checks if styles of provided element can be matched against provided patterns.\n//\n// @param {Object} patterns Object with information about styles to match. Each key of the object will be\n// used as style name. Value of each key can be a string or regular expression to match against style value.\n// @param {module:engine/view/element~Element} element Element which styles will be tested.\n// @returns {Array|null} Returns array with matched style names or `null` if no styles were matched.\nfunction matchStyles( patterns, element ) {\n\tconst match = [];\n\n\tfor ( const name in patterns ) {\n\t\tconst pattern = patterns[ name ];\n\n\t\tif ( element.hasStyle( name ) ) {\n\t\t\tconst style = element.getStyle( name );\n\n\t\t\tif ( pattern instanceof RegExp ) {\n\t\t\t\tif ( pattern.test( style ) ) {\n\t\t\t\t\tmatch.push( name );\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t} else if ( style === pattern ) {\n\t\t\t\tmatch.push( name );\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn match;\n}\n\n/**\n * An entity that is a valid pattern recognized by a matcher. `MatcherPattern` is used by {@link ~Matcher} to recognize\n * if a view element fits in a group of view elements described by the pattern.\n *\n * `MatcherPattern` can be given as a `String`, a `RegExp`, an `Object` or a `Function`.\n *\n * If `MatcherPattern` is given as a `String` or `RegExp`, it will match any view element that has a matching name:\n *\n *\t\t// Match any element with name equal to 'div'.\n *\t\tconst pattern = 'div';\n *\n *\t\t// Match any element which name starts on 'p'.\n *\t\tconst pattern = /^p/;\n *\n * If `MatcherPattern` is given as an `Object`, all the object's properties will be matched with view element properties.\n *\n *\t\t// Match view element's name.\n *\t\tconst pattern = { name: /^p/ };\n *\n *\t\t// Match view element which has matching attributes.\n *\t\tconst pattern = {\n *\t\t\tattributes: {\n *\t\t\t\ttitle: 'foobar',\t// Attribute title should equal 'foobar'.\n *\t\t\t\tfoo: /^\\w+/,\t\t// Attribute foo should match /^\\w+/ regexp.\n *\t\t\t\tbar: true\t\t\t// Attribute bar should be set (can be empty).\n *\t\t\t}\n *\t\t};\n *\n *\t\t// Match view element which has given class.\n *\t\tconst pattern = {\n *\t\t\tclasses: 'foobar'\n *\t\t};\n *\n *\t\t// Match view element class using regular expression.\n *\t\tconst pattern = {\n *\t\t\tclasses: /foo.../\n *\t\t};\n *\n *\t\t// Multiple classes to match.\n *\t\tconst pattern = {\n *\t\t\tclasses: [ 'baz', 'bar', /foo.../ ]\n *\t\t};\n *\n *\t\t// Match view element which has given styles.\n *\t\tconst pattern = {\n *\t\t\tstyles: {\n *\t\t\t\tposition: 'absolute',\n *\t\t\t\tcolor: /^\\w*blue$/\n *\t\t\t}\n *\t\t};\n *\n *\t\t// Pattern with multiple properties.\n *\t\tconst pattern = {\n *\t\t\tname: 'span',\n *\t\t\tstyles: {\n *\t\t\t\t'font-weight': 'bold'\n *\t\t\t},\n *\t\t\tclasses: 'highlighted'\n *\t\t};\n *\n * If `MatcherPattern` is given as a `Function`, the function takes a view element as a first and only parameter and\n * the function should decide whether that element matches. If so, it should return what part of the view element has been matched.\n * Otherwise, the function should return `null`. The returned result will be included in `match` property of the object\n * returned by {@link ~Matcher#match} call.\n *\n *\t\t// Match an empty <div> element.\n *\t\tconst pattern = element => {\n *\t\t\tif ( element.name == 'div' && element.childCount > 0 ) {\n *\t\t\t\t// Return which part of the element was matched.\n *\t\t\t\treturn { name: true };\n *\t\t\t}\n *\n *\t\t\treturn null;\n *\t\t};\n *\n *\t\t// Match a <p> element with big font (\"heading-like\" element).\n *\t\tconst pattern = element => {\n *\t\t\tif ( element.name == 'p' ) {\n *\t\t\t\tconst fontSize = element.getStyle( 'font-size' );\n *\t\t\t\tconst size = fontSize.match( /(\\d+)/px );\n *\n *\t\t\t\tif ( size && Number( size[ 1 ] ) > 26 ) {\n *\t\t\t\t\treturn { name: true, attribute: [ 'font-size' ] };\n *\t\t\t\t}\n *\t\t\t}\n *\n *\t\t\treturn null;\n *\t\t};\n *\n * `MatcherPattern` is defined in a way that it is a superset of {@link module:engine/view/elementdefinition~ElementDefinition},\n * that is, every `ElementDefinition` also can be used as a `MatcherPattern`.\n *\n * @typedef {String|RegExp|Object|Function} module:engine/view/matcher~MatcherPattern\n *\n * @property {String|RegExp} [name] View element name to match.\n * @property {String|RegExp|Array.<String|RegExp>} [classes] View element's class name(s) to match.\n * @property {Object} [styles] Object with key-value pairs representing styles to match.\n * Each object key represents style name. Value can be given as `String` or `RegExp`.\n * @property {Object} [attributes] Object with key-value pairs representing attributes to match.\n * Each object key represents attribute name. Value can be given as `String` or `RegExp`.\n */\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\nexport default isSymbol;\n","import isArray from './isArray.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used to match property names within property paths. */\nvar reIsDeepProp = /\\.|\\[(?:[^[\\]]*|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*?\\1)\\]/,\n reIsPlainProp = /^\\w*$/;\n\n/**\n * Checks if `value` is a property name and not a property path.\n *\n * @private\n * @param {*} value The value to check.\n * @param {Object} [object] The object to query keys on.\n * @returns {boolean} Returns `true` if `value` is a property name, else `false`.\n */\nfunction isKey(value, object) {\n if (isArray(value)) {\n return false;\n }\n var type = typeof value;\n if (type == 'number' || type == 'symbol' || type == 'boolean' ||\n value == null || isSymbol(value)) {\n return true;\n }\n return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||\n (object != null && value in Object(object));\n}\n\nexport default isKey;\n","import MapCache from './_MapCache.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that memoizes the result of `func`. If `resolver` is\n * provided, it determines the cache key for storing the result based on the\n * arguments provided to the memoized function. By default, the first argument\n * provided to the memoized function is used as the map cache key. The `func`\n * is invoked with the `this` binding of the memoized function.\n *\n * **Note:** The cache is exposed as the `cache` property on the memoized\n * function. Its creation may be customized by replacing the `_.memoize.Cache`\n * constructor with one whose instances implement the\n * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)\n * method interface of `clear`, `delete`, `get`, `has`, and `set`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to have its output memoized.\n * @param {Function} [resolver] The function to resolve the cache key.\n * @returns {Function} Returns the new memoized function.\n * @example\n *\n * var object = { 'a': 1, 'b': 2 };\n * var other = { 'c': 3, 'd': 4 };\n *\n * var values = _.memoize(_.values);\n * values(object);\n * // => [1, 2]\n *\n * values(other);\n * // => [3, 4]\n *\n * object.a = 2;\n * values(object);\n * // => [1, 2]\n *\n * // Modify the result cache.\n * values.cache.set(object, ['a', 'b']);\n * values(object);\n * // => ['a', 'b']\n *\n * // Replace `_.memoize.Cache`.\n * _.memoize.Cache = WeakMap;\n */\nfunction memoize(func, resolver) {\n if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n var memoized = function() {\n var args = arguments,\n key = resolver ? resolver.apply(this, args) : args[0],\n cache = memoized.cache;\n\n if (cache.has(key)) {\n return cache.get(key);\n }\n var result = func.apply(this, args);\n memoized.cache = cache.set(key, result) || cache;\n return result;\n };\n memoized.cache = new (memoize.Cache || MapCache);\n return memoized;\n}\n\n// Expose `MapCache`.\nmemoize.Cache = MapCache;\n\nexport default memoize;\n","import memoize from './memoize.js';\n\n/** Used as the maximum memoize cache size. */\nvar MAX_MEMOIZE_SIZE = 500;\n\n/**\n * A specialized version of `_.memoize` which clears the memoized function's\n * cache when it exceeds `MAX_MEMOIZE_SIZE`.\n *\n * @private\n * @param {Function} func The function to have its output memoized.\n * @returns {Function} Returns the new memoized function.\n */\nfunction memoizeCapped(func) {\n var result = memoize(func, function(key) {\n if (cache.size === MAX_MEMOIZE_SIZE) {\n cache.clear();\n }\n return key;\n });\n\n var cache = result.cache;\n return result;\n}\n\nexport default memoizeCapped;\n","import memoizeCapped from './_memoizeCapped.js';\n\n/** Used to match property names within property paths. */\nvar rePropName = /[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g;\n\n/** Used to match backslashes in property paths. */\nvar reEscapeChar = /\\\\(\\\\)?/g;\n\n/**\n * Converts `string` to a property path array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the property path array.\n */\nvar stringToPath = memoizeCapped(function(string) {\n var result = [];\n if (string.charCodeAt(0) === 46 /* . */) {\n result.push('');\n }\n string.replace(rePropName, function(match, number, quote, subString) {\n result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));\n });\n return result;\n});\n\nexport default stringToPath;\n","/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nexport default arrayMap;\n","import Symbol from './_Symbol.js';\nimport arrayMap from './_arrayMap.js';\nimport isArray from './isArray.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolToString = symbolProto ? symbolProto.toString : undefined;\n\n/**\n * The base implementation of `_.toString` which doesn't convert nullish\n * values to empty strings.\n *\n * @private\n * @param {*} value The value to process.\n * @returns {string} Returns the string.\n */\nfunction baseToString(value) {\n // Exit early for strings to avoid a performance hit in some environments.\n if (typeof value == 'string') {\n return value;\n }\n if (isArray(value)) {\n // Recursively convert values (susceptible to call stack limits).\n return arrayMap(value, baseToString) + '';\n }\n if (isSymbol(value)) {\n return symbolToString ? symbolToString.call(value) : '';\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\nexport default baseToString;\n","import baseToString from './_baseToString.js';\n\n/**\n * Converts `value` to a string. An empty string is returned for `null`\n * and `undefined` values. The sign of `-0` is preserved.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.toString(null);\n * // => ''\n *\n * _.toString(-0);\n * // => '-0'\n *\n * _.toString([1, 2, 3]);\n * // => '1,2,3'\n */\nfunction toString(value) {\n return value == null ? '' : baseToString(value);\n}\n\nexport default toString;\n","import isArray from './isArray.js';\nimport isKey from './_isKey.js';\nimport stringToPath from './_stringToPath.js';\nimport toString from './toString.js';\n\n/**\n * Casts `value` to a path array if it's not one.\n *\n * @private\n * @param {*} value The value to inspect.\n * @param {Object} [object] The object to query keys on.\n * @returns {Array} Returns the cast property path array.\n */\nfunction castPath(value, object) {\n if (isArray(value)) {\n return value;\n }\n return isKey(value, object) ? [value] : stringToPath(toString(value));\n}\n\nexport default castPath;\n","/**\n * Gets the last element of `array`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Array\n * @param {Array} array The array to query.\n * @returns {*} Returns the last element of `array`.\n * @example\n *\n * _.last([1, 2, 3]);\n * // => 3\n */\nfunction last(array) {\n var length = array == null ? 0 : array.length;\n return length ? array[length - 1] : undefined;\n}\n\nexport default last;\n","import isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/**\n * Converts `value` to a string key if it's not a string or symbol.\n *\n * @private\n * @param {*} value The value to inspect.\n * @returns {string|symbol} Returns the key.\n */\nfunction toKey(value) {\n if (typeof value == 'string' || isSymbol(value)) {\n return value;\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\nexport default toKey;\n","import castPath from './_castPath.js';\nimport toKey from './_toKey.js';\n\n/**\n * The base implementation of `_.get` without support for default values.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the property to get.\n * @returns {*} Returns the resolved value.\n */\nfunction baseGet(object, path) {\n path = castPath(path, object);\n\n var index = 0,\n length = path.length;\n\n while (object != null && index < length) {\n object = object[toKey(path[index++])];\n }\n return (index && index == length) ? object : undefined;\n}\n\nexport default baseGet;\n","/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\nexport default baseSlice;\n","import baseGet from './_baseGet.js';\nimport baseSlice from './_baseSlice.js';\n\n/**\n * Gets the parent value at `path` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Array} path The path to get the parent value of.\n * @returns {*} Returns the parent value.\n */\nfunction parent(object, path) {\n return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));\n}\n\nexport default parent;\n","import castPath from './_castPath.js';\nimport last from './last.js';\nimport parent from './_parent.js';\nimport toKey from './_toKey.js';\n\n/**\n * The base implementation of `_.unset`.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {Array|string} path The property path to unset.\n * @returns {boolean} Returns `true` if the property is deleted, else `false`.\n */\nfunction baseUnset(object, path) {\n path = castPath(path, object);\n object = parent(object, path);\n return object == null || delete object[toKey(last(path))];\n}\n\nexport default baseUnset;\n","import baseUnset from './_baseUnset.js';\n\n/**\n * Removes the property at `path` of `object`.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to unset.\n * @returns {boolean} Returns `true` if the property is deleted, else `false`.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 7 } }] };\n * _.unset(object, 'a[0].b.c');\n * // => true\n *\n * console.log(object);\n * // => { 'a': [{ 'b': {} }] };\n *\n * _.unset(object, ['a', '0', 'b', 'c']);\n * // => true\n *\n * console.log(object);\n * // => { 'a': [{ 'b': {} }] };\n */\nfunction unset(object, path) {\n return object == null ? true : baseUnset(object, path);\n}\n\nexport default unset;\n","import baseGet from './_baseGet.js';\n\n/**\n * Gets the value at `path` of `object`. If the resolved value is\n * `undefined`, the `defaultValue` is returned in its place.\n *\n * @static\n * @memberOf _\n * @since 3.7.0\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the property to get.\n * @param {*} [defaultValue] The value returned for `undefined` resolved values.\n * @returns {*} Returns the resolved value.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 3 } }] };\n *\n * _.get(object, 'a[0].b.c');\n * // => 3\n *\n * _.get(object, ['a', '0', 'b', 'c']);\n * // => 3\n *\n * _.get(object, 'a.b.c', 'default');\n * // => 'default'\n */\nfunction get(object, path, defaultValue) {\n var result = object == null ? undefined : baseGet(object, path);\n return result === undefined ? defaultValue : result;\n}\n\nexport default get;\n","import baseAssignValue from './_baseAssignValue.js';\nimport eq from './eq.js';\n\n/**\n * This function is like `assignValue` except that it doesn't assign\n * `undefined` values.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction assignMergeValue(object, key, value) {\n if ((value !== undefined && !eq(object[key], value)) ||\n (value === undefined && !(key in object))) {\n baseAssignValue(object, key, value);\n }\n}\n\nexport default assignMergeValue;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","import createBaseFor from './_createBaseFor.js';\n\n/**\n * The base implementation of `baseForOwn` which iterates over `object`\n * properties returned by `keysFunc` and invokes `iteratee` for each property.\n * Iteratee functions may exit iteration early by explicitly returning `false`.\n *\n * @private\n * @param {Object} object The object to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @returns {Object} Returns `object`.\n */\nvar baseFor = createBaseFor();\n\nexport default baseFor;\n","import isArrayLike from './isArrayLike.js';\nimport isObjectLike from './isObjectLike.js';\n\n/**\n * This method is like `_.isArrayLike` except that it also checks if `value`\n * is an object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array-like object,\n * else `false`.\n * @example\n *\n * _.isArrayLikeObject([1, 2, 3]);\n * // => true\n *\n * _.isArrayLikeObject(document.body.children);\n * // => true\n *\n * _.isArrayLikeObject('abc');\n * // => false\n *\n * _.isArrayLikeObject(_.noop);\n * // => false\n */\nfunction isArrayLikeObject(value) {\n return isObjectLike(value) && isArrayLike(value);\n}\n\nexport default isArrayLikeObject;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","import copyObject from './_copyObject.js';\nimport keysIn from './keysIn.js';\n\n/**\n * Converts `value` to a plain object flattening inherited enumerable string\n * keyed properties of `value` to own properties of the plain object.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {Object} Returns the converted plain object.\n * @example\n *\n * function Foo() {\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.assign({ 'a': 1 }, new Foo);\n * // => { 'a': 1, 'b': 2 }\n *\n * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));\n * // => { 'a': 1, 'b': 2, 'c': 3 }\n */\nfunction toPlainObject(value) {\n return copyObject(value, keysIn(value));\n}\n\nexport default toPlainObject;\n","import assignMergeValue from './_assignMergeValue.js';\nimport cloneBuffer from './_cloneBuffer.js';\nimport cloneTypedArray from './_cloneTypedArray.js';\nimport copyArray from './_copyArray.js';\nimport initCloneObject from './_initCloneObject.js';\nimport isArguments from './isArguments.js';\nimport isArray from './isArray.js';\nimport isArrayLikeObject from './isArrayLikeObject.js';\nimport isBuffer from './isBuffer.js';\nimport isFunction from './isFunction.js';\nimport isObject from './isObject.js';\nimport isPlainObject from './isPlainObject.js';\nimport isTypedArray from './isTypedArray.js';\nimport safeGet from './_safeGet.js';\nimport toPlainObject from './toPlainObject.js';\n\n/**\n * A specialized version of `baseMerge` for arrays and objects which performs\n * deep merges and tracks traversed objects enabling objects with circular\n * references to be merged.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @param {string} key The key of the value to merge.\n * @param {number} srcIndex The index of `source`.\n * @param {Function} mergeFunc The function to merge values.\n * @param {Function} [customizer] The function to customize assigned values.\n * @param {Object} [stack] Tracks traversed source values and their merged\n * counterparts.\n */\nfunction baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {\n var objValue = safeGet(object, key),\n srcValue = safeGet(source, key),\n stacked = stack.get(srcValue);\n\n if (stacked) {\n assignMergeValue(object, key, stacked);\n return;\n }\n var newValue = customizer\n ? customizer(objValue, srcValue, (key + ''), object, source, stack)\n : undefined;\n\n var isCommon = newValue === undefined;\n\n if (isCommon) {\n var isArr = isArray(srcValue),\n isBuff = !isArr && isBuffer(srcValue),\n isTyped = !isArr && !isBuff && isTypedArray(srcValue);\n\n newValue = srcValue;\n if (isArr || isBuff || isTyped) {\n if (isArray(objValue)) {\n newValue = objValue;\n }\n else if (isArrayLikeObject(objValue)) {\n newValue = copyArray(objValue);\n }\n else if (isBuff) {\n isCommon = false;\n newValue = cloneBuffer(srcValue, true);\n }\n else if (isTyped) {\n isCommon = false;\n newValue = cloneTypedArray(srcValue, true);\n }\n else {\n newValue = [];\n }\n }\n else if (isPlainObject(srcValue) || isArguments(srcValue)) {\n newValue = objValue;\n if (isArguments(objValue)) {\n newValue = toPlainObject(objValue);\n }\n else if (!isObject(objValue) || isFunction(objValue)) {\n newValue = initCloneObject(srcValue);\n }\n }\n else {\n isCommon = false;\n }\n }\n if (isCommon) {\n // Recursively merge objects and arrays (susceptible to call stack limits).\n stack.set(srcValue, newValue);\n mergeFunc(newValue, srcValue, srcIndex, customizer, stack);\n stack['delete'](srcValue);\n }\n assignMergeValue(object, key, newValue);\n}\n\nexport default baseMergeDeep;\n","import Stack from './_Stack.js';\nimport assignMergeValue from './_assignMergeValue.js';\nimport baseFor from './_baseFor.js';\nimport baseMergeDeep from './_baseMergeDeep.js';\nimport isObject from './isObject.js';\nimport keysIn from './keysIn.js';\nimport safeGet from './_safeGet.js';\n\n/**\n * The base implementation of `_.merge` without support for multiple sources.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @param {number} srcIndex The index of `source`.\n * @param {Function} [customizer] The function to customize merged values.\n * @param {Object} [stack] Tracks traversed source values and their merged\n * counterparts.\n */\nfunction baseMerge(object, source, srcIndex, customizer, stack) {\n if (object === source) {\n return;\n }\n baseFor(source, function(srcValue, key) {\n stack || (stack = new Stack);\n if (isObject(srcValue)) {\n baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);\n }\n else {\n var newValue = customizer\n ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack)\n : undefined;\n\n if (newValue === undefined) {\n newValue = srcValue;\n }\n assignMergeValue(object, key, newValue);\n }\n }, keysIn);\n}\n\nexport default baseMerge;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","import apply from './_apply.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max;\n\n/**\n * A specialized version of `baseRest` which transforms the rest array.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @param {Function} transform The rest array transform.\n * @returns {Function} Returns the new function.\n */\nfunction overRest(func, start, transform) {\n start = nativeMax(start === undefined ? (func.length - 1) : start, 0);\n return function() {\n var args = arguments,\n index = -1,\n length = nativeMax(args.length - start, 0),\n array = Array(length);\n\n while (++index < length) {\n array[index] = args[start + index];\n }\n index = -1;\n var otherArgs = Array(start + 1);\n while (++index < start) {\n otherArgs[index] = args[index];\n }\n otherArgs[start] = transform(array);\n return apply(func, this, otherArgs);\n };\n}\n\nexport default overRest;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","import constant from './constant.js';\nimport defineProperty from './_defineProperty.js';\nimport identity from './identity.js';\n\n/**\n * The base implementation of `setToString` without support for hot loop shorting.\n *\n * @private\n * @param {Function} func The function to modify.\n * @param {Function} string The `toString` result.\n * @returns {Function} Returns `func`.\n */\nvar baseSetToString = !defineProperty ? identity : function(func, string) {\n return defineProperty(func, 'toString', {\n 'configurable': true,\n 'enumerable': false,\n 'value': constant(string),\n 'writable': true\n });\n};\n\nexport default baseSetToString;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","import baseSetToString from './_baseSetToString.js';\nimport shortOut from './_shortOut.js';\n\n/**\n * Sets the `toString` method of `func` to return `string`.\n *\n * @private\n * @param {Function} func The function to modify.\n * @param {Function} string The `toString` result.\n * @returns {Function} Returns `func`.\n */\nvar setToString = shortOut(baseSetToString);\n\nexport default setToString;\n","import identity from './identity.js';\nimport overRest from './_overRest.js';\nimport setToString from './_setToString.js';\n\n/**\n * The base implementation of `_.rest` which doesn't validate or coerce arguments.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @returns {Function} Returns the new function.\n */\nfunction baseRest(func, start) {\n return setToString(overRest(func, start, identity), func + '');\n}\n\nexport default baseRest;\n","import eq from './eq.js';\nimport isArrayLike from './isArrayLike.js';\nimport isIndex from './_isIndex.js';\nimport isObject from './isObject.js';\n\n/**\n * Checks if the given arguments are from an iteratee call.\n *\n * @private\n * @param {*} value The potential iteratee value argument.\n * @param {*} index The potential iteratee index or key argument.\n * @param {*} object The potential iteratee object argument.\n * @returns {boolean} Returns `true` if the arguments are from an iteratee call,\n * else `false`.\n */\nfunction isIterateeCall(value, index, object) {\n if (!isObject(object)) {\n return false;\n }\n var type = typeof index;\n if (type == 'number'\n ? (isArrayLike(object) && isIndex(index, object.length))\n : (type == 'string' && index in object)\n ) {\n return eq(object[index], value);\n }\n return false;\n}\n\nexport default isIterateeCall;\n","import baseRest from './_baseRest.js';\nimport isIterateeCall from './_isIterateeCall.js';\n\n/**\n * Creates a function like `_.assign`.\n *\n * @private\n * @param {Function} assigner The function to assign values.\n * @returns {Function} Returns the new assigner function.\n */\nfunction createAssigner(assigner) {\n return baseRest(function(object, sources) {\n var index = -1,\n length = sources.length,\n customizer = length > 1 ? sources[length - 1] : undefined,\n guard = length > 2 ? sources[2] : undefined;\n\n customizer = (assigner.length > 3 && typeof customizer == 'function')\n ? (length--, customizer)\n : undefined;\n\n if (guard && isIterateeCall(sources[0], sources[1], guard)) {\n customizer = length < 3 ? undefined : customizer;\n length = 1;\n }\n object = Object(object);\n while (++index < length) {\n var source = sources[index];\n if (source) {\n assigner(object, source, index, customizer);\n }\n }\n return object;\n });\n}\n\nexport default createAssigner;\n","import baseMerge from './_baseMerge.js';\nimport createAssigner from './_createAssigner.js';\n\n/**\n * This method is like `_.assign` except that it recursively merges own and\n * inherited enumerable string keyed properties of source objects into the\n * destination object. Source properties that resolve to `undefined` are\n * skipped if a destination value exists. Array and plain object properties\n * are merged recursively. Other objects and value types are overridden by\n * assignment. Source objects are applied from left to right. Subsequent\n * sources overwrite property assignments of previous sources.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 0.5.0\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @example\n *\n * var object = {\n * 'a': [{ 'b': 2 }, { 'd': 4 }]\n * };\n *\n * var other = {\n * 'a': [{ 'c': 3 }, { 'e': 5 }]\n * };\n *\n * _.merge(object, other);\n * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }\n */\nvar merge = createAssigner(function(object, source, srcIndex) {\n baseMerge(object, source, srcIndex);\n});\n\nexport default merge;\n","import assignValue from './_assignValue.js';\nimport castPath from './_castPath.js';\nimport isIndex from './_isIndex.js';\nimport isObject from './isObject.js';\nimport toKey from './_toKey.js';\n\n/**\n * The base implementation of `_.set`.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to set.\n * @param {*} value The value to set.\n * @param {Function} [customizer] The function to customize path creation.\n * @returns {Object} Returns `object`.\n */\nfunction baseSet(object, path, value, customizer) {\n if (!isObject(object)) {\n return object;\n }\n path = castPath(path, object);\n\n var index = -1,\n length = path.length,\n lastIndex = length - 1,\n nested = object;\n\n while (nested != null && ++index < length) {\n var key = toKey(path[index]),\n newValue = value;\n\n if (index != lastIndex) {\n var objValue = nested[key];\n newValue = customizer ? customizer(objValue, key, nested) : undefined;\n if (newValue === undefined) {\n newValue = isObject(objValue)\n ? objValue\n : (isIndex(path[index + 1]) ? [] : {});\n }\n }\n assignValue(nested, key, newValue);\n nested = nested[key];\n }\n return object;\n}\n\nexport default baseSet;\n","import baseSet from './_baseSet.js';\n\n/**\n * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,\n * it's created. Arrays are created for missing index properties while objects\n * are created for all other missing properties. Use `_.setWith` to customize\n * `path` creation.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 3.7.0\n * @category Object\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns `object`.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 3 } }] };\n *\n * _.set(object, 'a[0].b.c', 4);\n * console.log(object.a[0].b.c);\n * // => 4\n *\n * _.set(object, ['x', '0', 'y', 'z'], 5);\n * console.log(object.x[0].y.z);\n * // => 5\n */\nfunction set(object, path, value) {\n return object == null ? object : baseSet(object, path, value);\n}\n\nexport default set;\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/stylesmap\n */\n\nimport { get, isObject, merge, set, unset } from 'lodash-es';\n\n/**\n * Styles map. Allows handling (adding, removing, retrieving) a set of style rules (usually, of an element).\n *\n * The styles map is capable of normalizing style names so e.g. the following operations are possible:\n */\nexport default class StylesMap {\n\t/**\n\t * Creates Styles instance.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Keeps an internal representation of styles map. Normalized styles are kept as object tree to allow unified modification and\n\t\t * value access model using lodash's get, set, unset, etc methods.\n\t\t *\n\t\t * When no style processor rules are defined the it acts as simple key-value storage.\n\t\t *\n\t\t * @type {Object}\n\t\t * @private\n\t\t */\n\t\tthis._styles = {};\n\n\t\t// Hide _styleProcessor from the watchdog by making this property non-enumarable. Watchdog checks errors for their editor origin\n\t\t// by checking if two objects are connected through properties. Using singleton is against this check as it would detect\n\t\t// that two editors are connected through single style processor instance.\n\t\tObject.defineProperty( this, '_styleProcessor', {\n\t\t\tget() {\n\t\t\t\treturn StylesMap._styleProcessor;\n\t\t\t},\n\t\t\tenumerable: false\n\t\t} );\n\t}\n\n\t/**\n\t * Returns true if style map has no styles set.\n\t *\n\t * @returns {Boolean}\n\t */\n\tget isEmpty() {\n\t\tconst entries = Object.entries( this._styles );\n\t\tconst from = Array.from( entries );\n\n\t\treturn !from.length;\n\t}\n\n\t/**\n\t * Number of styles defined.\n\t *\n\t * @type {Number}\n\t */\n\tget size() {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn this.getStyleNames().length;\n\t}\n\n\t/**\n\t * Set styles map to a new value.\n\t *\n\t *\t\tstyles.setTo( 'border:1px solid blue;margin-top:1px;' );\n\t *\n\t * @param {String} inlineStyle\n\t */\n\tsetTo( inlineStyle ) {\n\t\tthis.clear();\n\n\t\tconst parsedStyles = Array.from( parseInlineStyles( inlineStyle ).entries() );\n\n\t\tfor ( const [ key, value ] of parsedStyles ) {\n\t\t\tthis._styleProcessor.toNormalizedForm( key, value, this._styles );\n\t\t}\n\t}\n\n\t/**\n\t * Checks if a given style is set.\n\t *\n\t *\t\tstyles.setTo( 'margin-left:1px;' );\n\t *\n\t *\t\tstyles.has( 'margin-left' ); // -> true\n\t *\t\tstyles.has( 'padding' ); // -> false\n\t *\n\t * **Note**: This check supports normalized style names.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.editing.view.document.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tstyles.setTo( 'margin:2px;' );\n\t *\n\t *\t\tstyles.has( 'margin' ); // -> true\n\t *\t\tstyles.has( 'margin-top' ); // -> true\n\t *\t\tstyles.has( 'margin-left' ); // -> true\n\t *\n\t *\t\tstyles.remove( 'margin-top' );\n\t *\n\t *\t\tstyles.has( 'margin' ); // -> false\n\t *\t\tstyles.has( 'margin-top' ); // -> false\n\t *\t\tstyles.has( 'margin-left' ); // -> true\n\t *\n\t * @param {String} name Style name.\n\t * @returns {Boolean}\n\t */\n\thas( name ) {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst styles = this._styleProcessor.getReducedForm( name, this._styles );\n\n\t\tconst propertyDescriptor = styles.find( ( [ property ] ) => property === name );\n\n\t\t// Only return a value if it is set;\n\t\treturn Array.isArray( propertyDescriptor );\n\t}\n\n\t/**\n\t * Sets a given style.\n\t *\n\t * Can insert one by one:\n\t *\n\t *\t\tstyles.set( 'color', 'blue' );\n\t *\t\tstyles.set( 'margin-right', '1em' );\n\t *\n\t * or many styles at once:\n\t *\n\t *\t\tstyles.set( {\n\t *\t\t\tcolor: 'blue',\n\t *\t\t\t'margin-right': '1em'\n\t *\t\t} );\n\t *\n\t * ***Note**:* This method uses {@link module:engine/view/document~Document#addStyleProcessorRules enabled style processor rules}\n\t * to normalize passed values.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.editing.view.document.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tstyles.set( 'margin', '2px' );\n\t *\n\t * The above code will set margin to:\n\t *\n\t *\t\tstyles.getNormalized( 'margin' );\n\t *\t\t// -> { top: '2px', right: '2px', bottom: '2px', left: '2px' }\n\t *\n\t * Which makes it possible to retrieve a \"sub-value\":\n\t *\n\t *\t\tstyles.get( 'margin-left' ); // -> '2px'\n\t *\n\t * Or modify it:\n\t *\n\t *\t\tstyles.remove( 'margin-left' );\n\t *\n\t *\t\tstyles.getNormalized( 'margin' ); // -> { top: '1px', bottom: '1px', right: '1px' }\n\t *\t\tstyles.toString(); // -> 'margin-bottom:1px;margin-right:1px;margin-top:1px;'\n\t *\n\t * This method also allows to set normalized values directly (if a particular styles processor rule was enabled):\n\t *\n\t *\t\tstyles.set( 'border-color', { top: 'blue' } );\n\t *\t\tstyles.set( 'margin', { right: '2em' } );\n\t *\n\t *\t\tstyles.toString(); // -> 'border-color-top:blue;margin-right:2em;'\n\t *\n\t * @param {String|Object} nameOrObject Style property name or object with multiple properties.\n\t * @param {String|Object} valueOrObject Value to set.\n\t */\n\tset( nameOrObject, valueOrObject ) {\n\t\tif ( isObject( nameOrObject ) ) {\n\t\t\tfor ( const [ key, value ] of Object.entries( nameOrObject ) ) {\n\t\t\t\tthis._styleProcessor.toNormalizedForm( key, value, this._styles );\n\t\t\t}\n\t\t} else {\n\t\t\tthis._styleProcessor.toNormalizedForm( nameOrObject, valueOrObject, this._styles );\n\t\t}\n\t}\n\n\t/**\n\t * Removes given style.\n\t *\n\t *\t\tstyles.setTo( 'background:#f00;margin-right:2px;' );\n\t *\n\t *\t\tstyles.remove( 'background' );\n\t *\n\t *\t\tstyles.toString(); // -> 'margin-right:2px;'\n\t *\n\t * ***Note**:* This method uses {@link module:engine/view/document~Document#addStyleProcessorRules enabled style processor rules}\n\t * to normalize passed values.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.editing.view.document.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tstyles.setTo( 'margin:1px' );\n\t *\n\t *\t\tstyles.remove( 'margin-top' );\n\t *\t\tstyles.remove( 'margin-right' );\n\t *\n\t *\t\tstyles.toString(); // -> 'margin-bottom:1px;margin-left:1px;'\n\t *\n\t * @param {String} name Style name.\n\t */\n\tremove( name ) {\n\t\tconst path = toPath( name );\n\n\t\tunset( this._styles, path );\n\t\tdelete this._styles[ name ];\n\n\t\tthis._cleanEmptyObjectsOnPath( path );\n\t}\n\n\t/**\n\t * Returns a normalized style object or a single value.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.editing.view.document.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px 2px 3em;' );\n\t *\n\t *\t\tstyles.getNormalized( 'margin' );\n\t *\t\t// will log:\n\t *\t\t// {\n\t *\t\t// top: '1px',\n\t *\t\t// right: '2px',\n\t *\t\t// bottom: '3em',\n\t *\t\t// left: '2px' // normalized value from margin shorthand\n\t *\t\t// }\n\t *\n\t *\t\tstyles.getNormalized( 'margin-left' ); // -> '2px'\n\t *\n\t * **Note**: This method will only return normalized styles if a style processor was defined.\n\t *\n\t * @param {String} name Style name.\n\t * @returns {Object|String|undefined}\n\t */\n\tgetNormalized( name ) {\n\t\treturn this._styleProcessor.getNormalized( name, this._styles );\n\t}\n\n\t/**\n\t * Returns a normalized style string. Styles are sorted by name.\n\t *\n\t *\t\tstyles.set( 'margin' , '1px' );\n\t *\t\tstyles.set( 'background', '#f00' );\n\t *\n\t *\t\tstyles.toString(); // -> 'background:#f00;margin:1px;'\n\t *\n\t * **Note**: This method supports normalized styles if defined.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.editing.view.document.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tstyles.set( 'margin' , '1px' );\n\t *\t\tstyles.set( 'background', '#f00' );\n\t *\t\tstyles.remove( 'margin-top' );\n\t *\t\tstyles.remove( 'margin-right' );\n\t *\n\t *\t\tstyles.toString(); // -> 'background:#f00;margin-bottom:1px;margin-left:1px;'\n\t *\n\t * @returns {String}\n\t */\n\ttoString() {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn '';\n\t\t}\n\n\t\treturn this._getStylesEntries()\n\t\t\t.map( arr => arr.join( ':' ) )\n\t\t\t.sort()\n\t\t\t.join( ';' ) + ';';\n\t}\n\n\t/**\n\t * Returns property as a value string or undefined if property is not set.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.editing.view.document.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px;' );\n\t *\t\tstyles.set( 'margin-bottom', '3em' );\n\t *\n\t *\t\tstyles.getAsString( 'margin' ); // -> 'margin: 1px 1px 3em;'\n\t *\n\t * Note, however, that all sub-values must be set for the longhand property name to return a value:\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px;' );\n\t *\t\tstyles.remove( 'margin-bottom' );\n\t *\n\t *\t\tstyles.getAsString( 'margin' ); // -> undefined\n\t *\n\t * In the above scenario, it is not possible to return a `margin` value, so `undefined` is returned.\n\t * Instead, you should use:\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px;' );\n\t *\t\tstyles.remove( 'margin-bottom' );\n\t *\n\t *\t\tfor ( const styleName of styles.getStyleNames() ) {\n\t *\t\t\tconsole.log( styleName, styles.getAsString( styleName ) );\n\t *\t\t}\n\t *\t\t// 'margin-top', '1px'\n\t *\t\t// 'margin-right', '1px'\n\t *\t\t// 'margin-left', '1px'\n\t *\n\t * In general, it is recommend to iterate over style names like in the example above. This way, you will always get all\n\t * the currently set style values. So, if all the 4 margin values would be set\n\t * the for-of loop above would yield only `'margin'`, `'1px'`:\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px;' );\n\t *\n\t *\t\tfor ( const styleName of styles.getStyleNames() ) {\n\t *\t\t\tconsole.log( styleName, styles.getAsString( styleName ) );\n\t *\t\t}\n\t *\t\t// 'margin', '1px'\n\t *\n\t * **Note**: To get a normalized version of a longhand property use the {@link #getNormalized `#getNormalized()`} method.\n\t *\n\t * @param {String} propertyName\n\t * @returns {String|undefined}\n\t */\n\tgetAsString( propertyName ) {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this._styles[ propertyName ] && !isObject( this._styles[ propertyName ] ) ) {\n\t\t\t// Try return styles set directly - values that are not parsed.\n\t\t\treturn this._styles[ propertyName ];\n\t\t}\n\n\t\tconst styles = this._styleProcessor.getReducedForm( propertyName, this._styles );\n\n\t\tconst propertyDescriptor = styles.find( ( [ property ] ) => property === propertyName );\n\n\t\t// Only return a value if it is set;\n\t\tif ( Array.isArray( propertyDescriptor ) ) {\n\t\t\treturn propertyDescriptor[ 1 ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns style property names as they would appear when using {@link #toString `#toString()`}.\n\t *\n\t * @returns {Array.<String>}\n\t */\n\tgetStyleNames() {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst entries = this._getStylesEntries();\n\n\t\treturn entries.map( ( [ key ] ) => key );\n\t}\n\n\t/**\n\t * Removes all styles.\n\t */\n\tclear() {\n\t\tthis._styles = {};\n\t}\n\n\t/**\n\t * Returns related style names.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.editing.view.document.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tStylesMap.getRelatedStyles( 'margin' );\n\t *\t\t// will return: [ 'margin-top', 'margin-right', 'margin-bottom', 'margin-left' ];\n\t *\n\t *\t\tStylesMap.getRelatedStyles( 'margin-top' );\n\t *\t\t// will return: [ 'margin' ];\n\t *\n\t * **Note**: To define new style relations load an existing style processor (as shown above) or use\n\t * {@link module:engine/view/stylesmap~StylesProcessor#setStyleRelation `StylesProcessor.setStyleRelation()`}.\n\t *\n\t * @param {String} name\n\t * @returns {Array.<String>}\n\t */\n\tstatic getRelatedStyles( name ) {\n\t\treturn this._styleProcessor.getRelatedStyles( name );\n\t}\n\n\t/**\n\t * Returns normalized styles entries for further processing.\n\t *\n\t * @private\n\t * @returns {Array.<module:engine/view/stylesmap~PropertyDescriptor>}\n\t */\n\t_getStylesEntries() {\n\t\tconst parsed = [];\n\n\t\tconst keys = Object.keys( this._styles );\n\n\t\tfor ( const key of keys ) {\n\t\t\tparsed.push( ...this._styleProcessor.getReducedForm( key, this._styles ) );\n\t\t}\n\n\t\treturn parsed;\n\t}\n\n\t/**\n\t * Removes empty objects upon removing an entry from internal object.\n\t *\n\t * @param {String} path\n\t * @private\n\t */\n\t_cleanEmptyObjectsOnPath( path ) {\n\t\tconst pathParts = path.split( '.' );\n\t\tconst isChildPath = pathParts.length > 1;\n\n\t\tif ( !isChildPath ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst parentPath = pathParts.splice( 0, pathParts.length - 1 ).join( '.' );\n\n\t\tconst parentObject = get( this._styles, parentPath );\n\n\t\tif ( !parentObject ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isParentEmpty = !Array.from( Object.keys( parentObject ) ).length;\n\n\t\tif ( isParentEmpty ) {\n\t\t\tthis.remove( parentPath );\n\t\t}\n\t}\n\n\t/**\n\t * Returns global StylesProcessor instance.\n\t *\n\t * @returns {module:engine/view/stylesmap~StylesProcessor}\n\t * @private\n\t */\n\tstatic get _styleProcessor() {\n\t\tif ( !this._processor ) {\n\t\t\tthis._processor = new StylesProcessor();\n\t\t}\n\n\t\treturn this._processor;\n\t}\n\n\t/**\n\t * Set new StylesProcessor instance.\n\t *\n\t * This is an internal method used mostly in tests.\n\t *\n\t * @param processor\n\t * @protected\n\t */\n\tstatic _setProcessor( processor ) {\n\t\tthis._processor = processor;\n\t}\n}\n\n/**\n * Style processor is responsible for writing and reading a normalized styles object.\n */\nexport class StylesProcessor {\n\t/**\n\t * Creates StylesProcessor instance.\n\t *\n\t * @private\n\t */\n\tconstructor() {\n\t\tthis._normalizers = new Map();\n\t\tthis._extractors = new Map();\n\t\tthis._reducers = new Map();\n\t\tthis._consumables = new Map();\n\t}\n\n\t/**\n\t * Parse style string value to a normalized object and appends it to styles object.\n\t *\n\t *\t\tconst styles = {};\n\t *\n\t *\t\tstylesProcessor.toNormalizedForm( 'margin', '1px', styles );\n\t *\n\t *\t\t// styles will consist: { margin: { top: '1px', right: '1px', bottom: '1px', left: '1px; } }\n\t *\n\t * **Note**: To define normalizer callbacks use {@link #setNormalizer}.\n\t *\n\t * @param {String} name Name of style property.\n\t * @param {String} propertyValue Value of style property.\n\t * @param {Object} styles Object holding normalized styles.\n\t */\n\ttoNormalizedForm( name, propertyValue, styles ) {\n\t\tif ( isObject( propertyValue ) ) {\n\t\t\tappendStyleValue( styles, toPath( name ), propertyValue );\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this._normalizers.has( name ) ) {\n\t\t\tconst normalizer = this._normalizers.get( name );\n\n\t\t\tconst { path, value } = normalizer( propertyValue );\n\n\t\t\tappendStyleValue( styles, path, value );\n\t\t} else {\n\t\t\tappendStyleValue( styles, name, propertyValue );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a normalized version of a style property.\n\t *\t\tconst styles = {\n\t *\t\t\tmargin: { top: '1px', right: '1px', bottom: '1px', left: '1px; },\n\t *\t\t\tbackground: { color: '#f00' }\n\t *\t\t};\n\t *\n\t *\t\tstylesProcessor.getNormalized( 'background' );\n\t *\t\t// will return: { color: '#f00' }\n\t *\n\t *\t\tstylesProcessor.getNormalized( 'margin-top' );\n\t *\t\t// will return: '1px'\n\t *\n\t * **Note**: In some cases extracting single value requires defining an extractor callback {@link #setExtractor}.\n\t *\n\t * @param {String} name Name of style property.\n\t * @param {Object} styles Object holding normalized styles.\n\t * @returns {*}\n\t */\n\tgetNormalized( name, styles ) {\n\t\tif ( !name ) {\n\t\t\treturn merge( {}, styles );\n\t\t}\n\n\t\t// Might be empty string.\n\t\tif ( styles[ name ] !== undefined ) {\n\t\t\treturn styles[ name ];\n\t\t}\n\n\t\tif ( this._extractors.has( name ) ) {\n\t\t\tconst extractor = this._extractors.get( name );\n\n\t\t\tif ( typeof extractor === 'string' ) {\n\t\t\t\treturn get( styles, extractor );\n\t\t\t}\n\n\t\t\tconst value = extractor( name, styles );\n\n\t\t\tif ( value ) {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\n\t\treturn get( styles, toPath( name ) );\n\t}\n\n\t/**\n\t * Returns a reduced form of style property form normalized object.\n\t *\n\t * For default margin reducer, the below code:\n\t *\n\t *\t\tstylesProcessor.getReducedForm( 'margin', {\n\t *\t\t\tmargin: { top: '1px', right: '1px', bottom: '2px', left: '1px; }\n\t *\t\t} );\n\t *\n\t * will return:\n\t *\n\t *\t\t[\n\t *\t\t\t[ 'margin', '1px 1px 2px' ]\n\t *\t\t]\n\t *\n\t * because it might be represented as a shorthand 'margin' value. However if one of margin long hand values is missing it should return:\n\t *\n\t *\t\t[\n\t *\t\t\t[ 'margin-top', '1px' ],\n\t *\t\t\t[ 'margin-right', '1px' ],\n\t *\t\t\t[ 'margin-bottom', '2px' ]\n\t *\t\t\t// the 'left' value is missing - cannot use 'margin' shorthand.\n\t *\t\t]\n\t *\n\t * **Note**: To define reducer callbacks use {@link #setReducer}.\n\t *\n\t * @param {String} name\n\t * @param {String} name Name of style property.\n\t * @param {Object} styles Object holding normalized styles.\n\t * @returns {Array.<module:engine/view/stylesmap~PropertyDescriptor>}\n\t */\n\tgetReducedForm( name, styles ) {\n\t\tconst normalizedValue = this.getNormalized( name, styles );\n\n\t\t// Might be empty string.\n\t\tif ( normalizedValue === undefined ) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif ( this._reducers.has( name ) ) {\n\t\t\tconst reducer = this._reducers.get( name );\n\n\t\t\treturn reducer( normalizedValue );\n\t\t}\n\n\t\treturn [ [ name, normalizedValue ] ];\n\t}\n\n\t/**\n\t * Returns related style names.\n\t *\n\t *\t\tstylesProcessor.getRelatedStyles( 'margin' );\n\t *\t\t// will return: [ 'margin-top', 'margin-right', 'margin-bottom', 'margin-left' ];\n\t *\n\t *\t\tstylesProcessor.getRelatedStyles( 'margin-top' );\n\t *\t\t// will return: [ 'margin' ];\n\t *\n\t * **Note**: To define new style relations load an existing style processor or use\n\t * {@link module:engine/view/stylesmap~StylesProcessor#setStyleRelation `StylesProcessor.setStyleRelation()`}.\n\t *\n\t * @param {String} name\n\t * @returns {Array.<String>}\n\t */\n\tgetRelatedStyles( name ) {\n\t\treturn this._consumables.get( name ) || [];\n\t}\n\n\t/**\n\t * Adds a normalizer method for a style property.\n\t *\n\t * A normalizer returns describing how the value should be normalized.\n\t *\n\t * For instance 'margin' style is a shorthand for four margin values:\n\t *\n\t * - 'margin-top'\n\t * - 'margin-right'\n\t * - 'margin-bottom'\n\t * - 'margin-left'\n\t *\n\t * and can be written in various ways if some values are equal to others. For instance `'margin: 1px 2em;'` is a shorthand for\n\t * `'margin-top: 1px;margin-right: 2em;margin-bottom: 1px;margin-left: 2em'`.\n\t *\n\t * A normalizer should parse various margin notations as a single object:\n\t *\n\t *\t\tconst styles = {\n\t *\t\t\tmargin: {\n\t *\t\t\t\ttop: '1px',\n\t *\t\t\t\tright: '2em',\n\t *\t\t\t\tbottom: '1px',\n\t *\t\t\t\tleft: '2em'\n\t *\t\t\t}\n\t *\t\t};\n\t *\n\t * Thus a normalizer for 'margin' style should return an object defining style path and value to store:\n\t *\n\t *\t\tconst returnValue = {\n\t *\t\t\tpath: 'margin',\n\t *\t\t\tvalue: {\n\t *\t\t\t\ttop: '1px',\n\t *\t\t\t\tright: '2em',\n\t *\t\t\t\tbottom: '1px',\n\t *\t\t\t\tleft: '2em'\n\t *\t\t\t}\n\t *\t\t};\n\t *\n\t * Additionally to fully support all margin notations there should be also defined 4 normalizers for longhand margin notations. Below\n\t * is an example for 'margin-top' style property normalizer:\n\t *\n\t *\t\tstylesProcessor.setNormalizer( 'margin-top', valueString => {\n\t *\t\t\treturn {\n\t *\t\t\t\tpath: 'margin.top',\n\t *\t\t\t\tvalue: valueString\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @param {String} name\n\t * @param {Function} callback\n\t */\n\tsetNormalizer( name, callback ) {\n\t\tthis._normalizers.set( name, callback );\n\t}\n\n\t/**\n\t * Adds a extractor callback for a style property.\n\t *\n\t * Most normalized style values are stored as one level objects. It is assumed that `'margin-top'` style will be stored as:\n\t *\n\t *\t\tconst styles = {\n\t *\t\t\tmargin: {\n\t *\t\t\t\ttop: 'value'\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * However, some styles can have conflicting notations and thus it might be harder to extract a style value from shorthand. For instance\n\t * the 'border-top-style' can be defined using `'border-top:solid'`, `'border-style:solid none none none'` or by `'border:solid'`\n\t * shorthands. The default border styles processors stores styles as:\n\t *\n\t *\t\tconst styles = {\n\t *\t\t\tborder: {\n\t *\t\t\t\tstyle: {\n\t *\t\t\t\t\ttop: 'solid'\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * as it is better to modify border style independently from other values. On the other part the output of the border might be\n\t * desired as `border-top`, `border-left`, etc notation.\n\t *\n\t * In the above example a reducer should return a side border value that combines style, color and width:\n\t *\n\t *\t\tstyleProcessor.setExtractor( 'border-top', styles => {\n\t *\t\t\treturn {\n\t *\t\t\t\tcolor: styles.border.color.top,\n\t *\t\t\t\tstyle: styles.border.style.top,\n\t *\t\t\t\twidth: styles.border.width.top\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @param {String} name\n\t * @param {Function|String} callbackOrPath Callback that return a requested value or path string for single values.\n\t */\n\tsetExtractor( name, callbackOrPath ) {\n\t\tthis._extractors.set( name, callbackOrPath );\n\t}\n\n\t/**\n\t * Adds a reducer callback for a style property.\n\t *\n\t * Reducer returns a minimal notation for given style name. For longhand properties it is not required to write a reducer as\n\t * by default the direct value from style path is taken.\n\t *\n\t * For shorthand styles a reducer should return minimal style notation either by returning single name-value tuple or multiple tuples\n\t * if a shorthand cannot be used. For instance for a margin shorthand a reducer might return:\n\t *\n\t *\t\tconst marginShortHandTuple = [\n\t *\t\t\t[ 'margin', '1px 1px 2px' ]\n\t *\t\t];\n\t *\n\t * or a longhand tuples for defined values:\n\t *\n\t *\t\t// Considering margin.bottom and margin.left are undefined.\n\t *\t\tconst marginLonghandsTuples = [\n\t *\t\t\t[ 'margin-top', '1px' ],\n\t *\t\t\t[ 'margin-right', '1px' ]\n\t *\t\t];\n\t *\n\t * A reducer obtains a normalized style value:\n\t *\n\t *\t\t// Simplified reducer that always outputs 4 values which are always present:\n\t *\t\tstylesProcessor.setReducer( 'margin', margin => {\n\t *\t\t\treturn [\n\t *\t\t\t\t[ 'margin', `${ margin.top } ${ margin.right } ${ margin.bottom } ${ margin.left }` ]\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t * @param {String} name\n\t * @param {Function} callback\n\t */\n\tsetReducer( name, callback ) {\n\t\tthis._reducers.set( name, callback );\n\t}\n\n\t/**\n\t * Defines a style shorthand relation to other style notations.\n\t *\n\t *\t\tstylesProcessor.setStyleRelation( 'margin', [\n\t *\t\t\t'margin-top',\n\t *\t\t\t'margin-right',\n\t *\t\t\t'margin-bottom',\n\t *\t\t\t'margin-left'\n\t *\t\t] );\n\t *\n\t * This enables expanding of style names for shorthands. For instance, if defined,\n\t * {@link module:engine/conversion/viewconsumable~ViewConsumable view consumable} items are automatically created\n\t * for long-hand margin style notation alongside the `'margin'` item.\n\t *\n\t * This means that when an element being converted has a style `margin`, a converter for `margin-left` will work just\n\t * fine since the view consumable will contain a consumable `margin-left` item (thanks to the relation) and\n\t * `element.getStyle( 'margin-left' )` will work as well assuming that the style processor was correctly configured.\n\t * However, once `margin-left` is consumed, `margin` will not be consumable anymore.\n\t *\n\t * @param {String} shorthandName\n\t * @param {Array.<String>} styleNames\n\t */\n\tsetStyleRelation( shorthandName, styleNames ) {\n\t\tthis._mapStyleNames( shorthandName, styleNames );\n\n\t\tfor ( const alsoName of styleNames ) {\n\t\t\tthis._mapStyleNames( alsoName, [ shorthandName ] );\n\t\t}\n\t}\n\n\t/**\n\t * Set two-way binding of style names.\n\t *\n\t * @param {String} name\n\t * @param {Array.<String>} styleNames\n\t * @private\n\t */\n\t_mapStyleNames( name, styleNames ) {\n\t\tif ( !this._consumables.has( name ) ) {\n\t\t\tthis._consumables.set( name, [] );\n\t\t}\n\n\t\tthis._consumables.get( name ).push( ...styleNames );\n\t}\n}\n\n// Parses inline styles and puts property - value pairs into styles map.\n//\n// @param {String} stylesString Styles to parse.\n// @returns {Map.<String, String>} stylesMap Map of parsed properties and values.\nfunction parseInlineStyles( stylesString ) {\n\t// `null` if no quote was found in input string or last found quote was a closing quote. See below.\n\tlet quoteType = null;\n\tlet propertyNameStart = 0;\n\tlet propertyValueStart = 0;\n\tlet propertyName = null;\n\n\tconst stylesMap = new Map();\n\n\t// Do not set anything if input string is empty.\n\tif ( stylesString === '' ) {\n\t\treturn stylesMap;\n\t}\n\n\t// Fix inline styles that do not end with `;` so they are compatible with algorithm below.\n\tif ( stylesString.charAt( stylesString.length - 1 ) != ';' ) {\n\t\tstylesString = stylesString + ';';\n\t}\n\n\t// Seek the whole string for \"special characters\".\n\tfor ( let i = 0; i < stylesString.length; i++ ) {\n\t\tconst char = stylesString.charAt( i );\n\n\t\tif ( quoteType === null ) {\n\t\t\t// No quote found yet or last found quote was a closing quote.\n\t\t\tswitch ( char ) {\n\t\t\t\tcase ':':\n\t\t\t\t\t// Most of time colon means that property name just ended.\n\t\t\t\t\t// Sometimes however `:` is found inside property value (for example in background image url).\n\t\t\t\t\tif ( !propertyName ) {\n\t\t\t\t\t\t// Treat this as end of property only if property name is not already saved.\n\t\t\t\t\t\t// Save property name.\n\t\t\t\t\t\tpropertyName = stylesString.substr( propertyNameStart, i - propertyNameStart );\n\t\t\t\t\t\t// Save this point as the start of property value.\n\t\t\t\t\t\tpropertyValueStart = i + 1;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '\"':\n\t\t\t\tcase '\\'':\n\t\t\t\t\t// Opening quote found (this is an opening quote, because `quoteType` is `null`).\n\t\t\t\t\tquoteType = char;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ';': {\n\t\t\t\t\t// Property value just ended.\n\t\t\t\t\t// Use previously stored property value start to obtain property value.\n\t\t\t\t\tconst propertyValue = stylesString.substr( propertyValueStart, i - propertyValueStart );\n\n\t\t\t\t\tif ( propertyName ) {\n\t\t\t\t\t\t// Save parsed part.\n\t\t\t\t\t\tstylesMap.set( propertyName.trim(), propertyValue.trim() );\n\t\t\t\t\t}\n\n\t\t\t\t\tpropertyName = null;\n\n\t\t\t\t\t// Save this point as property name start. Property name starts immediately after previous property value ends.\n\t\t\t\t\tpropertyNameStart = i + 1;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ( char === quoteType ) {\n\t\t\t// If a quote char is found and it is a closing quote, mark this fact by `null`-ing `quoteType`.\n\t\t\tquoteType = null;\n\t\t}\n\t}\n\n\treturn stylesMap;\n}\n\n// Return lodash compatible path from style name.\nfunction toPath( name ) {\n\treturn name.replace( '-', '.' );\n}\n\n// Appends style definition to the styles object.\n//\n// @param {String} nameOrPath\n// @param {String|Object} valueOrObject\n// @private\nfunction appendStyleValue( stylesObject, nameOrPath, valueOrObject ) {\n\tlet valueToSet = valueOrObject;\n\n\tif ( isObject( valueOrObject ) ) {\n\t\tvalueToSet = merge( {}, get( stylesObject, nameOrPath ), valueOrObject );\n\t}\n\n\tset( stylesObject, nameOrPath, valueToSet );\n}\n\n/**\n * A CSS style property descriptor that contains tuplet of two strings:\n *\n * - first string describes property name\n * - second string describes property value\n *\n *\t\tconst marginDescriptor = [ 'margin', '2px 3em' ];\n *\t\tconst marginTopDescriptor = [ 'margin-top', '2px' ];\n *\n * @typedef {Array.<String, String>} module:engine/view/stylesmap~PropertyDescriptor\n */\n\n/**\n * An object describing values associated with the sides of a box, for instance margins, paddings,\n * border widths, border colors, etc.\n *\n *\t\tconst margin = {\n *\t\t\ttop: '1px',\n *\t\t\tright: '3px',\n *\t\t\tbottom: '3px',\n *\t\t\tleft: '7px'\n *\t\t};\n *\n *\t\tconst borderColor = {\n *\t\t\ttop: 'red',\n *\t\t\tright: 'blue',\n *\t\t\tbottom: 'blue',\n *\t\t\tleft: 'red'\n *\t\t};\n *\n * @typedef {Object} module:engine/view/stylesmap~BoxSides\n *\n * @property {String} top Top side value.\n * @property {String} right Right side value.\n * @property {String} bottom Bottom side value.\n * @property {String} left Left side value.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/element\n */\n\nimport Node from './node';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport Matcher from './matcher';\nimport StylesMap from './stylesmap';\n\n// @if CK_DEBUG_ENGINE // const { convertMapToTags } = require( '../dev-utils/utils' );\n\n/**\n * View element.\n *\n * The editing engine does not define a fixed semantics of its elements (it is \"DTD-free\").\n * This is why the type of the {@link module:engine/view/element~Element} need to\n * be defined by the feature developer. When creating an element you should use one of the following methods:\n *\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement `downcastWriter#createContainerElement()`}\n * in order to create a {@link module:engine/view/containerelement~ContainerElement},\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement `downcastWriter#createAttributeElement()`}\n * in order to create a {@link module:engine/view/attributeelement~AttributeElement},\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement `downcastWriter#createEmptyElement()`}\n * in order to create a {@link module:engine/view/emptyelement~EmptyElement}.\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`}\n * in order to create a {@link module:engine/view/uielement~UIElement}.\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createEditableElement `downcastWriter#createEditableElement()`}\n * in order to create a {@link module:engine/view/editableelement~EditableElement}.\n *\n * Note that for view elements which are not created from the model, like elements from mutations, paste or\n * {@link module:engine/controller/datacontroller~DataController#set data.set} it is not possible to define the type of the element.\n * In such cases the {@link module:engine/view/upcastwriter~UpcastWriter#createElement `UpcastWriter#createElement()`} method\n * should be used to create generic view elements.\n *\n * @extends module:engine/view/node~Node\n */\nexport default class Element extends Node {\n\t/**\n\t * Creates a view element.\n\t *\n\t * Attributes can be passed in various formats:\n\t *\n\t *\t\tnew Element( 'div', { class: 'editor', contentEditable: 'true' } ); // object\n\t *\t\tnew Element( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator\n\t *\t\tnew Element( 'div', mapOfAttributes ); // map\n\t *\n\t * @protected\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( name, attrs, children ) {\n\t\tsuper();\n\n\t\t/**\n\t\t * Name of the element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Map of attributes, where attributes names are keys and attributes values are values.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map} #_attrs\n\t\t */\n\t\tthis._attrs = parseAttributes( attrs );\n\n\t\t/**\n\t\t * Array of child nodes.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.<module:engine/view/node~Node>}\n\t\t */\n\t\tthis._children = [];\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\n\t\t/**\n\t\t * Set of classes associated with element instance.\n\t\t *\n\t\t * @protected\n\t\t * @member {Set}\n\t\t */\n\t\tthis._classes = new Set();\n\n\t\tif ( this._attrs.has( 'class' ) ) {\n\t\t\t// Remove class attribute and handle it by class set.\n\t\t\tconst classString = this._attrs.get( 'class' );\n\t\t\tparseClasses( this._classes, classString );\n\t\t\tthis._attrs.delete( 'class' );\n\t\t}\n\n\t\t/**\n\t\t * Normalized styles.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:engine/view/stylesmap~StylesMap} module:engine/view/element~Element#_styles\n\t\t */\n\t\tthis._styles = new StylesMap();\n\n\t\tif ( this._attrs.has( 'style' ) ) {\n\t\t\t// Remove style attribute and handle it by styles map.\n\t\t\tthis._styles.setTo( this._attrs.get( 'style' ) );\n\n\t\t\tthis._attrs.delete( 'style' );\n\t\t}\n\n\t\t/**\n\t\t * Map of custom properties.\n\t\t * Custom properties can be added to element instance, will be cloned but not rendered into DOM.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map}\n\t\t */\n\t\tthis._customProperties = new Map();\n\t}\n\n\t/**\n\t * Number of element's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this element, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this._children.length === 0;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\telement.is( 'element' ); // -> true\n\t *\t\telement.is( 'node' ); // -> true\n\t *\t\telement.is( 'view:element' ); // -> true\n\t *\t\telement.is( 'view:node' ); // -> true\n\t *\n\t *\t\telement.is( 'model:element' ); // -> false\n\t *\t\telement.is( 'documentSelection' ); // -> false\n\t *\n\t * Assuming that the object being checked is an element, you can also check its\n\t * {@link module:engine/view/element~Element#name name}:\n\t *\n\t *\t\telement.is( 'img' ); // -> true if this is an <img> element\n\t *\t\telement.is( 'element', 'img' ); // -> same as above\n\t *\t\ttext.is( 'img' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check when `name` parameter is present.\n\t * Otherwise, it acts like the `name` parameter.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tconst cutType = type.replace( /^view:/, '' );\n\t\tif ( !name ) {\n\t\t\treturn cutType == 'element' || cutType == this.name || super.is( type );\n\t\t} else {\n\t\t\treturn cutType == 'element' && name == this.name;\n\t\t}\n\t}\n\n\t/**\n\t * Gets child at the given index.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/view/node~Node} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children[ index ];\n\t}\n\n\t/**\n\t * Gets index of the given child node. Returns `-1` if child node is not found.\n\t *\n\t * @param {module:engine/view/node~Node} node Child node.\n\t * @returns {Number} Index of the child node.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.indexOf( node );\n\t}\n\n\t/**\n\t * Gets child nodes iterator.\n\t *\n\t * @returns {Iterable.<module:engine/view/node~Node>} Child nodes iterator.\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns an iterator that contains the keys for attributes. Order of inserting attributes is not preserved.\n\t *\n\t * @returns {Iterable.<String>} Keys for attributes.\n\t */\n\t* getAttributeKeys() {\n\t\tif ( this._classes.size > 0 ) {\n\t\t\tyield 'class';\n\t\t}\n\n\t\tif ( !this._styles.isEmpty ) {\n\t\t\tyield 'style';\n\t\t}\n\n\t\tyield* this._attrs.keys();\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this element's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\t* getAttributes() {\n\t\tyield* this._attrs.entries();\n\n\t\tif ( this._classes.size > 0 ) {\n\t\t\tyield [ 'class', this.getAttribute( 'class' ) ];\n\t\t}\n\n\t\tif ( !this._styles.isEmpty ) {\n\t\t\tyield [ 'style', this.getAttribute( 'style' ) ];\n\t\t}\n\t}\n\n\t/**\n\t * Gets attribute by key. If attribute is not present - returns undefined.\n\t *\n\t * @param {String} key Attribute key.\n\t * @returns {String|undefined} Attribute value.\n\t */\n\tgetAttribute( key ) {\n\t\tif ( key == 'class' ) {\n\t\t\tif ( this._classes.size > 0 ) {\n\t\t\t\treturn [ ...this._classes ].join( ' ' );\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif ( key == 'style' ) {\n\t\t\tconst inlineStyle = this._styles.toString();\n\n\t\t\treturn inlineStyle == '' ? undefined : inlineStyle;\n\t\t}\n\n\t\treturn this._attrs.get( key );\n\t}\n\n\t/**\n\t * Returns a boolean indicating whether an attribute with the specified key exists in the element.\n\t *\n\t * @param {String} key Attribute key.\n\t * @returns {Boolean} `true` if attribute with the specified key exists in the element, false otherwise.\n\t */\n\thasAttribute( key ) {\n\t\tif ( key == 'class' ) {\n\t\t\treturn this._classes.size > 0;\n\t\t}\n\n\t\tif ( key == 'style' ) {\n\t\t\treturn !this._styles.isEmpty;\n\t\t}\n\n\t\treturn this._attrs.has( key );\n\t}\n\n\t/**\n\t * Checks if this element is similar to other element.\n\t * Both elements should have the same name and attributes to be considered as similar. Two similar elements\n\t * can contain different set of children nodes.\n\t *\n\t * @param {module:engine/view/element~Element} otherElement\n\t * @returns {Boolean}\n\t */\n\tisSimilar( otherElement ) {\n\t\tif ( !( otherElement instanceof Element ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If exactly the same Element is provided - return true immediately.\n\t\tif ( this === otherElement ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check element name.\n\t\tif ( this.name != otherElement.name ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check number of attributes, classes and styles.\n\t\tif ( this._attrs.size !== otherElement._attrs.size || this._classes.size !== otherElement._classes.size ||\n\t\t\tthis._styles.size !== otherElement._styles.size ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if attributes are the same.\n\t\tfor ( const [ key, value ] of this._attrs ) {\n\t\t\tif ( !otherElement._attrs.has( key ) || otherElement._attrs.get( key ) !== value ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if classes are the same.\n\t\tfor ( const className of this._classes ) {\n\t\t\tif ( !otherElement._classes.has( className ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if styles are the same.\n\t\tfor ( const property of this._styles.getStyleNames() ) {\n\t\t\tif (\n\t\t\t\t!otherElement._styles.has( property ) ||\n\t\t\t\totherElement._styles.getAsString( property ) !== this._styles.getAsString( property )\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns true if class is present.\n\t * If more then one class is provided - returns true only when all classes are present.\n\t *\n\t *\t\telement.hasClass( 'foo' ); // Returns true if 'foo' class is present.\n\t *\t\telement.hasClass( 'foo', 'bar' ); // Returns true if 'foo' and 'bar' classes are both present.\n\t *\n\t * @param {...String} className\n\t */\n\thasClass( ...className ) {\n\t\tfor ( const name of className ) {\n\t\t\tif ( !this._classes.has( name ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns iterator that contains all class names.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetClassNames() {\n\t\treturn this._classes.keys();\n\t}\n\n\t/**\n\t * Returns style value for the given property mae.\n\t * If the style does not exist `undefined` is returned.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#getAsString `StylesMap#getAsString()`} for details.\n\t *\n\t * For an element with style set to `'margin:1px'`:\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.editing.view.document.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tconst element = view.change( writer => {\n\t *\t\t\tconst element = writer.createElement();\n\t *\t\t\twriter.setStyle( 'margin', '1px' );\n\t *\t\t\twriter.setStyle( 'margin-bottom', '3em' );\n\t *\n\t *\t\t\treturn element;\n\t *\t\t} );\n\t *\n\t *\t\telement.getStyle( 'margin' ); // -> 'margin: 1px 1px 3em;'\n\t *\n\t * @param {String} property\n\t * @returns {String|undefined}\n\t */\n\tgetStyle( property ) {\n\t\treturn this._styles.getAsString( property );\n\t}\n\n\t/**\n\t * Returns a normalized style object or single style value.\n\t *\n\t * For an element with style set to: margin:1px 2px 3em;\n\t *\n\t *\t\telement.getNormalizedStyle( 'margin' ) );\n\t *\n\t * will return:\n\t *\n\t *\t\t{\n\t *\t\t\ttop: '1px',\n\t *\t\t\tright: '2px',\n\t *\t\t\tbottom: '3em',\n\t *\t\t\tleft: '2px' // a normalized value from margin shorthand\n\t *\t\t}\n\t *\n\t * and reading for single style value:\n\t *\n\t *\t\tstyles.getNormalizedStyle( 'margin-left' );\n\t *\n\t * Will return a `2px` string.\n\t *\n\t * **Note**: This method will return normalized values only if\n\t * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#getNormalized `StylesMap#getNormalized()`} for details.\n\t *\n\t *\n\t * @param {String} property Name of CSS property\n\t * @returns {Object|String|undefined}\n\t */\n\tgetNormalizedStyle( property ) {\n\t\treturn this._styles.getNormalized( property );\n\t}\n\n\t/**\n\t * Returns iterator that contains all style names.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetStyleNames() {\n\t\treturn this._styles.getStyleNames();\n\t}\n\n\t/**\n\t * Returns true if style keys are present.\n\t * If more then one style property is provided - returns true only when all properties are present.\n\t *\n\t *\t\telement.hasStyle( 'color' ); // Returns true if 'border-top' style is present.\n\t *\t\telement.hasStyle( 'color', 'border-top' ); // Returns true if 'color' and 'border-top' styles are both present.\n\t *\n\t * @param {...String} property\n\t */\n\thasStyle( ...property ) {\n\t\tfor ( const name of property ) {\n\t\t\tif ( !this._styles.has( name ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns ancestor element that match specified pattern.\n\t * Provided patterns should be compatible with {@link module:engine/view/matcher~Matcher Matcher} as it is used internally.\n\t *\n\t * @see module:engine/view/matcher~Matcher\n\t * @param {Object|String|RegExp|Function} patterns Patterns used to match correct ancestor.\n\t * See {@link module:engine/view/matcher~Matcher}.\n\t * @returns {module:engine/view/element~Element|null} Found element or `null` if no matching ancestor was found.\n\t */\n\tfindAncestor( ...patterns ) {\n\t\tconst matcher = new Matcher( ...patterns );\n\t\tlet parent = this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tif ( matcher.match( parent ) ) {\n\t\t\t\treturn parent;\n\t\t\t}\n\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the custom property value for the given key.\n\t *\n\t * @param {String|Symbol} key\n\t * @returns {*}\n\t */\n\tgetCustomProperty( key ) {\n\t\treturn this._customProperties.get( key );\n\t}\n\n\t/**\n\t * Returns an iterator which iterates over this element's custom properties.\n\t * Iterator provides `[ key, value ]` pairs for each stored property.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\t* getCustomProperties() {\n\t\tyield* this._customProperties.entries();\n\t}\n\n\t/**\n\t * Returns identity string based on element's name, styles, classes and other attributes.\n\t * Two elements that {@link #isSimilar are similar} will have same identity string.\n\t * It has the following format:\n\t *\n\t *\t\t'name class=\"class1,class2\" style=\"style1:value1;style2:value2\" attr1=\"val1\" attr2=\"val2\"'\n \t *\n\t * For example:\n\t *\n\t *\t\tconst element = writer.createContainerElement( 'foo', {\n\t *\t\t\tbanana: '10',\n\t *\t\t\tapple: '20',\n\t *\t\t\tstyle: 'color: red; border-color: white;',\n\t *\t\t\tclass: 'baz'\n\t *\t\t} );\n\t *\n\t *\t\t// returns 'foo class=\"baz\" style=\"border-color:white;color:red\" apple=\"20\" banana=\"10\"'\n\t *\t\telement.getIdentity();\n\t *\n\t * **Note**: Classes, styles and other attributes are sorted alphabetically.\n\t *\n\t * @returns {String}\n\t */\n\tgetIdentity() {\n\t\tconst classes = Array.from( this._classes ).sort().join( ',' );\n\t\tconst styles = this._styles.toString();\n\t\tconst attributes = Array.from( this._attrs ).map( i => `${ i[ 0 ] }=\"${ i[ 1 ] }\"` ).sort().join( ' ' );\n\n\t\treturn this.name +\n\t\t\t( classes == '' ? '' : ` class=\"${ classes }\"` ) +\n\t\t\t( !styles ? '' : ` style=\"${ styles }\"` ) +\n\t\t\t( attributes == '' ? '' : ` ${ attributes }` );\n\t}\n\n\t/**\n\t * Clones provided element.\n\t *\n\t * @protected\n\t * @param {Boolean} [deep=false] If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any children.\n\t * @returns {module:engine/view/element~Element} Clone of this element.\n\t */\n\t_clone( deep = false ) {\n\t\tconst childrenClone = [];\n\n\t\tif ( deep ) {\n\t\t\tfor ( const child of this.getChildren() ) {\n\t\t\t\tchildrenClone.push( child._clone( deep ) );\n\t\t\t}\n\t\t}\n\n\t\t// ContainerElement and AttributeElement should be also cloned properly.\n\t\tconst cloned = new this.constructor( this.name, this._attrs, childrenClone );\n\n\t\t// Classes and styles are cloned separately - this solution is faster than adding them back to attributes and\n\t\t// parse once again in constructor.\n\t\tcloned._classes = new Set( this._classes );\n\t\tcloned._styles.set( this._styles.getNormalized() );\n\n\t\t// Clone custom properties.\n\t\tcloned._customProperties = new Map( this._customProperties );\n\n\t\t// Clone filler offset method.\n\t\t// We can't define this method in a prototype because it's behavior which\n\t\t// is changed by e.g. toWidget() function from ckeditor5-widget. Perhaps this should be one of custom props.\n\t\tcloned.getFillerOffset = this.getFillerOffset;\n\n\t\treturn cloned;\n\t}\n\n\t/**\n\t * {@link module:engine/view/element~Element#_insertChild Insert} a child node or a list of child nodes at the end of this node\n\t * and sets the parent of these nodes to this element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#insert\n\t * @protected\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @fires module:engine/view/node~Node#change\n\t * @returns {Number} Number of appended nodes.\n\t */\n\t_appendChild( items ) {\n\t\treturn this._insertChild( this.childCount, items );\n\t}\n\n\t/**\n\t * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to\n\t * this element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#insert\n\t * @protected\n\t * @param {Number} index Position where nodes should be inserted.\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @fires module:engine/view/node~Node#change\n\t * @returns {Number} Number of inserted nodes.\n\t */\n\t_insertChild( index, items ) {\n\t\tthis._fireChange( 'children', this );\n\t\tlet count = 0;\n\n\t\tconst nodes = normalize( items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\n\t\t\tthis._children.splice( index, 0, node );\n\t\t\tindex++;\n\t\t\tcount++;\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/**\n\t * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#remove\n\t * @protected\n\t * @param {Number} index Number of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @fires module:engine/view/node~Node#change\n\t * @returns {Array.<module:engine/view/node~Node>} The array of removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tthis._fireChange( 'children', this );\n\n\t\tfor ( let i = index; i < index + howMany; i++ ) {\n\t\t\tthis._children[ i ].parent = null;\n\t\t}\n\n\t\treturn this._children.splice( index, howMany );\n\t}\n\n\t/**\n\t * Adds or overwrite attribute with a specified key and value.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#setAttribute\n\t * @protected\n\t * @param {String} key Attribute key.\n\t * @param {String} value Attribute value.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_setAttribute( key, value ) {\n\t\tvalue = String( value );\n\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tif ( key == 'class' ) {\n\t\t\tparseClasses( this._classes, value );\n\t\t} else if ( key == 'style' ) {\n\t\t\tthis._styles.setTo( value );\n\t\t} else {\n\t\t\tthis._attrs.set( key, value );\n\t\t}\n\t}\n\n\t/**\n\t * Removes attribute from the element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#removeAttribute\n\t * @protected\n\t * @param {String} key Attribute key.\n\t * @returns {Boolean} Returns true if an attribute existed and has been removed.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_removeAttribute( key ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\t// Remove class attribute.\n\t\tif ( key == 'class' ) {\n\t\t\tif ( this._classes.size > 0 ) {\n\t\t\t\tthis._classes.clear();\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\t// Remove style attribute.\n\t\tif ( key == 'style' ) {\n\t\t\tif ( !this._styles.isEmpty ) {\n\t\t\t\tthis._styles.clear();\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\t// Remove other attributes.\n\t\treturn this._attrs.delete( key );\n\t}\n\n\t/**\n\t * Adds specified class.\n\t *\n\t *\t\telement._addClass( 'foo' ); // Adds 'foo' class.\n\t *\t\telement._addClass( [ 'foo', 'bar' ] ); // Adds 'foo' and 'bar' classes.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#addClass\n\t * @protected\n\t * @param {Array.<String>|String} className\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_addClass( className ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tclassName = Array.isArray( className ) ? className : [ className ];\n\t\tclassName.forEach( name => this._classes.add( name ) );\n\t}\n\n\t/**\n\t * Removes specified class.\n\t *\n\t *\t\telement._removeClass( 'foo' ); // Removes 'foo' class.\n\t *\t\telement._removeClass( [ 'foo', 'bar' ] ); // Removes both 'foo' and 'bar' classes.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#removeClass\n\t * @protected\n\t * @param {Array.<String>|String} className\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_removeClass( className ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tclassName = Array.isArray( className ) ? className : [ className ];\n\t\tclassName.forEach( name => this._classes.delete( name ) );\n\t}\n\n\t/**\n\t * Adds style to the element.\n\t *\n\t *\t\telement._setStyle( 'color', 'red' );\n\t *\t\telement._setStyle( {\n\t *\t\t\tcolor: 'red',\n\t *\t\t\tposition: 'fixed'\n\t *\t\t} );\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#setStyle\n\t * @protected\n\t * @param {String|Object} property Property name or object with key - value pairs.\n\t * @param {String} [value] Value to set. This parameter is ignored if object is provided as the first parameter.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_setStyle( property, value ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tthis._styles.set( property, value );\n\t}\n\n\t/**\n\t * Removes specified style.\n\t *\n\t *\t\telement._removeStyle( 'color' ); // Removes 'color' style.\n\t *\t\telement._removeStyle( [ 'color', 'border-top' ] ); // Removes both 'color' and 'border-top' styles.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#removeStyle\n\t * @protected\n\t * @param {Array.<String>|String} property\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_removeStyle( property ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tproperty = Array.isArray( property ) ? property : [ property ];\n\t\tproperty.forEach( name => this._styles.remove( name ) );\n\t}\n\n\t/**\n\t * Sets a custom property. Unlike attributes, custom properties are not rendered to the DOM,\n\t * so they can be used to add special data to elements.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#setCustomProperty\n\t * @protected\n\t * @param {String|Symbol} key\n\t * @param {*} value\n\t */\n\t_setCustomProperty( key, value ) {\n\t\tthis._customProperties.set( key, value );\n\t}\n\n\t/**\n\t * Removes the custom property stored under the given key.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#removeCustomProperty\n\t * @protected\n\t * @param {String|Symbol} key\n\t * @returns {Boolean} Returns true if property was removed.\n\t */\n\t_removeCustomProperty( key ) {\n\t\treturn this._customProperties.delete( key );\n\t}\n\n\t/**\n\t * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n\t *\n\t * @abstract\n\t * @method module:engine/view/element~Element#getFillerOffset\n\t */\n\n\t// @if CK_DEBUG_ENGINE // printTree( level = 0) {\n\t// @if CK_DEBUG_ENGINE // \tlet string = '';\n\n\t// @if CK_DEBUG_ENGINE //\tstring += '\\t'.repeat( level ) + `<${ this.name }${ convertMapToTags( this.getAttributes() ) }>`;\n\n\t// @if CK_DEBUG_ENGINE //\tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE //\t\tif ( child.is( 'text' ) ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + '\\t'.repeat( level + 1 ) + child.data;\n\t// @if CK_DEBUG_ENGINE //\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + child.printTree( level + 1 );\n\t// @if CK_DEBUG_ENGINE //\t\t}\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tif ( this.childCount ) {\n\t// @if CK_DEBUG_ENGINE //\t\tstring += '\\n' + '\\t'.repeat( level );\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tstring += `</${ this.name }>`;\n\n\t// @if CK_DEBUG_ENGINE //\treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n// Parses attributes provided to the element constructor before they are applied to an element. If attributes are passed\n// as an object (instead of `Iterable`), the object is transformed to the map. Attributes with `null` value are removed.\n// Attributes with non-`String` value are converted to `String`.\n//\n// @param {Object|Iterable} attrs Attributes to parse.\n// @returns {Map} Parsed attributes.\nfunction parseAttributes( attrs ) {\n\tattrs = toMap( attrs );\n\n\tfor ( const [ key, value ] of attrs ) {\n\t\tif ( value === null ) {\n\t\t\tattrs.delete( key );\n\t\t} else if ( typeof value != 'string' ) {\n\t\t\tattrs.set( key, String( value ) );\n\t\t}\n\t}\n\n\treturn attrs;\n}\n\n// Parses class attribute and puts all classes into classes set.\n// Classes set s cleared before insertion.\n//\n// @param {Set.<String>} classesSet Set to insert parsed classes.\n// @param {String} classesString String with classes to parse.\nfunction parseClasses( classesSet, classesString ) {\n\tconst classArray = classesString.split( /\\s+/ );\n\tclassesSet.clear();\n\tclassArray.forEach( name => classesSet.add( name ) );\n}\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/view/item~Item|Iterable.<String|module:engine/view/item~Item>}\n// @returns {Iterable.<module:engine/view/node~Node>}\nfunction normalize( nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( node.data );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/containerelement\n */\n\nimport Element from './element';\n\n/**\n * Containers are elements which define document structure. They define boundaries for\n * {@link module:engine/view/attributeelement~AttributeElement attributes}. They are mostly used for block elements like `<p>` or `<div>`.\n *\n * Editing engine does not define a fixed HTML DTD. This is why a feature developer needs to choose between various\n * types (container element, {@link module:engine/view/attributeelement~AttributeElement attribute element},\n * {@link module:engine/view/emptyelement~EmptyElement empty element}, etc) when developing a feature.\n *\n * The container element should be your default choice when writing a converter, unless:\n *\n * * this element represents a model text attribute (then use {@link module:engine/view/attributeelement~AttributeElement}),\n * * this is an empty element like `<img>` (then use {@link module:engine/view/emptyelement~EmptyElement}),\n * * this is a root element,\n * * this is a nested editable element (then use {@link module:engine/view/editableelement~EditableElement}).\n *\n * To create a new container element instance use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement `DowncastWriter#createContainerElement()`}\n * method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class ContainerElement extends Element {\n\t/**\n\t * Creates a container element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createContainerElement\n\t * @see module:engine/view/element~Element\n\t * @protected\n\t */\n\tconstructor( name, attrs, children ) {\n\t\tsuper( name, attrs, children );\n\n\t\t/**\n\t\t * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {Number|null} Block filler offset or `null` if block filler is not needed.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tcontainerElement.is( 'containerElement' ); // -> true\n\t *\t\tcontainerElement.is( 'element' ); // -> true\n\t *\t\tcontainerElement.is( 'node' ); // -> true\n\t *\t\tcontainerElement.is( 'view:containerElement' ); // -> true\n\t *\t\tcontainerElement.is( 'view:element' ); // -> true\n\t *\t\tcontainerElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\tcontainerElement.is( 'model:element' ); // -> false\n\t *\t\tcontainerElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is a container element, you can also check its\n\t * {@link module:engine/view/containerelement~ContainerElement#name name}:\n\t *\n\t *\t\tcontainerElement.is( 'div' ); // -> true if this is a div container element\n\t *\t\tcontainerElement.is( 'contaienrElement', 'div' ); // -> same as above\n\t *\t\ttext.is( 'div' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check when `name` parameter is present.\n\t * Otherwise, it acts like the `name` parameter.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tconst cutType = type && type.replace( /^view:/, '' );\n\t\tif ( !name ) {\n\t\t\treturn cutType == 'containerElement' || super.is( type );\n\t\t} else {\n\t\t\treturn ( cutType == 'containerElement' && name == this.name ) || super.is( type, name );\n\t\t}\n\t}\n}\n\n/**\n * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n *\n * @returns {Number|null} Block filler offset or `null` if block filler is not needed.\n */\nexport function getFillerOffset() {\n\tconst children = [ ...this.getChildren() ];\n\tconst lastChild = children[ this.childCount - 1 ];\n\n\t// Block filler is required after a `<br>` if it's the last element in its container. See #1422.\n\tif ( lastChild && lastChild.is( 'element', 'br' ) ) {\n\t\treturn this.childCount;\n\t}\n\n\tfor ( const child of children ) {\n\t\t// If there's any non-UI element – don't render the bogus.\n\t\tif ( !child.is( 'uiElement' ) ) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// If there are only UI elements – render the bogus at the end of the element.\n\treturn this.childCount;\n}\n","import copyObject from './_copyObject.js';\nimport createAssigner from './_createAssigner.js';\nimport keysIn from './keysIn.js';\n\n/**\n * This method is like `_.assign` except that it iterates over own and\n * inherited source properties.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @alias extend\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @see _.assign\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * function Bar() {\n * this.c = 3;\n * }\n *\n * Foo.prototype.b = 2;\n * Bar.prototype.d = 4;\n *\n * _.assignIn({ 'a': 0 }, new Foo, new Bar);\n * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }\n */\nvar assignIn = createAssigner(function(object, source) {\n copyObject(source, keysIn(source), object);\n});\n\nexport default assignIn;\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/observablemixin\n */\n\nimport EmitterMixin from './emittermixin';\nimport CKEditorError from './ckeditorerror';\nimport { extend, isObject } from 'lodash-es';\n\nconst observablePropertiesSymbol = Symbol( 'observableProperties' );\nconst boundObservablesSymbol = Symbol( 'boundObservables' );\nconst boundPropertiesSymbol = Symbol( 'boundProperties' );\n\n/**\n * Mixin that injects the \"observable properties\" and data binding functionality described in the\n * {@link ~Observable} interface.\n *\n * Read more about the concept of observables in the:\n * * {@glink framework/guides/architecture/core-editor-architecture#event-system-and-observables \"Event system and observables\"}\n * section of the {@glink framework/guides/architecture/core-editor-architecture \"Core editor architecture\"} guide,\n * * {@glink framework/guides/deep-dive/observables \"Observables\" deep dive} guide.\n *\n * @mixin ObservableMixin\n * @mixes module:utils/emittermixin~EmitterMixin\n * @implements module:utils/observablemixin~Observable\n */\nconst ObservableMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\tset( name, value ) {\n\t\t// If the first parameter is an Object, iterate over its properties.\n\t\tif ( isObject( name ) ) {\n\t\t\tObject.keys( name ).forEach( property => {\n\t\t\t\tthis.set( property, name[ property ] );\n\t\t\t}, this );\n\n\t\t\treturn;\n\t\t}\n\n\t\tinitObservable( this );\n\n\t\tconst properties = this[ observablePropertiesSymbol ];\n\n\t\tif ( ( name in this ) && !properties.has( name ) ) {\n\t\t\t/**\n\t\t\t * Cannot override an existing property.\n\t\t\t *\n\t\t\t * This error is thrown when trying to {@link ~Observable#set set} an property with\n\t\t\t * a name of an already existing property. For example:\n\t\t\t *\n\t\t\t *\t\tlet observable = new Model();\n\t\t\t *\t\tobservable.property = 1;\n\t\t\t *\t\tobservable.set( 'property', 2 );\t\t\t// throws\n\t\t\t *\n\t\t\t *\t\tobservable.set( 'property', 1 );\n\t\t\t *\t\tobservable.set( 'property', 2 );\t\t\t// ok, because this is an existing property.\n\t\t\t *\n\t\t\t * @error observable-set-cannot-override\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'observable-set-cannot-override: Cannot override an existing property.', this );\n\t\t}\n\n\t\tObject.defineProperty( this, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget() {\n\t\t\t\treturn properties.get( name );\n\t\t\t},\n\n\t\t\tset( value ) {\n\t\t\t\tconst oldValue = properties.get( name );\n\n\t\t\t\t// Fire `set` event before the new value will be set to make it possible\n\t\t\t\t// to override observable property without affecting `change` event.\n\t\t\t\t// See https://github.com/ckeditor/ckeditor5-utils/issues/171.\n\t\t\t\tlet newValue = this.fire( 'set:' + name, name, value, oldValue );\n\n\t\t\t\tif ( newValue === undefined ) {\n\t\t\t\t\tnewValue = value;\n\t\t\t\t}\n\n\t\t\t\t// Allow undefined as an initial value like A.define( 'x', undefined ) (#132).\n\t\t\t\t// Note: When properties map has no such own property, then its value is undefined.\n\t\t\t\tif ( oldValue !== newValue || !properties.has( name ) ) {\n\t\t\t\t\tproperties.set( name, newValue );\n\t\t\t\t\tthis.fire( 'change:' + name, name, newValue, oldValue );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\tthis[ name ] = value;\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tbind( ...bindProperties ) {\n\t\tif ( !bindProperties.length || !isStringArray( bindProperties ) ) {\n\t\t\t/**\n\t\t\t * All properties must be strings.\n\t\t\t *\n\t\t\t * @error observable-bind-wrong-properties\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'observable-bind-wrong-properties: All properties must be strings.', this );\n\t\t}\n\n\t\tif ( ( new Set( bindProperties ) ).size !== bindProperties.length ) {\n\t\t\t/**\n\t\t\t * Properties must be unique.\n\t\t\t *\n\t\t\t * @error observable-bind-duplicate-properties\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'observable-bind-duplicate-properties: Properties must be unique.', this );\n\t\t}\n\n\t\tinitObservable( this );\n\n\t\tconst boundProperties = this[ boundPropertiesSymbol ];\n\n\t\tbindProperties.forEach( propertyName => {\n\t\t\tif ( boundProperties.has( propertyName ) ) {\n\t\t\t\t/**\n\t\t\t\t * Cannot bind the same property more than once.\n\t\t\t\t *\n\t\t\t\t * @error observable-bind-rebind\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'observable-bind-rebind: Cannot bind the same property more than once.', this );\n\t\t\t}\n\t\t} );\n\n\t\tconst bindings = new Map();\n\n\t\t// @typedef {Object} Binding\n\t\t// @property {Array} property Property which is bound.\n\t\t// @property {Array} to Array of observable–property components of the binding (`{ observable: ..., property: .. }`).\n\t\t// @property {Array} callback A function which processes `to` components.\n\t\tbindProperties.forEach( a => {\n\t\t\tconst binding = { property: a, to: [] };\n\n\t\t\tboundProperties.set( a, binding );\n\t\t\tbindings.set( a, binding );\n\t\t} );\n\n\t\t// @typedef {Object} BindChain\n\t\t// @property {Function} to See {@link ~ObservableMixin#_bindTo}.\n\t\t// @property {Function} toMany See {@link ~ObservableMixin#_bindToMany}.\n\t\t// @property {module:utils/observablemixin~Observable} _observable The observable which initializes the binding.\n\t\t// @property {Array} _bindProperties Array of `_observable` properties to be bound.\n\t\t// @property {Array} _to Array of `to()` observable–properties (`{ observable: toObservable, properties: ...toProperties }`).\n\t\t// @property {Map} _bindings Stores bindings to be kept in\n\t\t// {@link ~ObservableMixin#_boundProperties}/{@link ~ObservableMixin#_boundObservables}\n\t\t// initiated in this binding chain.\n\t\treturn {\n\t\t\tto: bindTo,\n\t\t\ttoMany: bindToMany,\n\n\t\t\t_observable: this,\n\t\t\t_bindProperties: bindProperties,\n\t\t\t_to: [],\n\t\t\t_bindings: bindings\n\t\t};\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tunbind( ...unbindProperties ) {\n\t\t// Nothing to do here if not inited yet.\n\t\tif ( !( observablePropertiesSymbol in this ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst boundProperties = this[ boundPropertiesSymbol ];\n\t\tconst boundObservables = this[ boundObservablesSymbol ];\n\n\t\tif ( unbindProperties.length ) {\n\t\t\tif ( !isStringArray( unbindProperties ) ) {\n\t\t\t\t/**\n\t\t\t\t * Properties must be strings.\n\t\t\t\t *\n\t\t\t\t * @error observable-unbind-wrong-properties\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'observable-unbind-wrong-properties: Properties must be strings.', this );\n\t\t\t}\n\n\t\t\tunbindProperties.forEach( propertyName => {\n\t\t\t\tconst binding = boundProperties.get( propertyName );\n\n\t\t\t\t// Nothing to do if the binding is not defined\n\t\t\t\tif ( !binding ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet toObservable, toProperty, toProperties, toPropertyBindings;\n\n\t\t\t\tbinding.to.forEach( to => {\n\t\t\t\t\t// TODO: ES6 destructuring.\n\t\t\t\t\ttoObservable = to[ 0 ];\n\t\t\t\t\ttoProperty = to[ 1 ];\n\t\t\t\t\ttoProperties = boundObservables.get( toObservable );\n\t\t\t\t\ttoPropertyBindings = toProperties[ toProperty ];\n\n\t\t\t\t\ttoPropertyBindings.delete( binding );\n\n\t\t\t\t\tif ( !toPropertyBindings.size ) {\n\t\t\t\t\t\tdelete toProperties[ toProperty ];\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( !Object.keys( toProperties ).length ) {\n\t\t\t\t\t\tboundObservables.delete( toObservable );\n\t\t\t\t\t\tthis.stopListening( toObservable, 'change' );\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\tboundProperties.delete( propertyName );\n\t\t\t} );\n\t\t} else {\n\t\t\tboundObservables.forEach( ( bindings, boundObservable ) => {\n\t\t\t\tthis.stopListening( boundObservable, 'change' );\n\t\t\t} );\n\n\t\t\tboundObservables.clear();\n\t\t\tboundProperties.clear();\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdecorate( methodName ) {\n\t\tconst originalMethod = this[ methodName ];\n\n\t\tif ( !originalMethod ) {\n\t\t\t/**\n\t\t\t * Cannot decorate an undefined method.\n\t\t\t *\n\t\t\t * @error observablemixin-cannot-decorate-undefined\n\t\t\t * @param {Object} object The object which method should be decorated.\n\t\t\t * @param {String} methodName Name of the method which does not exist.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'observablemixin-cannot-decorate-undefined: Cannot decorate an undefined method.',\n\t\t\t\tthis,\n\t\t\t\t{ object: this, methodName }\n\t\t\t);\n\t\t}\n\n\t\tthis.on( methodName, ( evt, args ) => {\n\t\t\tevt.return = originalMethod.apply( this, args );\n\t\t} );\n\n\t\tthis[ methodName ] = function( ...args ) {\n\t\t\treturn this.fire( methodName, args );\n\t\t};\n\t}\n};\n\nextend( ObservableMixin, EmitterMixin );\n\nexport default ObservableMixin;\n\n// Init symbol properties needed to for the observable mechanism to work.\n//\n// @private\n// @param {module:utils/observablemixin~ObservableMixin} observable\nfunction initObservable( observable ) {\n\t// Do nothing if already inited.\n\tif ( observablePropertiesSymbol in observable ) {\n\t\treturn;\n\t}\n\n\t// The internal hash containing the observable's state.\n\t//\n\t// @private\n\t// @type {Map}\n\tObject.defineProperty( observable, observablePropertiesSymbol, {\n\t\tvalue: new Map()\n\t} );\n\n\t// Map containing bindings to external observables. It shares the binding objects\n\t// (`{ observable: A, property: 'a', to: ... }`) with {@link module:utils/observablemixin~ObservableMixin#_boundProperties} and\n\t// it is used to observe external observables to update own properties accordingly.\n\t// See {@link module:utils/observablemixin~ObservableMixin#bind}.\n\t//\n\t//\t\tA.bind( 'a', 'b', 'c' ).to( B, 'x', 'y', 'x' );\n\t//\t\tconsole.log( A._boundObservables );\n\t//\n\t//\t\t\tMap( {\n\t//\t\t\t\tB: {\n\t//\t\t\t\t\tx: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'a', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\t\t\t{ observable: A, property: 'c', to: [ [ B, 'x' ] ] }\n\t//\t\t\t\t\t] ),\n\t//\t\t\t\t\ty: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n\t//\t\t\t\t\t] )\n\t//\t\t\t\t}\n\t//\t\t\t} )\n\t//\n\t//\t\tA.bind( 'd' ).to( B, 'z' ).to( C, 'w' ).as( callback );\n\t//\t\tconsole.log( A._boundObservables );\n\t//\n\t//\t\t\tMap( {\n\t//\t\t\t\tB: {\n\t//\t\t\t\t\tx: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'a', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\t\t\t{ observable: A, property: 'c', to: [ [ B, 'x' ] ] }\n\t//\t\t\t\t\t] ),\n\t//\t\t\t\t\ty: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n\t//\t\t\t\t\t] ),\n\t//\t\t\t\t\tz: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'd', to: [ [ B, 'z' ], [ C, 'w' ] ], callback: callback }\n\t//\t\t\t\t\t] )\n\t//\t\t\t\t},\n\t//\t\t\t\tC: {\n\t//\t\t\t\t\tw: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'd', to: [ [ B, 'z' ], [ C, 'w' ] ], callback: callback }\n\t//\t\t\t\t\t] )\n\t//\t\t\t\t}\n\t//\t\t\t} )\n\t//\n\t// @private\n\t// @type {Map}\n\tObject.defineProperty( observable, boundObservablesSymbol, {\n\t\tvalue: new Map()\n\t} );\n\n\t// Object that stores which properties of this observable are bound and how. It shares\n\t// the binding objects (`{ observable: A, property: 'a', to: ... }`) with\n\t// {@link module:utils/observablemixin~ObservableMixin#_boundObservables}. This data structure is\n\t// a reverse of {@link module:utils/observablemixin~ObservableMixin#_boundObservables} and it is helpful for\n\t// {@link module:utils/observablemixin~ObservableMixin#unbind}.\n\t//\n\t// See {@link module:utils/observablemixin~ObservableMixin#bind}.\n\t//\n\t//\t\tA.bind( 'a', 'b', 'c' ).to( B, 'x', 'y', 'x' );\n\t//\t\tconsole.log( A._boundProperties );\n\t//\n\t//\t\t\tMap( {\n\t//\t\t\t\ta: { observable: A, property: 'a', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\tb: { observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n\t//\t\t\t\tc: { observable: A, property: 'c', to: [ [ B, 'x' ] ] }\n\t//\t\t\t} )\n\t//\n\t//\t\tA.bind( 'd' ).to( B, 'z' ).to( C, 'w' ).as( callback );\n\t//\t\tconsole.log( A._boundProperties );\n\t//\n\t//\t\t\tMap( {\n\t//\t\t\t\ta: { observable: A, property: 'a', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\tb: { observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n\t//\t\t\t\tc: { observable: A, property: 'c', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\td: { observable: A, property: 'd', to: [ [ B, 'z' ], [ C, 'w' ] ], callback: callback }\n\t//\t\t\t} )\n\t//\n\t// @private\n\t// @type {Map}\n\tObject.defineProperty( observable, boundPropertiesSymbol, {\n\t\tvalue: new Map()\n\t} );\n}\n\n// A chaining for {@link module:utils/observablemixin~ObservableMixin#bind} providing `.to()` interface.\n//\n// @private\n// @param {...[Observable|String|Function]} args Arguments of the `.to( args )` binding.\nfunction bindTo( ...args ) {\n\tconst parsedArgs = parseBindToArgs( ...args );\n\tconst bindingsKeys = Array.from( this._bindings.keys() );\n\tconst numberOfBindings = bindingsKeys.length;\n\n\t// Eliminate A.bind( 'x' ).to( B, C )\n\tif ( !parsedArgs.callback && parsedArgs.to.length > 1 ) {\n\t\t/**\n\t\t * Binding multiple observables only possible with callback.\n\t\t *\n\t\t * @error observable-bind-no-callback\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'observable-bind-to-no-callback: Binding multiple observables only possible with callback.',\n\t\t\tthis\n\t\t);\n\t}\n\n\t// Eliminate A.bind( 'x', 'y' ).to( B, callback )\n\tif ( numberOfBindings > 1 && parsedArgs.callback ) {\n\t\t/**\n\t\t * Cannot bind multiple properties and use a callback in one binding.\n\t\t *\n\t\t * @error observable-bind-to-extra-callback\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'observable-bind-to-extra-callback: Cannot bind multiple properties and use a callback in one binding.',\n\t\t\tthis\n\t\t);\n\t}\n\n\tparsedArgs.to.forEach( to => {\n\t\t// Eliminate A.bind( 'x', 'y' ).to( B, 'a' )\n\t\tif ( to.properties.length && to.properties.length !== numberOfBindings ) {\n\t\t\t/**\n\t\t\t * The number of properties must match.\n\t\t\t *\n\t\t\t * @error observable-bind-to-properties-length\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'observable-bind-to-properties-length: The number of properties must match.', this );\n\t\t}\n\n\t\t// When no to.properties specified, observing source properties instead i.e.\n\t\t// A.bind( 'x', 'y' ).to( B ) -> Observe B.x and B.y\n\t\tif ( !to.properties.length ) {\n\t\t\tto.properties = this._bindProperties;\n\t\t}\n\t} );\n\n\tthis._to = parsedArgs.to;\n\n\t// Fill {@link BindChain#_bindings} with callback. When the callback is set there's only one binding.\n\tif ( parsedArgs.callback ) {\n\t\tthis._bindings.get( bindingsKeys[ 0 ] ).callback = parsedArgs.callback;\n\t}\n\n\tattachBindToListeners( this._observable, this._to );\n\n\t// Update observable._boundProperties and observable._boundObservables.\n\tupdateBindToBound( this );\n\n\t// Set initial values of bound properties.\n\tthis._bindProperties.forEach( propertyName => {\n\t\tupdateBoundObservableProperty( this._observable, propertyName );\n\t} );\n}\n\n// Binds to an attribute in a set of iterable observables.\n//\n// @private\n// @param {Array.<Observable>} observables\n// @param {String} attribute\n// @param {Function} callback\nfunction bindToMany( observables, attribute, callback ) {\n\tif ( this._bindings.size > 1 ) {\n\t\t/**\n\t\t * Binding one attribute to many observables only possible with one attribute.\n\t\t *\n\t\t * @error observable-bind-to-many-not-one-binding\n\t\t */\n\t\tthrow new CKEditorError( 'observable-bind-to-many-not-one-binding: Cannot bind multiple properties with toMany().', this );\n\t}\n\n\tthis.to(\n\t\t// Bind to #attribute of each observable...\n\t\t...getBindingTargets( observables, attribute ),\n\t\t// ...using given callback to parse attribute values.\n\t\tcallback\n\t);\n}\n\n// Returns an array of binding components for\n// {@link Observable#bind} from a set of iterable observables.\n//\n// @param {Array.<Observable>} observables\n// @param {String} attribute\n// @returns {Array.<String|Observable>}\nfunction getBindingTargets( observables, attribute ) {\n\tconst observableAndAttributePairs = observables.map( observable => [ observable, attribute ] );\n\n\t// Merge pairs to one-dimension array of observables and attributes.\n\treturn Array.prototype.concat.apply( [], observableAndAttributePairs );\n}\n\n// Check if all entries of the array are of `String` type.\n//\n// @private\n// @param {Array} arr An array to be checked.\n// @returns {Boolean}\nfunction isStringArray( arr ) {\n\treturn arr.every( a => typeof a == 'string' );\n}\n\n// Parses and validates {@link Observable#bind}`.to( args )` arguments and returns\n// an object with a parsed structure. For example\n//\n//\t\tA.bind( 'x' ).to( B, 'a', C, 'b', call );\n//\n// becomes\n//\n//\t\t{\n//\t\t\tto: [\n//\t\t\t\t{ observable: B, properties: [ 'a' ] },\n//\t\t\t\t{ observable: C, properties: [ 'b' ] },\n//\t\t\t],\n//\t\t\tcallback: call\n// \t\t}\n//\n// @private\n// @param {...*} args Arguments of {@link Observable#bind}`.to( args )`.\n// @returns {Object}\nfunction parseBindToArgs( ...args ) {\n\t// Eliminate A.bind( 'x' ).to()\n\tif ( !args.length ) {\n\t\t/**\n\t\t * Invalid argument syntax in `to()`.\n\t\t *\n\t\t * @error observable-bind-to-parse-error\n\t\t */\n\t\tthrow new CKEditorError( 'observable-bind-to-parse-error: Invalid argument syntax in `to()`.', null );\n\t}\n\n\tconst parsed = { to: [] };\n\tlet lastObservable;\n\n\tif ( typeof args[ args.length - 1 ] == 'function' ) {\n\t\tparsed.callback = args.pop();\n\t}\n\n\targs.forEach( a => {\n\t\tif ( typeof a == 'string' ) {\n\t\t\tlastObservable.properties.push( a );\n\t\t} else if ( typeof a == 'object' ) {\n\t\t\tlastObservable = { observable: a, properties: [] };\n\t\t\tparsed.to.push( lastObservable );\n\t\t} else {\n\t\t\tthrow new CKEditorError( 'observable-bind-to-parse-error: Invalid argument syntax in `to()`.', null );\n\t\t}\n\t} );\n\n\treturn parsed;\n}\n\n// Synchronizes {@link module:utils/observablemixin#_boundObservables} with {@link Binding}.\n//\n// @private\n// @param {Binding} binding A binding to store in {@link Observable#_boundObservables}.\n// @param {Observable} toObservable A observable, which is a new component of `binding`.\n// @param {String} toPropertyName A name of `toObservable`'s property, a new component of the `binding`.\nfunction updateBoundObservables( observable, binding, toObservable, toPropertyName ) {\n\tconst boundObservables = observable[ boundObservablesSymbol ];\n\tconst bindingsToObservable = boundObservables.get( toObservable );\n\tconst bindings = bindingsToObservable || {};\n\n\tif ( !bindings[ toPropertyName ] ) {\n\t\tbindings[ toPropertyName ] = new Set();\n\t}\n\n\t// Pass the binding to a corresponding Set in `observable._boundObservables`.\n\tbindings[ toPropertyName ].add( binding );\n\n\tif ( !bindingsToObservable ) {\n\t\tboundObservables.set( toObservable, bindings );\n\t}\n}\n\n// Synchronizes {@link Observable#_boundProperties} and {@link Observable#_boundObservables}\n// with {@link BindChain}.\n//\n// Assuming the following binding being created\n//\n// \t\tA.bind( 'a', 'b' ).to( B, 'x', 'y' );\n//\n// the following bindings were initialized by {@link Observable#bind} in {@link BindChain#_bindings}:\n//\n// \t\t{\n// \t\t\ta: { observable: A, property: 'a', to: [] },\n// \t\t\tb: { observable: A, property: 'b', to: [] },\n// \t\t}\n//\n// Iterate over all bindings in this chain and fill their `to` properties with\n// corresponding to( ... ) arguments (components of the binding), so\n//\n// \t\t{\n// \t\t\ta: { observable: A, property: 'a', to: [ B, 'x' ] },\n// \t\t\tb: { observable: A, property: 'b', to: [ B, 'y' ] },\n// \t\t}\n//\n// Then update the structure of {@link Observable#_boundObservables} with updated\n// binding, so it becomes:\n//\n// \t\tMap( {\n// \t\t\tB: {\n// \t\t\t\tx: Set( [\n// \t\t\t\t\t{ observable: A, property: 'a', to: [ [ B, 'x' ] ] }\n// \t\t\t\t] ),\n// \t\t\t\ty: Set( [\n// \t\t\t\t\t{ observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n// \t\t\t\t] )\n//\t\t\t}\n// \t\t} )\n//\n// @private\n// @param {BindChain} chain The binding initialized by {@link Observable#bind}.\nfunction updateBindToBound( chain ) {\n\tlet toProperty;\n\n\tchain._bindings.forEach( ( binding, propertyName ) => {\n\t\t// Note: For a binding without a callback, this will run only once\n\t\t// like in A.bind( 'x', 'y' ).to( B, 'a', 'b' )\n\t\t// TODO: ES6 destructuring.\n\t\tchain._to.forEach( to => {\n\t\t\ttoProperty = to.properties[ binding.callback ? 0 : chain._bindProperties.indexOf( propertyName ) ];\n\n\t\t\tbinding.to.push( [ to.observable, toProperty ] );\n\t\t\tupdateBoundObservables( chain._observable, binding, to.observable, toProperty );\n\t\t} );\n\t} );\n}\n\n// Updates an property of a {@link Observable} with a value\n// determined by an entry in {@link Observable#_boundProperties}.\n//\n// @private\n// @param {Observable} observable A observable which property is to be updated.\n// @param {String} propertyName An property to be updated.\nfunction updateBoundObservableProperty( observable, propertyName ) {\n\tconst boundProperties = observable[ boundPropertiesSymbol ];\n\tconst binding = boundProperties.get( propertyName );\n\tlet propertyValue;\n\n\t// When a binding with callback is created like\n\t//\n\t// \t\tA.bind( 'a' ).to( B, 'b', C, 'c', callback );\n\t//\n\t// collect B.b and C.c, then pass them to callback to set A.a.\n\tif ( binding.callback ) {\n\t\tpropertyValue = binding.callback.apply( observable, binding.to.map( to => to[ 0 ][ to[ 1 ] ] ) );\n\t} else {\n\t\tpropertyValue = binding.to[ 0 ];\n\t\tpropertyValue = propertyValue[ 0 ][ propertyValue[ 1 ] ];\n\t}\n\n\tif ( observable.hasOwnProperty( propertyName ) ) {\n\t\tobservable[ propertyName ] = propertyValue;\n\t} else {\n\t\tobservable.set( propertyName, propertyValue );\n\t}\n}\n\n// Starts listening to changes in {@link BindChain._to} observables to update\n// {@link BindChain._observable} {@link BindChain._bindProperties}. Also sets the\n// initial state of {@link BindChain._observable}.\n//\n// @private\n// @param {BindChain} chain The chain initialized by {@link Observable#bind}.\nfunction attachBindToListeners( observable, toBindings ) {\n\ttoBindings.forEach( to => {\n\t\tconst boundObservables = observable[ boundObservablesSymbol ];\n\t\tlet bindings;\n\n\t\t// If there's already a chain between the observables (`observable` listens to\n\t\t// `to.observable`), there's no need to create another `change` event listener.\n\t\tif ( !boundObservables.get( to.observable ) ) {\n\t\t\tobservable.listenTo( to.observable, 'change', ( evt, propertyName ) => {\n\t\t\t\tbindings = boundObservables.get( to.observable )[ propertyName ];\n\n\t\t\t\t// Note: to.observable will fire for any property change, react\n\t\t\t\t// to changes of properties which are bound only.\n\t\t\t\tif ( bindings ) {\n\t\t\t\t\tbindings.forEach( binding => {\n\t\t\t\t\t\tupdateBoundObservableProperty( observable, binding.property );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t} );\n}\n\n/**\n * Interface which adds \"observable properties\" and data binding functionality.\n *\n * Can be easily implemented by a class by mixing the {@link module:utils/observablemixin~ObservableMixin} mixin.\n *\n * Read more about the usage of this interface in the:\n * * {@glink framework/guides/architecture/core-editor-architecture#event-system-and-observables \"Event system and observables\"}\n * section of the {@glink framework/guides/architecture/core-editor-architecture \"Core editor architecture\"} guide,\n * * {@glink framework/guides/deep-dive/observables \"Observables\" deep dive} guide.\n *\n * @interface Observable\n * @extends module:utils/emittermixin~Emitter\n */\n\n/**\n * Fired when a property changed value.\n *\n *\t\tobservable.set( 'prop', 1 );\n *\n *\t\tobservable.on( 'change:prop', ( evt, propertyName, newValue, oldValue ) => {\n *\t\t\tconsole.log( `${ propertyName } has changed from ${ oldValue } to ${ newValue }` );\n *\t\t} );\n *\n *\t\tobservable.prop = 2; // -> 'prop has changed from 1 to 2'\n *\n * @event change:{property}\n * @param {String} name The property name.\n * @param {*} value The new property value.\n * @param {*} oldValue The previous property value.\n */\n\n/**\n * Fired when a property value is going to be set but is not set yet (before the `change` event is fired).\n *\n * You can control the final value of the property by using\n * the {@link module:utils/eventinfo~EventInfo#return event's `return` property}.\n *\n *\t\tobservable.set( 'prop', 1 );\n *\n *\t\tobservable.on( 'set:prop', ( evt, propertyName, newValue, oldValue ) => {\n *\t\t\tconsole.log( `Value is going to be changed from ${ oldValue } to ${ newValue }` );\n *\t\t\tconsole.log( `Current property value is ${ observable[ propertyName ] }` );\n *\n *\t\t\t// Let's override the value.\n *\t\t\tevt.return = 3;\n *\t\t} );\n *\n *\t\tobservable.on( 'change:prop', ( evt, propertyName, newValue, oldValue ) => {\n *\t\t\tconsole.log( `Value has changed from ${ oldValue } to ${ newValue }` );\n *\t\t} );\n *\n *\t\tobservable.prop = 2; // -> 'Value is going to be changed from 1 to 2'\n *\t\t // -> 'Current property value is 1'\n *\t\t // -> 'Value has changed from 1 to 3'\n *\n * **Note:** Event is fired even when the new value is the same as the old value.\n *\n * @event set:{property}\n * @param {String} name The property name.\n * @param {*} value The new property value.\n * @param {*} oldValue The previous property value.\n */\n\n/**\n * Creates and sets the value of an observable property of this object. Such an property becomes a part\n * of the state and is be observable.\n *\n * It accepts also a single object literal containing key/value pairs with properties to be set.\n *\n * This method throws the `observable-set-cannot-override` error if the observable instance already\n * have a property with the given property name. This prevents from mistakenly overriding existing\n * properties and methods, but means that `foo.set( 'bar', 1 )` may be slightly slower than `foo.bar = 1`.\n *\n * @method #set\n * @param {String|Object} name The property's name or object with `name=>value` pairs.\n * @param {*} [value] The property's value (if `name` was passed in the first parameter).\n */\n\n/**\n * Binds {@link #set observable properties} to other objects implementing the\n * {@link module:utils/observablemixin~Observable} interface.\n *\n * Read more in the {@glink framework/guides/deep-dive/observables#property-bindings dedicated guide}\n * covering the topic of property bindings with some additional examples.\n *\n * Consider two objects: a `button` and an associated `command` (both `Observable`).\n *\n * A simple property binding could be as follows:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command, 'isEnabled' );\n *\n * or even shorter:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command );\n *\n * which works in the following way:\n *\n * * `button.isEnabled` **instantly equals** `command.isEnabled`,\n * * whenever `command.isEnabled` changes, `button.isEnabled` will immediately reflect its value.\n *\n * **Note**: To release the binding, use {@link module:utils/observablemixin~Observable#unbind}.\n *\n * You can also \"rename\" the property in the binding by specifying the new name in the `to()` chain:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command, 'isWorking' );\n *\n * It is possible to bind more than one property at a time to shorten the code:\n *\n *\t\tbutton.bind( 'isEnabled', 'value' ).to( command );\n *\n * which corresponds to:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command );\n *\t\tbutton.bind( 'value' ).to( command );\n *\n * The binding can include more than one observable, combining multiple data sources in a custom callback:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command, 'isEnabled', ui, 'isVisible',\n *\t\t\t( isCommandEnabled, isUIVisible ) => isCommandEnabled && isUIVisible );\n *\n * It is also possible to bind to the same property in an array of observables.\n * To bind a `button` to multiple commands (also `Observables`) so that each and every one of them\n * must be enabled for the button to become enabled, use the following code:\n *\n *\t\tbutton.bind( 'isEnabled' ).toMany( [ commandA, commandB, commandC ], 'isEnabled',\n *\t\t\t( isAEnabled, isBEnabled, isCEnabled ) => isAEnabled && isBEnabled && isCEnabled );\n *\n * @method #bind\n * @param {...String} bindProperties Observable properties that will be bound to other observable(s).\n * @returns {Object} The bind chain with the `to()` and `toMany()` methods.\n */\n\n/**\n * Removes the binding created with {@link #bind}.\n *\n *\t\t// Removes the binding for the 'a' property.\n *\t\tA.unbind( 'a' );\n *\n *\t\t// Removes bindings for all properties.\n *\t\tA.unbind();\n *\n * @method #unbind\n * @param {...String} [unbindProperties] Observable properties to be unbound. All the bindings will\n * be released if no properties are provided.\n */\n\n/**\n * Turns the given methods of this object into event-based ones. This means that the new method will fire an event\n * (named after the method) and the original action will be plugged as a listener to that event.\n *\n * Read more in the {@glink framework/guides/deep-dive/observables#decorating-object-methods dedicated guide}\n * covering the topic of decorating methods with some additional examples.\n *\n * Decorating the method does not change its behavior (it only adds an event),\n * but it allows to modify it later on by listening to the method's event.\n *\n * For example, to cancel the method execution the event can be {@link module:utils/eventinfo~EventInfo#stop stopped}:\n *\n *\t\tclass Foo {\n *\t\t\tconstructor() {\n *\t\t\t\tthis.decorate( 'method' );\n *\t\t\t}\n *\n *\t\t\tmethod() {\n *\t\t\t\tconsole.log( 'called!' );\n *\t\t\t}\n *\t\t}\n *\n *\t\tconst foo = new Foo();\n *\t\tfoo.on( 'method', ( evt ) => {\n *\t\t\tevt.stop();\n *\t\t}, { priority: 'high' } );\n *\n *\t\tfoo.method(); // Nothing is logged.\n *\n *\n * **Note**: The high {@link module:utils/priorities~PriorityString priority} listener\n * has been used to execute this particular callback before the one which calls the original method\n * (which uses the \"normal\" priority).\n *\n * It is also possible to change the returned value:\n *\n *\t\tfoo.on( 'method', ( evt ) => {\n *\t\t\tevt.return = 'Foo!';\n *\t\t} );\n *\n *\t\tfoo.method(); // -> 'Foo'\n *\n * Finally, it is possible to access and modify the arguments the method is called with:\n *\n *\t\tmethod( a, b ) {\n *\t\t\tconsole.log( `${ a }, ${ b }` );\n *\t\t}\n *\n *\t\t// ...\n *\n *\t\tfoo.on( 'method', ( evt, args ) => {\n *\t\t\targs[ 0 ] = 3;\n *\n *\t\t\tconsole.log( args[ 1 ] ); // -> 2\n *\t\t}, { priority: 'high' } );\n *\n *\t\tfoo.method( 1, 2 ); // -> '3, 2'\n *\n * @method #decorate\n * @param {String} methodName Name of the method to decorate.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/editableelement\n */\n\nimport ContainerElement from './containerelement';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\n\nconst documentSymbol = Symbol( 'document' );\n\n/**\n * Editable element which can be a {@link module:engine/view/rooteditableelement~RootEditableElement root}\n * or nested editable area in the editor.\n *\n * Editable is automatically read-only when its {@link module:engine/view/document~Document Document} is read-only.\n *\n * The constructor of this class shouldn't be used directly. To create new `EditableElement` use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createEditableElement `downcastWriter#createEditableElement()`} method.\n *\n * @extends module:engine/view/containerelement~ContainerElement\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class EditableElement extends ContainerElement {\n\t/**\n\t * Creates an editable element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createEditableElement\n\t * @protected\n\t */\n\tconstructor( name, attrs, children ) {\n\t\tsuper( name, attrs, children );\n\n\t\t/**\n\t\t * Whether the editable is in read-write or read-only mode.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/editableelement~EditableElement#isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * Whether the editable is focused.\n\t\t *\n\t\t * This property updates when {@link module:engine/view/document~Document#isFocused document.isFocused} or view\n\t\t * selection is changed.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/editableelement~EditableElement#isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * The {@link module:engine/view/document~Document} which is an owner of this root.\n\t\t * Can only by set once.\n\t\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-editableelement-document-already-set`\n\t\t * when document is already set.\n\t\t *\n\t\t * @member {module:engine/view/document~Document} #document\n\t\t */\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\teditableElement.is( 'editableElement' ); // -> true\n\t *\t\teditableElement.is( 'element' ); // -> true\n\t *\t\teditableElement.is( 'node' ); // -> true\n\t *\t\teditableElement.is( 'view:editableElement' ); // -> true\n\t *\t\teditableElement.is( 'view:element' ); // -> true\n\t *\t\teditableElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\teditableElement.is( 'model:element' ); // -> false\n\t *\t\teditableElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an editbale element, you can also check its\n\t * {@link module:engine/view/editableelement~EditableElement#name name}:\n\t *\n\t *\t\teditableElement.is( 'div' ); // -> true if this is a div element\n\t *\t\teditableElement.is( 'editableElement', 'div' ); // -> same as above\n\t *\t\ttext.is( 'div' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check when `name` parameter is present.\n\t * Otherwise, it acts like the `name` parameter.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tconst cutType = type && type.replace( /^view:/, '' );\n\t\tif ( !name ) {\n\t\t\treturn cutType == 'editableElement' || super.is( type );\n\t\t} else {\n\t\t\treturn ( cutType == 'editableElement' && name == this.name ) || super.is( type, name );\n\t\t}\n\t}\n\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Returns document associated with the editable.\n\t *\n\t * @readonly\n\t * @returns {module:engine/view/document~Document}\n\t */\n\tget document() {\n\t\treturn this.getCustomProperty( documentSymbol );\n\t}\n\n\t/**\n\t * Sets document of this editable element.\n\t *\n\t * @protected\n\t * @param {module:engine/view/document~Document} document\n\t */\n\tset _document( document ) {\n\t\tif ( this.getCustomProperty( documentSymbol ) ) {\n\t\t\t/**\n\t\t\t * View document is already set. It can only be set once.\n\t\t\t *\n\t\t\t * @error view-editableelement-document-already-set\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-editableelement-document-already-set: View document is already set.', this );\n\t\t}\n\n\t\tthis._setCustomProperty( documentSymbol, document );\n\n\t\tthis.bind( 'isReadOnly' ).to( document );\n\n\t\tthis.bind( 'isFocused' ).to(\n\t\t\tdocument,\n\t\t\t'isFocused',\n\t\t\tisFocused => isFocused && document.selection.editableElement == this\n\t\t);\n\n\t\t// Update focus state based on selection changes.\n\t\tthis.listenTo( document.selection, 'change', () => {\n\t\t\tthis.isFocused = document.isFocused && document.selection.editableElement == this;\n\t\t} );\n\t}\n}\n\nmix( EditableElement, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/rooteditableelement\n */\n\nimport EditableElement from './editableelement';\n\nconst rootNameSymbol = Symbol( 'rootName' );\n\n/**\n * Class representing a single root in the data view. A root can be either {@link ~RootEditableElement#isReadOnly editable or read-only},\n * but in both cases it is called \"an editable\". Roots can contain other {@link module:engine/view/editableelement~EditableElement\n * editable elements} making them \"nested editables\".\n *\n * @extends module:engine/view/editableelement~EditableElement\n */\nexport default class RootEditableElement extends EditableElement {\n\t/**\n\t * Creates root editable element.\n\t *\n\t * @param {String} name Node name.\n\t */\n\tconstructor( name ) {\n\t\tsuper( name );\n\n\t\t/**\n\t\t * Name of this root inside {@link module:engine/view/document~Document} that is an owner of this root. If no\n\t\t * other name is set, `main` name is used.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.rootName = 'main';\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\trootEditableElement.is( 'rootEditableElement' ); // -> true\n\t *\t\trootEditableElement.is( 'editableElement' ); // -> true\n\t *\t\trootEditableElement.is( 'element' ); // -> true\n\t *\t\trootEditableElement.is( 'node' ); // -> true\n\t *\t\trootEditableElement.is( 'view:rootEditableElement' ); // -> true\n\t *\t\trootEditableElement.is( 'view:editableElement' ); // -> true\n\t *\t\trootEditableElement.is( 'view:element' ); // -> true\n\t *\t\trootEditableElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\trootEditableElement.is( 'model:element' ); // -> false\n\t *\t\trootEditableElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is a root editbale element, you can also check its\n\t * {@link module:engine/view/rooteditableelement~RootEditableElement#name name}:\n\t *\n\t *\t\trootEditableElement.is( 'div' ); // -> true if this is a div root editable element\n\t *\t\trootEditableElement.is( 'rootEditableElement', 'div' ); // -> same as above\n\t *\t\ttext.is( 'div' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check when `name` parameter is present.\n\t * Otherwise, it acts like the `name` parameter.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tconst cutType = type.replace( /^view:/, '' );\n\t\tif ( !name ) {\n\t\t\treturn cutType == 'rootElement' || super.is( type );\n\t\t} else {\n\t\t\treturn ( cutType == 'rootElement' && name == this.name ) || super.is( type, name );\n\t\t}\n\t}\n\n\tget rootName() {\n\t\treturn this.getCustomProperty( rootNameSymbol );\n\t}\n\n\tset rootName( rootName ) {\n\t\tthis._setCustomProperty( rootNameSymbol, rootName );\n\t}\n\n\t/**\n\t * Overrides old element name and sets new one.\n\t * This is needed because view roots are created before they are attached to the DOM.\n\t * The name of the root element is temporary at this stage. It has to be changed when the\n\t * view root element is attached to the DOM element.\n\t *\n\t * @protected\n\t * @param {String} name The new name of element.\n\t */\n\tset _name( name ) {\n\t\tthis.name = name;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/treewalker\n */\n\nimport Element from './element';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport Position from './position';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Position iterator class. It allows to iterate forward and backward over the document.\n */\nexport default class TreeWalker {\n\t/**\n\t * Creates a range iterator. All parameters are optional, but you have to specify either `boundaries` or `startPosition`.\n\t *\n\t * @constructor\n\t * @param {Object} options Object with configuration.\n\t * @param {module:engine/view/range~Range} [options.boundaries=null] Range to define boundaries of the iterator.\n\t * @param {module:engine/view/position~Position} [options.startPosition] Starting position.\n\t * @param {'forward'|'backward'} [options.direction='forward'] Walking direction.\n\t * @param {Boolean} [options.singleCharacters=false] Flag indicating whether all characters from\n\t * {@link module:engine/view/text~Text} should be returned as one {@link module:engine/view/text~Text} (`false`) ore one by one as\n\t * {@link module:engine/view/textproxy~TextProxy} (`true`).\n\t * @param {Boolean} [options.shallow=false] Flag indicating whether iterator should enter elements or not. If the\n\t * iterator is shallow child nodes of any iterated node will not be returned along with `elementEnd` tag.\n\t * @param {Boolean} [options.ignoreElementEnd=false] Flag indicating whether iterator should ignore `elementEnd`\n\t * tags. If the option is true walker will not return a parent node of start position. If this option is `true`\n\t * each {@link module:engine/view/element~Element} will be returned once, while if the option is `false` they might be returned\n\t * twice: for `'elementStart'` and `'elementEnd'`.\n\t */\n\tconstructor( options = {} ) {\n\t\tif ( !options.boundaries && !options.startPosition ) {\n\t\t\t/**\n\t\t\t * Neither boundaries nor starting position have been defined.\n\t\t\t *\n\t\t\t * @error view-tree-walker-no-start-position\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-tree-walker-no-start-position: Neither boundaries nor starting position have been defined.',\n\t\t\t\tnull\n\t\t\t);\n\t\t}\n\n\t\tif ( options.direction && options.direction != 'forward' && options.direction != 'backward' ) {\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-tree-walker-unknown-direction: Only `backward` and `forward` direction allowed.',\n\t\t\t\toptions.startPosition,\n\t\t\t\t{ direction: options.direction }\n\t\t\t);\n\t\t}\n\n\t\t/**\n\t\t * Iterator boundaries.\n\t\t *\n\t\t * When the iterator is walking `'forward'` on the end of boundary or is walking `'backward'`\n\t\t * on the start of boundary, then `{ done: true }` is returned.\n\t\t *\n\t\t * If boundaries are not defined they are set before first and after last child of the root node.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/range~Range} module:engine/view/treewalker~TreeWalker#boundaries\n\t\t */\n\t\tthis.boundaries = options.boundaries || null;\n\n\t\t/**\n\t\t * Iterator position. If start position is not defined then position depends on {@link #direction}. If direction is\n\t\t * `'forward'` position starts form the beginning, when direction is `'backward'` position starts from the end.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/position~Position} module:engine/view/treewalker~TreeWalker#position\n\t\t */\n\t\tif ( options.startPosition ) {\n\t\t\tthis.position = Position._createAt( options.startPosition );\n\t\t} else {\n\t\t\tthis.position = Position._createAt( options.boundaries[ options.direction == 'backward' ? 'end' : 'start' ] );\n\t\t}\n\n\t\t/**\n\t\t * Walking direction. Defaults `'forward'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'backward'|'forward'} module:engine/view/treewalker~TreeWalker#direction\n\t\t */\n\t\tthis.direction = options.direction || 'forward';\n\n\t\t/**\n\t\t * Flag indicating whether all characters from {@link module:engine/view/text~Text} should be returned as one\n\t\t * {@link module:engine/view/text~Text} or one by one as {@link module:engine/view/textproxy~TextProxy}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/view/treewalker~TreeWalker#singleCharacters\n\t\t */\n\t\tthis.singleCharacters = !!options.singleCharacters;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should enter elements or not. If the iterator is shallow child nodes of any\n\t\t * iterated node will not be returned along with `elementEnd` tag.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/view/treewalker~TreeWalker#shallow\n\t\t */\n\t\tthis.shallow = !!options.shallow;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should ignore `elementEnd` tags. If set to `true`, walker will not\n\t\t * return a parent node of the start position. Each {@link module:engine/view/element~Element} will be returned once.\n\t\t * When set to `false` each element might be returned twice: for `'elementStart'` and `'elementEnd'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/view/treewalker~TreeWalker#ignoreElementEnd\n\t\t */\n\t\tthis.ignoreElementEnd = !!options.ignoreElementEnd;\n\n\t\t/**\n\t\t * Start boundary parent.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/node~Node} module:engine/view/treewalker~TreeWalker#_boundaryStartParent\n\t\t */\n\t\tthis._boundaryStartParent = this.boundaries ? this.boundaries.start.parent : null;\n\n\t\t/**\n\t\t * End boundary parent.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/node~Node} module:engine/view/treewalker~TreeWalker#_boundaryEndParent\n\t\t */\n\t\tthis._boundaryEndParent = this.boundaries ? this.boundaries.end.parent : null;\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<module:engine/view/treewalker~TreeWalkerValue>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Moves {@link #position} in the {@link #direction} skipping values as long as the callback function returns `true`.\n\t *\n\t * For example:\n\t *\n\t * \t\twalker.skip( value => value.type == 'text' ); // <p>{}foo</p> -> <p>foo[]</p>\n\t * \t\twalker.skip( value => true ); // Move the position to the end: <p>{}foo</p> -> <p>foo</p>[]\n\t * \t\twalker.skip( value => false ); // Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/view/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t */\n\tskip( skip ) {\n\t\tlet done, value, prevPosition;\n\n\t\tdo {\n\t\t\tprevPosition = this.position;\n\n\t\t\t( { done, value } = this.next() );\n\t\t} while ( !done && skip( value ) );\n\n\t\tif ( !done ) {\n\t\t\tthis.position = prevPosition;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the next tree walker's value.\n\t *\n\t * @returns {module:engine/view/treewalker~TreeWalkerValue} Object implementing iterator interface, returning\n\t * information about taken step.\n\t */\n\tnext() {\n\t\tif ( this.direction == 'forward' ) {\n\t\t\treturn this._next();\n\t\t} else {\n\t\t\treturn this._previous();\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step forward in view. Moves the {@link #position} to the next position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done `true` if iterator is done, `false` otherwise.\n\t * @returns {module:engine/view/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_next() {\n\t\tlet position = this.position.clone();\n\t\tconst previousPosition = this.position;\n\t\tconst parent = position.parent;\n\n\t\t// We are at the end of the root.\n\t\tif ( parent.parent === null && position.offset === parent.childCount ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent === this._boundaryEndParent && position.offset == this.boundaries.end.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just after current position.\n\t\tlet node;\n\n\t\t// Text is a specific parent because it contains string instead of child nodes.\n\t\tif ( parent instanceof Text ) {\n\t\t\tif ( position.isAtEnd ) {\n\t\t\t\t// Prevent returning \"elementEnd\" for Text node. Skip that value and return the next walker step.\n\t\t\t\tthis.position = Position._createAfter( parent );\n\n\t\t\t\treturn this._next();\n\t\t\t}\n\n\t\t\tnode = parent.data[ position.offset ];\n\t\t} else {\n\t\t\tnode = parent.getChild( position.offset );\n\t\t}\n\n\t\tif ( node instanceof Element ) {\n\t\t\tif ( !this.shallow ) {\n\t\t\t\tposition = new Position( node, 0 );\n\t\t\t} else {\n\t\t\t\tposition.offset++;\n\t\t\t}\n\n\t\t\tthis.position = position;\n\n\t\t\treturn this._formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t} else if ( node instanceof Text ) {\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tposition = new Position( node, 0 );\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._next();\n\t\t\t} else {\n\t\t\t\tlet charactersCount = node.data.length;\n\t\t\t\tlet item;\n\n\t\t\t\t// If text stick out of walker range, we need to cut it and wrap in TextProxy.\n\t\t\t\tif ( node == this._boundaryEndParent ) {\n\t\t\t\t\tcharactersCount = this.boundaries.end.offset;\n\t\t\t\t\titem = new TextProxy( node, 0, charactersCount );\n\t\t\t\t\tposition = Position._createAfter( item );\n\t\t\t\t} else {\n\t\t\t\t\titem = new TextProxy( node, 0, node.data.length );\n\t\t\t\t\t// If not just keep moving forward.\n\t\t\t\t\tposition.offset++;\n\t\t\t\t}\n\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t\t}\n\t\t} else if ( typeof node == 'string' ) {\n\t\t\tlet textLength;\n\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\ttextLength = 1;\n\t\t\t} else {\n\t\t\t\t// Check if text stick out of walker range.\n\t\t\t\tconst endOffset = parent === this._boundaryEndParent ? this.boundaries.end.offset : parent.data.length;\n\n\t\t\t\ttextLength = endOffset - position.offset;\n\t\t\t}\n\n\t\t\tconst textProxy = new TextProxy( parent, position.offset, textLength );\n\n\t\t\tposition.offset += textLength;\n\t\t\tthis.position = position;\n\n\t\t\treturn this._formatReturnValue( 'text', textProxy, previousPosition, position, textLength );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the end of current `parent`.\n\t\t\tposition = Position._createAfter( parent );\n\t\t\tthis.position = position;\n\n\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\treturn this._next();\n\t\t\t} else {\n\t\t\t\treturn this._formatReturnValue( 'elementEnd', parent, previousPosition, position );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step backward in view. Moves the {@link #position} to the previous position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done True if iterator is done.\n\t * @returns {module:engine/view/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_previous() {\n\t\tlet position = this.position.clone();\n\t\tconst previousPosition = this.position;\n\t\tconst parent = position.parent;\n\n\t\t// We are at the beginning of the root.\n\t\tif ( parent.parent === null && position.offset === 0 ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent == this._boundaryStartParent && position.offset == this.boundaries.start.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just before current position.\n\t\tlet node;\n\n\t\t// Text {@link module:engine/view/text~Text} element is a specific parent because contains string instead of child nodes.\n\t\tif ( parent instanceof Text ) {\n\t\t\tif ( position.isAtStart ) {\n\t\t\t\t// Prevent returning \"elementStart\" for Text node. Skip that value and return the next walker step.\n\t\t\t\tthis.position = Position._createBefore( parent );\n\n\t\t\t\treturn this._previous();\n\t\t\t}\n\n\t\t\tnode = parent.data[ position.offset - 1 ];\n\t\t} else {\n\t\t\tnode = parent.getChild( position.offset - 1 );\n\t\t}\n\n\t\tif ( node instanceof Element ) {\n\t\t\tif ( !this.shallow ) {\n\t\t\t\tposition = new Position( node, node.childCount );\n\t\t\t\tthis.position = position;\n\n\t\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\t\treturn this._previous();\n\t\t\t\t} else {\n\t\t\t\t\treturn this._formatReturnValue( 'elementEnd', node, previousPosition, position );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tposition.offset--;\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t\t}\n\t\t} else if ( node instanceof Text ) {\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tposition = new Position( node, node.data.length );\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._previous();\n\t\t\t} else {\n\t\t\t\tlet charactersCount = node.data.length;\n\t\t\t\tlet item;\n\n\t\t\t\t// If text stick out of walker range, we need to cut it and wrap in TextProxy.\n\t\t\t\tif ( node == this._boundaryStartParent ) {\n\t\t\t\t\tconst offset = this.boundaries.start.offset;\n\n\t\t\t\t\titem = new TextProxy( node, offset, node.data.length - offset );\n\t\t\t\t\tcharactersCount = item.data.length;\n\t\t\t\t\tposition = Position._createBefore( item );\n\t\t\t\t} else {\n\t\t\t\t\titem = new TextProxy( node, 0, node.data.length );\n\t\t\t\t\t// If not just keep moving backward.\n\t\t\t\t\tposition.offset--;\n\t\t\t\t}\n\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t\t}\n\t\t} else if ( typeof node == 'string' ) {\n\t\t\tlet textLength;\n\n\t\t\tif ( !this.singleCharacters ) {\n\t\t\t\t// Check if text stick out of walker range.\n\t\t\t\tconst startOffset = parent === this._boundaryStartParent ? this.boundaries.start.offset : 0;\n\n\t\t\t\ttextLength = position.offset - startOffset;\n\t\t\t} else {\n\t\t\t\ttextLength = 1;\n\t\t\t}\n\n\t\t\tposition.offset -= textLength;\n\n\t\t\tconst textProxy = new TextProxy( parent, position.offset, textLength );\n\n\t\t\tthis.position = position;\n\n\t\t\treturn this._formatReturnValue( 'text', textProxy, previousPosition, position, textLength );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the beginning of current `parent`.\n\t\t\tposition = Position._createBefore( parent );\n\t\t\tthis.position = position;\n\n\t\t\treturn this._formatReturnValue( 'elementStart', parent, previousPosition, position, 1 );\n\t\t}\n\t}\n\n\t/**\n\t * Format returned data and adjust `previousPosition` and `nextPosition` if reach the bound of the {@link module:engine/view/text~Text}.\n\t *\n\t * @private\n\t * @param {module:engine/view/treewalker~TreeWalkerValueType} type Type of step.\n\t * @param {module:engine/view/item~Item} item Item between old and new position.\n\t * @param {module:engine/view/position~Position} previousPosition Previous position of iterator.\n\t * @param {module:engine/view/position~Position} nextPosition Next position of iterator.\n\t * @param {Number} [length] Length of the item.\n\t * @returns {module:engine/view/treewalker~TreeWalkerValue}\n\t */\n\t_formatReturnValue( type, item, previousPosition, nextPosition, length ) {\n\t\t// Text is a specific parent, because contains string instead of children.\n\t\t// Walker doesn't enter to the Text except situations when walker is iterating over every single character,\n\t\t// or the bound starts/ends inside the Text. So when the position is at the beginning or at the end of the Text\n\t\t// we move it just before or just after Text.\n\t\tif ( item instanceof TextProxy ) {\n\t\t\t// Position is at the end of Text.\n\t\t\tif ( item.offsetInText + item.data.length == item.textNode.data.length ) {\n\t\t\t\tif ( this.direction == 'forward' && !( this.boundaries && this.boundaries.end.isEqual( this.position ) ) ) {\n\t\t\t\t\tnextPosition = Position._createAfter( item.textNode );\n\t\t\t\t\t// When we change nextPosition of returned value we need also update walker current position.\n\t\t\t\t\tthis.position = nextPosition;\n\t\t\t\t} else {\n\t\t\t\t\tpreviousPosition = Position._createAfter( item.textNode );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Position is at the begining ot the text.\n\t\t\tif ( item.offsetInText === 0 ) {\n\t\t\t\tif ( this.direction == 'backward' && !( this.boundaries && this.boundaries.start.isEqual( this.position ) ) ) {\n\t\t\t\t\tnextPosition = Position._createBefore( item.textNode );\n\t\t\t\t\t// When we change nextPosition of returned value we need also update walker current position.\n\t\t\t\t\tthis.position = nextPosition;\n\t\t\t\t} else {\n\t\t\t\t\tpreviousPosition = Position._createBefore( item.textNode );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tdone: false,\n\t\t\tvalue: {\n\t\t\t\ttype,\n\t\t\t\titem,\n\t\t\t\tpreviousPosition,\n\t\t\t\tnextPosition,\n\t\t\t\tlength\n\t\t\t}\n\t\t};\n\t}\n}\n\n/**\n * Type of the step made by {@link module:engine/view/treewalker~TreeWalker}.\n * Possible values: `'elementStart'` if walker is at the beginning of a node, `'elementEnd'` if walker is at the end\n * of node, or `'text'` if walker traversed over single and multiple characters.\n * For {@link module:engine/view/text~Text} `elementStart` and `elementEnd` is not returned.\n *\n * @typedef {String} module:engine/view/treewalker~TreeWalkerValueType\n */\n\n/**\n * Object returned by {@link module:engine/view/treewalker~TreeWalker} when traversing tree view.\n *\n * @typedef {Object} module:engine/view/treewalker~TreeWalkerValue\n * @property {module:engine/view/treewalker~TreeWalkerValueType} type\n * @property {module:engine/view/item~Item} item Item between the old and the new positions\n * of the tree walker.\n * @property {module:engine/view/position~Position} previousPosition Previous position of the iterator.\n * * Forward iteration: For `'elementEnd'` it is the last position inside the element. For all other types it is the\n * position before the item.\n * * Backward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after item.\n * * If the position is at the beginning or at the end of the {@link module:engine/view/text~Text} it is always moved from the\n * inside of the text to its parent just before or just after that text.\n * @property {module:engine/view/position~Position} nextPosition Next position of the iterator.\n * * Forward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after the item.\n * * Backward iteration: For `'elementEnd'` it is last position inside element. For all other types it is the position\n * before the item.\n * * If the position is at the beginning or at the end of the {@link module:engine/view/text~Text} it is always moved from the\n * inside of the text to its parent just before or just after that text.\n * @property {Number} [length] Length of the item. For `'elementStart'` it is `1`. For `'text'` it is\n * the length of that text. For `'elementEnd'` it is `undefined`.\n */\n\n/**\n * Tree walking directions.\n *\n * @typedef {'forward'|'backward'} module:engine/view/treewalker~TreeWalkerDirection\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/position\n */\n\nimport TreeWalker from './treewalker';\n\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport EditableElement from './editableelement';\n\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Position in the view tree. Position is represented by its parent node and an offset in this parent.\n *\n * In order to create a new position instance use the `createPosition*()` factory methods available in:\n *\n * * {@link module:engine/view/view~View}\n * * {@link module:engine/view/downcastwriter~DowncastWriter}\n * * {@link module:engine/view/upcastwriter~UpcastWriter}\n */\nexport default class Position {\n\t/**\n\t * Creates a position.\n\t *\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} parent Position parent.\n\t * @param {Number} offset Position offset.\n\t */\n\tconstructor( parent, offset ) {\n\t\t/**\n\t\t * Position parent.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t\t * module:engine/view/position~Position#parent\n\t\t */\n\t\tthis.parent = parent;\n\n\t\t/**\n\t\t * Position offset.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} module:engine/view/position~Position#offset\n\t\t */\n\t\tthis.offset = offset;\n\t}\n\n\t/**\n\t * Node directly after the position. Equals `null` when there is no node after position or position is located\n\t * inside text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget nodeAfter() {\n\t\tif ( this.parent.is( 'text' ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.parent.getChild( this.offset ) || null;\n\t}\n\n\t/**\n\t * Node directly before the position. Equals `null` when there is no node before position or position is located\n\t * inside text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget nodeBefore() {\n\t\tif ( this.parent.is( 'text' ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.parent.getChild( this.offset - 1 ) || null;\n\t}\n\n\t/**\n\t * Is `true` if position is at the beginning of its {@link module:engine/view/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtStart() {\n\t\treturn this.offset === 0;\n\t}\n\n\t/**\n\t * Is `true` if position is at the end of its {@link module:engine/view/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtEnd() {\n\t\tconst endOffset = this.parent.is( 'text' ) ? this.parent.data.length : this.parent.childCount;\n\n\t\treturn this.offset === endOffset;\n\t}\n\n\t/**\n\t * Position's root, that is the root of the position's parent element.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.parent.root;\n\t}\n\n\t/**\n\t * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this position, or `null` if\n\t * position is not inside an editable element.\n\t *\n\t * @type {module:engine/view/editableelement~EditableElement|null}\n\t */\n\tget editableElement() {\n\t\tlet editable = this.parent;\n\n\t\twhile ( !( editable instanceof EditableElement ) ) {\n\t\t\tif ( editable.parent ) {\n\t\t\t\teditable = editable.parent;\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\treturn editable;\n\t}\n\n\t/**\n\t * Returns a new instance of Position with offset incremented by `shift` value.\n\t *\n\t * @param {Number} shift How position offset should get changed. Accepts negative values.\n\t * @returns {module:engine/view/position~Position} Shifted position.\n\t */\n\tgetShiftedBy( shift ) {\n\t\tconst shifted = Position._createAt( this );\n\n\t\tconst offset = shifted.offset + shift;\n\t\tshifted.offset = offset < 0 ? 0 : offset;\n\n\t\treturn shifted;\n\t}\n\n\t/**\n\t * Gets the farthest position which matches the callback using\n\t * {@link module:engine/view/treewalker~TreeWalker TreeWalker}.\n\t *\n\t * For example:\n\t *\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text' ); // <p>{}foo</p> -> <p>foo[]</p>\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text', { direction: 'backward' } ); // <p>foo[]</p> -> <p>{}foo</p>\n\t * \t\tgetLastMatchingPosition( value => false ); // Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/view/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t *\n\t * @returns {module:engine/view/position~Position} The position after the last item which matches the `skip` callback test.\n\t */\n\tgetLastMatchingPosition( skip, options = {} ) {\n\t\toptions.startPosition = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\t\ttreeWalker.skip( skip );\n\n\t\treturn treeWalker.position;\n\t}\n\n\t/**\n\t * Returns ancestors array of this position, that is this position's parent and it's ancestors.\n\t *\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors() {\n\t\tif ( this.parent.is( 'documentFragment' ) ) {\n\t\t\treturn [ this.parent ];\n\t\t} else {\n\t\t\treturn this.parent.getAncestors( { includeSelf: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/view/node~Node} or {@link module:engine/view/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both positions.\n\t *\n\t * @param {module:engine/view/position~Position} position\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( position ) {\n\t\tconst ancestorsA = this.getAncestors();\n\t\tconst ancestorsB = position.getAncestors();\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tposition.is( 'position' ); // -> true\n\t *\t\tposition.is( 'view:position' ); // -> true\n\t *\n\t *\t\tposition.is( 'model:position' ); // -> false\n\t *\t\tposition.is( 'element' ); // -> false\n\t *\t\tposition.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'position' || type == 'view:position';\n\t}\n\n\t/**\n\t * Checks whether this position equals given position.\n\t *\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if positions are same.\n\t */\n\tisEqual( otherPosition ) {\n\t\treturn ( this.parent == otherPosition.parent && this.offset == otherPosition.offset );\n\t}\n\n\t/**\n\t * Checks whether this position is located before given position. When method returns `false` it does not mean that\n\t * this position is after give one. Two positions may be located inside separate roots and in that situation this\n\t * method will still return `false`.\n\t *\n\t * @see module:engine/view/position~Position#isAfter\n\t * @see module:engine/view/position~Position#compareWith\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} Returns `true` if this position is before given position.\n\t */\n\tisBefore( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'before';\n\t}\n\n\t/**\n\t * Checks whether this position is located after given position. When method returns `false` it does not mean that\n\t * this position is before give one. Two positions may be located inside separate roots and in that situation this\n\t * method will still return `false`.\n\t *\n\t * @see module:engine/view/position~Position#isBefore\n\t * @see module:engine/view/position~Position#compareWith\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} Returns `true` if this position is after given position.\n\t */\n\tisAfter( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'after';\n\t}\n\n\t/**\n\t * Checks whether this position is before, after or in same position that other position. Two positions may be also\n\t * different when they are located in separate roots.\n\t *\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {module:engine/view/position~PositionRelation}\n\t */\n\tcompareWith( otherPosition ) {\n\t\tif ( this.root !== otherPosition.root ) {\n\t\t\treturn 'different';\n\t\t}\n\n\t\tif ( this.isEqual( otherPosition ) ) {\n\t\t\treturn 'same';\n\t\t}\n\n\t\t// Get path from root to position's parent element.\n\t\tconst thisPath = this.parent.is( 'node' ) ? this.parent.getPath() : [];\n\t\tconst otherPath = otherPosition.parent.is( 'node' ) ? otherPosition.parent.getPath() : [];\n\n\t\t// Add the positions' offsets to the parents offsets.\n\t\tthisPath.push( this.offset );\n\t\totherPath.push( otherPosition.offset );\n\n\t\t// Compare both path arrays to find common ancestor.\n\t\tconst result = compareArrays( thisPath, otherPath );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'prefix':\n\t\t\t\treturn 'before';\n\n\t\t\tcase 'extension':\n\t\t\t\treturn 'after';\n\n\t\t\tdefault:\n\t\t\t\treturn thisPath[ result ] < otherPath[ result ] ? 'before' : 'after';\n\t\t}\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/view/treewalker~TreeWalker TreeWalker} instance with this positions as a start position.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}\n\t * @param {module:engine/view/range~Range} [options.boundaries=null] Range to define boundaries of the iterator.\n\t * @param {Boolean} [options.singleCharacters=false]\n\t * @param {Boolean} [options.shallow=false]\n\t * @param {Boolean} [options.ignoreElementEnd=false]\n\t */\n\tgetWalker( options = {} ) {\n\t\toptions.startPosition = this;\n\n\t\treturn new TreeWalker( options );\n\t}\n\n\tclone() {\n\t\treturn new Position( this.parent, this.offset );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link module:engine/view/position~Position._createBefore},\n\t * * {@link module:engine/view/position~Position._createAfter}.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tstatic _createAt( itemOrPosition, offset ) {\n\t\tif ( itemOrPosition instanceof Position ) {\n\t\t\treturn new this( itemOrPosition.parent, itemOrPosition.offset );\n\t\t} else {\n\t\t\tconst node = itemOrPosition;\n\n\t\t\tif ( offset == 'end' ) {\n\t\t\t\toffset = node.is( 'text' ) ? node.data.length : node.childCount;\n\t\t\t} else if ( offset == 'before' ) {\n\t\t\t\treturn this._createBefore( node );\n\t\t\t} else if ( offset == 'after' ) {\n\t\t\t\treturn this._createAfter( node );\n\t\t\t} else if ( offset !== 0 && !offset ) {\n\t\t\t\t/**\n\t\t\t\t * {@link module:engine/view/view~View#createPositionAt `View#createPositionAt()`}\n\t\t\t\t * requires the offset to be specified when the first parameter is a view item.\n\t\t\t\t *\n\t\t\t\t * @error view-createPositionAt-offset-required\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'view-createPositionAt-offset-required: ' +\n\t\t\t\t\t'View#createPositionAt() requires the offset when the first parameter is a view item.',\n\t\t\t\t\tnode\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn new Position( node, offset );\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tstatic _createAfter( item ) {\n\t\t// TextProxy is not a instance of Node so we need do handle it in specific way.\n\t\tif ( item.is( 'textProxy' ) ) {\n\t\t\treturn new Position( item.textNode, item.offsetInText + item.data.length );\n\t\t}\n\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You can not make a position after a root.\n\t\t\t *\n\t\t\t * @error view-position-after-root\n\t\t\t * @param {module:engine/view/node~Node} root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-position-after-root: You can not make position after root.', item, { root: item } );\n\t\t}\n\n\t\treturn new Position( item.parent, item.index + 1 );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tstatic _createBefore( item ) {\n\t\t// TextProxy is not a instance of Node so we need do handle it in specific way.\n\t\tif ( item.is( 'textProxy' ) ) {\n\t\t\treturn new Position( item.textNode, item.offsetInText );\n\t\t}\n\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You cannot make a position before a root.\n\t\t\t *\n\t\t\t * @error view-position-before-root\n\t\t\t * @param {module:engine/view/node~Node} root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-position-before-root: You can not make position before root.', item, { root: item } );\n\t\t}\n\n\t\treturn new Position( item.parent, item.index );\n\t}\n}\n\n/**\n * A flag indicating whether this position is `'before'` or `'after'` or `'same'` as given position.\n * If positions are in different roots `'different'` flag is returned.\n *\n * @typedef {String} module:engine/view/position~PositionRelation\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/range\n */\n\nimport Position from './position';\nimport TreeWalker from './treewalker';\n\n/**\n * Range in the view tree. A range is represented by its start and end {@link module:engine/view/position~Position positions}.\n *\n * In order to create a new position instance use the `createPosition*()` factory methods available in:\n *\n * * {@link module:engine/view/view~View}\n * * {@link module:engine/view/downcastwriter~DowncastWriter}\n * * {@link module:engine/view/upcastwriter~UpcastWriter}\n */\nexport default class Range {\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** Constructor creates it's own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at the `start` position.\n\t */\n\tconstructor( start, end = null ) {\n\t\t/**\n\t\t * Start position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/position~Position}\n\t\t */\n\t\tthis.start = start.clone();\n\n\t\t/**\n\t\t * End position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/position~Position}\n\t\t */\n\t\tthis.end = end ? end.clone() : start.clone();\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all {@link module:engine/view/item~Item view items} that are in this range and returns\n\t * them together with additional information like length or {@link module:engine/view/position~Position positions},\n\t * grouped as {@link module:engine/view/treewalker~TreeWalkerValue}.\n\t *\n\t * This iterator uses {@link module:engine/view/treewalker~TreeWalker TreeWalker} with `boundaries` set to this range and\n\t * `ignoreElementEnd` option\n\t * set to `true`.\n\t *\n\t * @returns {Iterable.<module:engine/view/treewalker~TreeWalkerValue>}\n\t */\n\t* [ Symbol.iterator ]() {\n\t\tyield* new TreeWalker( { boundaries: this, ignoreElementEnd: true } );\n\t}\n\n\t/**\n\t * Returns whether the range is collapsed, that is it start and end positions are equal.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this.start.isEqual( this.end );\n\t}\n\n\t/**\n\t * Returns whether this range is flat, that is if {@link module:engine/view/range~Range#start start} position and\n\t * {@link module:engine/view/range~Range#end end} position are in the same {@link module:engine/view/position~Position#parent parent}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isFlat() {\n\t\treturn this.start.parent === this.end.parent;\n\t}\n\n\t/**\n\t * Range root element.\n\t *\n\t * @type {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.start.root;\n\t}\n\n\t/**\n\t * Creates a maximal range that has the same content as this range but is expanded in both ways (at the beginning\n\t * and at the end).\n\t *\n\t * For example:\n\t *\n\t *\t\t<p>Foo</p><p><b>{Bar}</b></p> -> <p>Foo</p>[<p><b>Bar</b>]</p>\n\t *\t\t<p><b>foo</b>{bar}<span></span></p> -> <p><b>foo[</b>bar<span></span>]</p>\n\t *\n\t * Note that in the sample above:\n\t *\n\t * - `<p>` have type of {@link module:engine/view/containerelement~ContainerElement},\n\t * - `<b>` have type of {@link module:engine/view/attributeelement~AttributeElement},\n\t * - `<span>` have type of {@link module:engine/view/uielement~UIElement}.\n\t *\n\t * @returns {module:engine/view/range~Range} Enlarged range.\n\t */\n\tgetEnlarged() {\n\t\tlet start = this.start.getLastMatchingPosition( enlargeTrimSkip, { direction: 'backward' } );\n\t\tlet end = this.end.getLastMatchingPosition( enlargeTrimSkip );\n\n\t\t// Fix positions, in case if they are in Text node.\n\t\tif ( start.parent.is( 'text' ) && start.isAtStart ) {\n\t\t\tstart = Position._createBefore( start.parent );\n\t\t}\n\n\t\tif ( end.parent.is( 'text' ) && end.isAtEnd ) {\n\t\t\tend = Position._createAfter( end.parent );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a minimum range that has the same content as this range but is trimmed in both ways (at the beginning\n\t * and at the end).\n\t *\n\t * For example:\n\t *\n\t *\t\t<p>Foo</p>[<p><b>Bar</b>]</p> -> <p>Foo</p><p><b>{Bar}</b></p>\n\t *\t\t<p><b>foo[</b>bar<span></span>]</p> -> <p><b>foo</b>{bar}<span></span></p>\n\t *\n\t * Note that in the sample above:\n\t *\n\t * - `<p>` have type of {@link module:engine/view/containerelement~ContainerElement},\n\t * - `<b>` have type of {@link module:engine/view/attributeelement~AttributeElement},\n\t * - `<span>` have type of {@link module:engine/view/uielement~UIElement}.\n\t *\n\t * @returns {module:engine/view/range~Range} Shrink range.\n\t */\n\tgetTrimmed() {\n\t\tlet start = this.start.getLastMatchingPosition( enlargeTrimSkip );\n\n\t\tif ( start.isAfter( this.end ) || start.isEqual( this.end ) ) {\n\t\t\treturn new Range( start, start );\n\t\t}\n\n\t\tlet end = this.end.getLastMatchingPosition( enlargeTrimSkip, { direction: 'backward' } );\n\t\tconst nodeAfterStart = start.nodeAfter;\n\t\tconst nodeBeforeEnd = end.nodeBefore;\n\n\t\t// Because TreeWalker prefers positions next to text node, we need to move them manually into these text nodes.\n\t\tif ( nodeAfterStart && nodeAfterStart.is( 'text' ) ) {\n\t\t\tstart = new Position( nodeAfterStart, 0 );\n\t\t}\n\n\t\tif ( nodeBeforeEnd && nodeBeforeEnd.is( 'text' ) ) {\n\t\t\tend = new Position( nodeBeforeEnd, nodeBeforeEnd.data.length );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Two ranges are equal if their start and end positions are equal.\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges are equal, `false` otherwise\n\t */\n\tisEqual( otherRange ) {\n\t\treturn this == otherRange || ( this.start.isEqual( otherRange.start ) && this.end.isEqual( otherRange.end ) );\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link module:engine/view/position~Position position}.\n\t *\n\t * @param {module:engine/view/position~Position} position Position to check.\n\t * @returns {Boolean} `true` if given {@link module:engine/view/position~Position position} is contained in this range,\n\t * `false` otherwise.\n\t */\n\tcontainsPosition( position ) {\n\t\treturn position.isAfter( this.start ) && position.isBefore( this.end );\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link module:engine/view/range~Range range}.\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to check.\n\t * @param {Boolean} [loose=false] Whether the check is loose or strict. If the check is strict (`false`), compared range cannot\n\t * start or end at the same position as this range boundaries. If the check is loose (`true`), compared range can start, end or\n\t * even be equal to this range. Note that collapsed ranges are always compared in strict mode.\n\t * @returns {Boolean} `true` if given {@link module:engine/view/range~Range range} boundaries are contained by this range, `false`\n\t * otherwise.\n\t */\n\tcontainsRange( otherRange, loose = false ) {\n\t\tif ( otherRange.isCollapsed ) {\n\t\t\tloose = false;\n\t\t}\n\n\t\tconst containsStart = this.containsPosition( otherRange.start ) || ( loose && this.start.isEqual( otherRange.start ) );\n\t\tconst containsEnd = this.containsPosition( otherRange.end ) || ( loose && this.end.isEqual( otherRange.end ) );\n\n\t\treturn containsStart && containsEnd;\n\t}\n\n\t/**\n\t * Computes which part(s) of this {@link module:engine/view/range~Range range} is not a part of given\n\t * {@link module:engine/view/range~Range range}.\n\t * Returned array contains zero, one or two {@link module:engine/view/range~Range ranges}.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet foo = downcastWriter.createText( 'foo' );\n\t *\t\tlet img = downcastWriter.createContainerElement( 'img' );\n\t *\t\tlet bar = downcastWriter.createText( 'bar' );\n\t *\t\tlet p = downcastWriter.createContainerElement( 'p', null, [ foo, img, bar ] );\n\t *\n\t *\t\tlet range = view.createRange( view.createPositionAt( foo, 2 ), view.createPositionAt( bar, 1 ); // \"o\", img, \"b\" are in range.\n\t *\t\tlet otherRange = view.createRange( // \"oo\", img, \"ba\" are in range.\n\t *\t\t\tview.createPositionAt( foo, 1 ),\n\t *\t\t\tview.createPositionAt( bar, 2 )\n\t *\t\t);\n\t *\t\tlet transformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has no ranges because `otherRange` contains `range`\n\t *\n\t *\t\totherRange = view.createRange( view.createPositionAt( foo, 1 ), view.createPositionAt( p, 2 ); // \"oo\", img are in range.\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has one range: from ( p, 2 ) to ( bar, 1 )\n\t *\n\t *\t\totherRange = view.createRange( view.createPositionAt( p, 1 ), view.createPositionAt( p, 2 ) ); // img is in range.\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has two ranges: from ( foo, 1 ) to ( p, 1 ) and from ( p, 2 ) to ( bar, 1 )\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to differentiate against.\n\t * @returns {Array.<module:engine/view/range~Range>} The difference between ranges.\n\t */\n\tgetDifference( otherRange ) {\n\t\tconst ranges = [];\n\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect.\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the start to the middle of this range.\n\t\t\t\tranges.push( new Range( this.start, otherRange.start ) );\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the middle of this range to the end.\n\t\t\t\tranges.push( new Range( otherRange.end, this.end ) );\n\t\t\t}\n\t\t} else {\n\t\t\t// Ranges do not intersect, return the original range.\n\t\t\tranges.push( this.clone() );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an intersection of this {@link module:engine/view/range~Range range} and given {@link module:engine/view/range~Range range}.\n\t * Intersection is a common part of both of those ranges. If ranges has no common part, returns `null`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet foo = downcastWriter.createText( 'foo' );\n\t *\t\tlet img = downcastWriter.createContainerElement( 'img' );\n\t *\t\tlet bar = downcastWriter.createText( 'bar' );\n\t *\t\tlet p = downcastWriter.createContainerElement( 'p', null, [ foo, img, bar ] );\n\t *\n\t *\t\tlet range = view.createRange( view.createPositionAt( foo, 2 ), view.createPositionAt( bar, 1 ); // \"o\", img, \"b\" are in range.\n\t *\t\tlet otherRange = view.createRange( view.createPositionAt( foo, 1 ), view.createPositionAt( p, 2 ); // \"oo\", img are in range.\n\t *\t\tlet transformed = range.getIntersection( otherRange ); // range from ( foo, 1 ) to ( p, 2 ).\n\t *\n\t *\t\totherRange = view.createRange( view.createPositionAt( bar, 1 ), view.createPositionAt( bar, 3 ); \"ar\" is in range.\n\t *\t\ttransformed = range.getIntersection( otherRange ); // null - no common part.\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to check for intersection.\n\t * @returns {module:engine/view/range~Range|null} A common part of given ranges or `null` if ranges have no common part.\n\t */\n\tgetIntersection( otherRange ) {\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect, so a common range will be returned.\n\t\t\t// At most, it will be same as this range.\n\t\t\tlet commonRangeStart = this.start;\n\t\t\tlet commonRangeEnd = this.end;\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means thaNt we have to\n\t\t\t\t// shrink common range to the given range start.\n\t\t\t\tcommonRangeStart = otherRange.start;\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// shrink common range to the given range end.\n\t\t\t\tcommonRangeEnd = otherRange.end;\n\t\t\t}\n\n\t\t\treturn new Range( commonRangeStart, commonRangeEnd );\n\t\t}\n\n\t\t// Ranges do not intersect, so they do not have common part.\n\t\treturn null;\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/view/treewalker~TreeWalker TreeWalker} instance with this range as a boundary.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t * @param {module:engine/view/position~Position} [options.startPosition]\n\t * @param {Boolean} [options.singleCharacters=false]\n\t * @param {Boolean} [options.shallow=false]\n\t * @param {Boolean} [options.ignoreElementEnd=false]\n\t * @returns {module:engine/view/treewalker~TreeWalker}\n\t */\n\tgetWalker( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\treturn new TreeWalker( options );\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/view/node~Node} or {@link module:engine/view/documentfragment~DocumentFragment}\n\t * which is a common ancestor of range's both ends (in which the entire range is contained).\n\t *\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor() {\n\t\treturn this.start.getCommonAncestor( this.end );\n\t}\n\n\t/**\n\t * Clones this range.\n\t *\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tclone() {\n\t\treturn new Range( this.start, this.end );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/view/item~Item view items} that are in this range and returns\n\t * them.\n\t *\n\t * This method uses {@link module:engine/view/treewalker~TreeWalker} with `boundaries` set to this range and `ignoreElementEnd` option\n\t * set to `true`. However it returns only {@link module:engine/view/item~Item items},\n\t * not {@link module:engine/view/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/view/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t * @returns {Iterable.<module:engine/view/item~Item>}\n\t */\n\t* getItems( options = {} ) {\n\t\toptions.boundaries = this;\n\t\toptions.ignoreElementEnd = true;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.item;\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/view/position~Position positions} that are boundaries or\n\t * contained in this range.\n\t *\n\t * This method uses {@link module:engine/view/treewalker~TreeWalker} with `boundaries` set to this range. However it returns only\n\t * {@link module:engine/view/position~Position positions}, not {@link module:engine/view/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/view/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t * @returns {Iterable.<module:engine/view/position~Position>}\n\t */\n\t* getPositions( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tyield treeWalker.position;\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.nextPosition;\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\trange.is( 'range' ); // -> true\n\t *\t\trange.is( 'view:range' ); // -> true\n\t *\n\t *\t\trange.is( 'model:range' ); // -> false\n\t *\t\trange.is( 'element' ); // -> false\n\t *\t\trange.is( 'selection' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'range' || type == 'view:range';\n\t}\n\n\t/**\n\t * Checks and returns whether this range intersects with the given range.\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} True if ranges intersect.\n\t */\n\tisIntersecting( otherRange ) {\n\t\treturn this.start.isBefore( otherRange.end ) && this.end.isAfter( otherRange.start );\n\t}\n\n\t/**\n\t * Creates a range from the given parents and offsets.\n\t *\n\t * @protected\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} startElement Start position\n\t * parent element.\n\t * @param {Number} startOffset Start position offset.\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} endElement End position\n\t * parent element.\n\t * @param {Number} endOffset End position offset.\n\t * @returns {module:engine/view/range~Range} Created range.\n\t */\n\tstatic _createFromParentsAndOffsets( startElement, startOffset, endElement, endOffset ) {\n\t\treturn new this(\n\t\t\tnew Position( startElement, startOffset ),\n\t\t\tnew Position( endElement, endOffset )\n\t\t);\n\t}\n\n\t/**\n\t * Creates a new range, spreading from specified {@link module:engine/view/position~Position position} to a position moved by\n\t * given `shift`. If `shift` is a negative value, shifted position is treated as the beginning of the range.\n\t *\n\t * @protected\n\t * @param {module:engine/view/position~Position} position Beginning of the range.\n\t * @param {Number} shift How long the range should be.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tstatic _createFromPositionAndShift( position, shift ) {\n\t\tconst start = position;\n\t\tconst end = position.getShiftedBy( shift );\n\n\t\treturn shift > 0 ? new this( start, end ) : new this( end, start );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @protected\n\t * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tstatic _createIn( element ) {\n\t\treturn this._createFromParentsAndOffsets( element, 0, element, element.childCount );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tstatic _createOn( item ) {\n\t\tconst size = item.is( 'textProxy' ) ? item.offsetSize : 1;\n\n\t\treturn this._createFromPositionAndShift( Position._createBefore( item ), size );\n\t}\n}\n\n// Function used by getEnlarged and getTrimmed methods.\nfunction enlargeTrimSkip( value ) {\n\tif ( value.item.is( 'attributeElement' ) || value.item.is( 'uiElement' ) ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/count\n */\n\n/**\n * Returns the number of items return by the iterator.\n *\n *\t\tcount( [ 1, 2, 3, 4, 5 ] ); // 5;\n *\n * @param {Iterable.<*>} iterator Any iterator.\n * @returns {Number} Number of items returned by that iterator.\n */\nexport default function count( iterator ) {\n\tlet count = 0;\n\n\tfor ( const _ of iterator ) { // eslint-disable-line no-unused-vars\n\t\tcount++;\n\t}\n\n\treturn count;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/selection\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Range from './range';\nimport Position from './position';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport Node from './node';\nimport Element from './element';\nimport count from '@ckeditor/ckeditor5-utils/src/count';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport DocumentSelection from './documentselection';\n\n/**\n * Class representing an arbirtary selection in the view.\n * See also {@link module:engine/view/documentselection~DocumentSelection}.\n *\n * New selection instances can be created via the constructor or one these methods:\n *\n * * {@link module:engine/view/view~View#createSelection `View#createSelection()`},\n * * {@link module:engine/view/upcastwriter~UpcastWriter#createSelection `UpcastWriter#createSelection()`}.\n *\n * A selection can consist of {@link module:engine/view/range~Range ranges} that can be set by using\n * the {@link module:engine/view/selection~Selection#setTo `Selection#setTo()`} method.\n */\nexport default class Selection {\n\t/**\n\t * Creates new selection instance.\n\t *\n\t * **Note**: The selection constructor is available as a factory method:\n\t *\n\t * * {@link module:engine/view/view~View#createSelection `View#createSelection()`},\n\t * * {@link module:engine/view/upcastwriter~UpcastWriter#createSelection `UpcastWriter#createSelection()`}.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = writer.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = writer.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tconstructor( selectable = null, placeOrOffset, options ) {\n\t\t/**\n\t\t * Stores all ranges that are selected.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.<module:engine/view/range~Range>}\n\t\t */\n\t\tthis._ranges = [];\n\n\t\t/**\n\t\t * Specifies whether the last added range was added as a backward or forward range.\n\t\t *\n\t\t * @protected\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._lastRangeBackward = false;\n\n\t\t/**\n\t\t * Specifies whether selection instance is fake.\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._isFake = false;\n\n\t\t/**\n\t\t * Fake selection's label.\n\t\t *\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._fakeSelectionLabel = '';\n\n\t\tthis.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Returns true if selection instance is marked as `fake`.\n\t *\n\t * @see #setTo\n\t * @returns {Boolean}\n\t */\n\tget isFake() {\n\t\treturn this._isFake;\n\t}\n\n\t/**\n\t * Returns fake selection label.\n\t *\n\t * @see #setTo\n\t * @returns {String}\n\t */\n\tget fakeSelectionLabel() {\n\t\treturn this._fakeSelectionLabel;\n\t}\n\n\t/**\n\t * Selection anchor. Anchor may be described as a position where the selection starts. Together with\n\t * {@link #focus focus} they define the direction of selection, which is important\n\t * when expanding/shrinking selection. Anchor is always the start or end of the most recent added range.\n\t * It may be a bit unintuitive when there are multiple ranges in selection.\n\t *\n\t * @see #focus\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget anchor() {\n\t\tif ( !this._ranges.length ) {\n\t\t\treturn null;\n\t\t}\n\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\t\tconst anchor = this._lastRangeBackward ? range.end : range.start;\n\n\t\treturn anchor.clone();\n\t}\n\n\t/**\n\t * Selection focus. Focus is a position where the selection ends.\n\t *\n\t * @see #anchor\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget focus() {\n\t\tif ( !this._ranges.length ) {\n\t\t\treturn null;\n\t\t}\n\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\t\tconst focus = this._lastRangeBackward ? range.start : range.end;\n\n\t\treturn focus.clone();\n\t}\n\n\t/**\n\t * Returns whether the selection is collapsed. Selection is collapsed when there is exactly one range which is\n\t * collapsed.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this.rangeCount === 1 && this._ranges[ 0 ].isCollapsed;\n\t}\n\n\t/**\n\t * Returns number of ranges in selection.\n\t *\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._ranges.length;\n\t}\n\n\t/**\n\t * Specifies whether the {@link #focus} precedes {@link #anchor}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn !this.isCollapsed && this._lastRangeBackward;\n\t}\n\n\t/**\n\t * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this selection, or `null`\n\t * if the selection is not inside an editable element.\n\t *\n\t * @type {module:engine/view/editableelement~EditableElement|null}\n\t */\n\tget editableElement() {\n\t\tif ( this.anchor ) {\n\t\t\treturn this.anchor.editableElement;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns an iterable that contains copies of all ranges added to the selection.\n\t *\n\t * @returns {Iterable.<module:engine/view/range~Range>}\n\t */\n\t* getRanges() {\n\t\tfor ( const range of this._ranges ) {\n\t\t\tyield range.clone();\n\t\t}\n\t}\n\n\t/**\n\t * Returns copy of the first range in the selection. First range is the one which\n\t * {@link module:engine/view/range~Range#start start} position {@link module:engine/view/position~Position#isBefore is before} start\n\t * position of all other ranges (not to confuse with the first range added to the selection).\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\tlet first = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !first || range.start.isBefore( first.start ) ) {\n\t\t\t\tfirst = range;\n\t\t\t}\n\t\t}\n\n\t\treturn first ? first.clone() : null;\n\t}\n\n\t/**\n\t * Returns copy of the last range in the selection. Last range is the one which {@link module:engine/view/range~Range#end end}\n\t * position {@link module:engine/view/position~Position#isAfter is after} end position of all other ranges (not to confuse\n\t * with the last range added to the selection). Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\tlet last = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !last || range.end.isAfter( last.end ) ) {\n\t\t\t\tlast = range;\n\t\t\t}\n\t\t}\n\n\t\treturn last ? last.clone() : null;\n\t}\n\n\t/**\n\t * Returns copy of the first position in the selection. First position is the position that\n\t * {@link module:engine/view/position~Position#isBefore is before} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\tconst firstRange = this.getFirstRange();\n\n\t\treturn firstRange ? firstRange.start.clone() : null;\n\t}\n\n\t/**\n\t * Returns copy of the last position in the selection. Last position is the position that\n\t * {@link module:engine/view/position~Position#isAfter is after} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\tconst lastRange = this.getLastRange();\n\n\t\treturn lastRange ? lastRange.end.clone() : null;\n\t}\n\n\t/**\n\t * Checks whether, this selection is equal to given selection. Selections are equal if they have same directions,\n\t * same number of ranges and all ranges from one selection equal to a range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are equal, `false` otherwise.\n\t */\n\tisEqual( otherSelection ) {\n\t\tif ( this.isFake != otherSelection.isFake ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this.isFake && this.fakeSelectionLabel != otherSelection.fakeSelectionLabel ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this.rangeCount != otherSelection.rangeCount ) {\n\t\t\treturn false;\n\t\t} else if ( this.rangeCount === 0 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ( !this.anchor.isEqual( otherSelection.anchor ) || !this.focus.isEqual( otherSelection.focus ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor ( const thisRange of this._ranges ) {\n\t\t\tlet found = false;\n\n\t\t\tfor ( const otherRange of otherSelection._ranges ) {\n\t\t\t\tif ( thisRange.isEqual( otherRange ) ) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( !found ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks whether this selection is similar to given selection. Selections are similar if they have same directions, same\n\t * number of ranges, and all {@link module:engine/view/range~Range#getTrimmed trimmed} ranges from one selection are\n\t * equal to any trimmed range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are similar, `false` otherwise.\n\t */\n\tisSimilar( otherSelection ) {\n\t\tif ( this.isBackward != otherSelection.isBackward ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst numOfRangesA = count( this.getRanges() );\n\t\tconst numOfRangesB = count( otherSelection.getRanges() );\n\n\t\t// If selections have different number of ranges, they cannot be similar.\n\t\tif ( numOfRangesA != numOfRangesB ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If both selections have no ranges, they are similar.\n\t\tif ( numOfRangesA == 0 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check if each range in one selection has a similar range in other selection.\n\t\tfor ( let rangeA of this.getRanges() ) {\n\t\t\trangeA = rangeA.getTrimmed();\n\n\t\t\tlet found = false;\n\n\t\t\tfor ( let rangeB of otherSelection.getRanges() ) {\n\t\t\t\trangeB = rangeB.getTrimmed();\n\n\t\t\t\tif ( rangeA.start.isEqual( rangeB.start ) && rangeA.end.isEqual( rangeB.end ) ) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// For `rangeA`, neither range in `otherSelection` was similar. So selections are not similar.\n\t\t\tif ( !found ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// There were no ranges that weren't matched. Selections are similar.\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/view/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/view/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\tif ( this.rangeCount !== 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst range = this.getFirstRange();\n\n\t\tlet nodeAfterStart = range.start.nodeAfter;\n\t\tlet nodeBeforeEnd = range.end.nodeBefore;\n\n\t\t// Handle the situation when selection position is at the beginning / at the end of a text node.\n\t\t// In such situation `.nodeAfter` and `.nodeBefore` are `null` but the selection still might be spanning\n\t\t// over one element.\n\t\t//\n\t\t// <p>Foo{<span class=\"widget\"></span>}bar</p> vs <p>Foo[<span class=\"widget\"></span>]bar</p>\n\t\t//\n\t\t// These are basically the same selections, only the difference is if the selection position is at\n\t\t// at the end/at the beginning of a text node or just before/just after the text node.\n\t\t//\n\t\tif ( range.start.parent.is( 'text' ) && range.start.isAtEnd && range.start.parent.nextSibling ) {\n\t\t\tnodeAfterStart = range.start.parent.nextSibling;\n\t\t}\n\n\t\tif ( range.end.parent.is( 'text' ) && range.end.isAtStart && range.end.parent.previousSibling ) {\n\t\t\tnodeBeforeEnd = range.end.parent.previousSibling;\n\t\t}\n\n\t\treturn ( nodeAfterStart instanceof Element && nodeAfterStart == nodeBeforeEnd ) ? nodeAfterStart : null;\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/view/selection~Selectable selectable}.\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tselection.setTo( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tselection.setTo( range );\n\t *\n\t *\t\t// Sets selection to the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tselection.setTo( otherSelection );\n\t *\n\t *\t \t// Sets selection to contents of DocumentSelection.\n\t *\t\tselection.setTo( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionAt( root, path );\n\t *\t\tselection.setTo( position );\n\t *\n\t * \t\t// Sets collapsed selection at the position of given item and offset.\n\t *\t\tselection.setTo( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t *\t\tselection.setTo( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\tselection.setTo( paragraph, 'on' );\n\t *\n\t * \t\t// Clears selection. Removes all ranges.\n\t *\t\tselection.setTo( null );\n\t *\n\t * `Selection#setTo()` method allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\tselection.setTo( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tselection.setTo( range, { fake: true, label: 'foo' } );\n\t *\n\t * @fires change\n\t * @param {module:engine/view/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tsetTo( selectable, placeOrOffset, options ) {\n\t\tif ( selectable === null ) {\n\t\t\tthis._setRanges( [] );\n\t\t\tthis._setFakeOptions( placeOrOffset );\n\t\t} else if ( selectable instanceof Selection || selectable instanceof DocumentSelection ) {\n\t\t\tthis._setRanges( selectable.getRanges(), selectable.isBackward );\n\t\t\tthis._setFakeOptions( { fake: selectable.isFake, label: selectable.fakeSelectionLabel } );\n\t\t} else if ( selectable instanceof Range ) {\n\t\t\tthis._setRanges( [ selectable ], placeOrOffset && placeOrOffset.backward );\n\t\t\tthis._setFakeOptions( placeOrOffset );\n\t\t} else if ( selectable instanceof Position ) {\n\t\t\tthis._setRanges( [ new Range( selectable ) ] );\n\t\t\tthis._setFakeOptions( placeOrOffset );\n\t\t} else if ( selectable instanceof Node ) {\n\t\t\tconst backward = !!options && !!options.backward;\n\t\t\tlet range;\n\n\t\t\tif ( placeOrOffset === undefined ) {\n\t\t\t\t/**\n\t\t\t\t * selection.setTo requires the second parameter when the first parameter is a node.\n\t\t\t\t *\n\t\t\t\t * @error view-selection-setTo-required-second-parameter\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'view-selection-setTo-required-second-parameter: ' +\n\t\t\t\t\t'selection.setTo requires the second parameter when the first parameter is a node.',\n\t\t\t\t\tthis\n\t\t\t\t);\n\t\t\t} else if ( placeOrOffset == 'in' ) {\n\t\t\t\trange = Range._createIn( selectable );\n\t\t\t} else if ( placeOrOffset == 'on' ) {\n\t\t\t\trange = Range._createOn( selectable );\n\t\t\t} else {\n\t\t\t\trange = new Range( Position._createAt( selectable, placeOrOffset ) );\n\t\t\t}\n\n\t\t\tthis._setRanges( [ range ], backward );\n\t\t\tthis._setFakeOptions( options );\n\t\t} else if ( isIterable( selectable ) ) {\n\t\t\t// We assume that the selectable is an iterable of ranges.\n\t\t\t// Array.from() is used to prevent setting ranges to the old iterable\n\t\t\tthis._setRanges( selectable, placeOrOffset && placeOrOffset.backward );\n\t\t\tthis._setFakeOptions( placeOrOffset );\n\t\t} else {\n\t\t\t/**\n\t\t\t * Cannot set selection to given place.\n\t\t\t *\n\t\t\t * @error view-selection-setTo-not-selectable\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-selection-setTo-not-selectable: Cannot set selection to given place.', this );\n\t\t}\n\n\t\tthis.fire( 'change' );\n\t}\n\n\t/**\n\t * Moves {@link #focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}\n\t * parameters.\n\t *\n\t * @fires change\n\t * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tsetFocus( itemOrPosition, offset ) {\n\t\tif ( this.anchor === null ) {\n\t\t\t/**\n\t\t\t * Cannot set selection focus if there are no ranges in selection.\n\t\t\t *\n\t\t\t * @error view-selection-setFocus-no-ranges\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-selection-setFocus-no-ranges: Cannot set selection focus if there are no ranges in selection.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tconst newFocus = Position._createAt( itemOrPosition, offset );\n\n\t\tif ( newFocus.compareWith( this.focus ) == 'same' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst anchor = this.anchor;\n\n\t\tthis._ranges.pop();\n\n\t\tif ( newFocus.compareWith( anchor ) == 'before' ) {\n\t\t\tthis._addRange( new Range( newFocus, anchor ), true );\n\t\t} else {\n\t\t\tthis._addRange( new Range( anchor, newFocus ) );\n\t\t}\n\n\t\tthis.fire( 'change' );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tselection.is( 'selection' ); // -> true\n\t *\t\tselection.is( 'view:selection' ); // -> true\n\t *\n\t *\t\tselection.is( 'model:selection' ); // -> false\n\t *\t\tselection.is( 'element' ); // -> false\n\t *\t\tselection.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'selection' || type == 'view:selection';\n\t}\n\n\t/**\n\t * Replaces all ranges that were added to the selection with given array of ranges. Last range of the array\n\t * is treated like the last added range and is used to set {@link #anchor anchor} and {@link #focus focus}.\n\t * Accepts a flag describing in which way the selection is made.\n\t *\n\t * @private\n\t * @param {Iterable.<module:engine/view/range~Range>} newRanges Iterable object of ranges to set.\n\t * @param {Boolean} [isLastBackward=false] Flag describing if last added range was selected forward - from start to end\n\t * (`false`) or backward - from end to start (`true`). Defaults to `false`.\n\t */\n\t_setRanges( newRanges, isLastBackward = false ) {\n\t\t// New ranges should be copied to prevent removing them by setting them to `[]` first.\n\t\t// Only applies to situations when selection is set to the same selection or same selection's ranges.\n\t\tnewRanges = Array.from( newRanges );\n\n\t\tthis._ranges = [];\n\n\t\tfor ( const range of newRanges ) {\n\t\t\tthis._addRange( range );\n\t\t}\n\n\t\tthis._lastRangeBackward = !!isLastBackward;\n\t}\n\n\t/**\n\t * Sets this selection instance to be marked as `fake`. A fake selection does not render as browser native selection\n\t * over selected elements and is hidden to the user. This way, no native selection UI artifacts are displayed to\n\t * the user and selection over elements can be represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM (and be\n\t * properly handled by screen readers).\n\t *\n\t * @private\n\t * @param {Object} [options] Options.\n\t * @param {Boolean} [options.fake] If set to true selection will be marked as `fake`.\n\t * @param {String} [options.label=''] Fake selection label.\n\t */\n\t_setFakeOptions( options = {} ) {\n\t\tthis._isFake = !!options.fake;\n\t\tthis._fakeSelectionLabel = options.fake ? options.label || '' : '';\n\t}\n\n\t/**\n\t * Adds a range to the selection. Added range is copied. This means that passed range is not saved in the\n\t * selection instance and you can safely operate on it.\n\t *\n\t * Accepts a flag describing in which way the selection is made - passed range might be selected from\n\t * {@link module:engine/view/range~Range#start start} to {@link module:engine/view/range~Range#end end}\n\t * or from {@link module:engine/view/range~Range#end end} to {@link module:engine/view/range~Range#start start}.\n\t * The flag is used to set {@link #anchor anchor} and {@link #focus focus} properties.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-selection-range-intersects` if added range intersects\n\t * with ranges already stored in Selection instance.\n\t *\n\t * @private\n\t * @fires change\n\t * @param {module:engine/view/range~Range} range\n\t * @param {Boolean} [isBackward]\n\t */\n\t_addRange( range, isBackward = false ) {\n\t\tif ( !( range instanceof Range ) ) {\n\t\t\t/**\n\t\t\t * Selection range set to an object that is not an instance of {@link module:engine/view/range~Range}.\n\t\t\t *\n\t\t\t * @error view-selection-add-range-not-range\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-selection-add-range-not-range: ' +\n\t\t\t\t'Selection range set to an object that is not an instance of view.Range',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tthis._pushRange( range );\n\t\tthis._lastRangeBackward = !!isBackward;\n\t}\n\n\t/**\n\t * Adds range to selection - creates copy of given range so it can be safely used and modified.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-selection-range-intersects` if added range intersects\n\t * with ranges already stored in selection instance.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range\n\t */\n\t_pushRange( range ) {\n\t\tfor ( const storedRange of this._ranges ) {\n\t\t\tif ( range.isIntersecting( storedRange ) ) {\n\t\t\t\t/**\n\t\t\t\t * Trying to add a range that intersects with another range from selection.\n\t\t\t\t *\n\t\t\t\t * @error view-selection-range-intersects\n\t\t\t\t * @param {module:engine/view/range~Range} addedRange Range that was added to the selection.\n\t\t\t\t * @param {module:engine/view/range~Range} intersectingRange Range from selection that intersects with `addedRange`.\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'view-selection-range-intersects: Trying to add a range that intersects with another range from selection.',\n\t\t\t\t\tthis,\n\t\t\t\t\t{ addedRange: range, intersectingRange: storedRange }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tthis._ranges.push( new Range( range.start, range.end ) );\n\t}\n\n\t/**\n\t * Fired whenever selection ranges are changed through {@link ~Selection Selection API}.\n\t *\n\t * @event change\n\t */\n}\n\nmix( Selection, EmitterMixin );\n\n/**\n * An entity that is used to set selection.\n *\n * See also {@link module:engine/view/selection~Selection#setTo}\n *\n * @typedef {\n * module:engine/view/selection~Selection|\n * module:engine/view/documentselection~DocumentSelection|\n * module:engine/view/position~Position|\n * Iterable.<module:engine/view/range~Range>|\n * module:engine/view/range~Range|\n * module:engine/view/item~Item|\n * null\n * } module:engine/view/selection~Selectable\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/documentselection\n */\n\nimport Selection from './selection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\n\n/**\n * Class representing the document selection in the view.\n *\n * Its instance is available in {@link module:engine/view/document~Document#selection `Document#selection`}.\n *\n * It is similar to {@link module:engine/view/selection~Selection} but\n * it has a read-only API and can be modified only by the writer available in\n * the {@link module:engine/view/view~View#change `View#change()`} block\n * (so via {@link module:engine/view/downcastwriter~DowncastWriter#setSelection `DowncastWriter#setSelection()`}).\n */\nexport default class DocumentSelection {\n\t/**\n\t * Creates new DocumentSelection instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = new DocumentSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = new DocumentSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];\n\t *\t\tconst selection = new DocumentSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = new DocumentSelection( otherSelection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionAt( root, offset );\n\t *\t\tconst selection = new DocumentSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = new DocumentSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = new DocumentSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = new DocumentSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = new DocumentSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = new DocumentSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tconstructor( selectable = null, placeOrOffset, options ) {\n\t\t/**\n\t\t * Selection is used internally (`DocumentSelection` is a proxy to that selection).\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/selection~Selection}\n\t\t */\n\t\tthis._selection = new Selection();\n\n\t\t// Delegate change event to be fired on DocumentSelection instance.\n\t\tthis._selection.delegate( 'change' ).to( this );\n\n\t\t// Set selection data.\n\t\tthis._selection.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Returns true if selection instance is marked as `fake`.\n\t *\n\t * @see #_setTo\n\t * @returns {Boolean}\n\t */\n\tget isFake() {\n\t\treturn this._selection.isFake;\n\t}\n\n\t/**\n\t * Returns fake selection label.\n\t *\n\t * @see #_setTo\n\t * @returns {String}\n\t */\n\tget fakeSelectionLabel() {\n\t\treturn this._selection.fakeSelectionLabel;\n\t}\n\n\t/**\n\t * Selection anchor. Anchor may be described as a position where the selection starts. Together with\n\t * {@link #focus focus} they define the direction of selection, which is important\n\t * when expanding/shrinking selection. Anchor is always the start or end of the most recent added range.\n\t * It may be a bit unintuitive when there are multiple ranges in selection.\n\t *\n\t * @see #focus\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget anchor() {\n\t\treturn this._selection.anchor;\n\t}\n\n\t/**\n\t * Selection focus. Focus is a position where the selection ends.\n\t *\n\t * @see #anchor\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget focus() {\n\t\treturn this._selection.focus;\n\t}\n\n\t/**\n\t * Returns whether the selection is collapsed. Selection is collapsed when there is exactly one range which is\n\t * collapsed.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this._selection.isCollapsed;\n\t}\n\n\t/**\n\t * Returns number of ranges in selection.\n\t *\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._selection.rangeCount;\n\t}\n\n\t/**\n\t * Specifies whether the {@link #focus} precedes {@link #anchor}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn this._selection.isBackward;\n\t}\n\n\t/**\n\t * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this selection, or `null`\n\t * if the selection is not inside an editable element.\n\t *\n\t * @type {module:engine/view/editableelement~EditableElement|null}\n\t */\n\tget editableElement() {\n\t\treturn this._selection.editableElement;\n\t}\n\n\t/**\n\t * Used for the compatibility with the {@link module:engine/view/selection~Selection#isEqual} method.\n\t *\n\t * @protected\n\t */\n\tget _ranges() {\n\t\treturn this._selection._ranges;\n\t}\n\n\t/**\n\t * Returns an iterable that contains copies of all ranges added to the selection.\n\t *\n\t * @returns {Iterable.<module:engine/view/range~Range>}\n\t */\n\t* getRanges() {\n\t\tyield* this._selection.getRanges();\n\t}\n\n\t/**\n\t * Returns copy of the first range in the selection. First range is the one which\n\t * {@link module:engine/view/range~Range#start start} position {@link module:engine/view/position~Position#isBefore is before} start\n\t * position of all other ranges (not to confuse with the first range added to the selection).\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\treturn this._selection.getFirstRange();\n\t}\n\n\t/**\n\t * Returns copy of the last range in the selection. Last range is the one which {@link module:engine/view/range~Range#end end}\n\t * position {@link module:engine/view/position~Position#isAfter is after} end position of all other ranges (not to confuse\n\t * with the last range added to the selection). Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\treturn this._selection.getLastRange();\n\t}\n\n\t/**\n\t * Returns copy of the first position in the selection. First position is the position that\n\t * {@link module:engine/view/position~Position#isBefore is before} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\treturn this._selection.getFirstPosition();\n\t}\n\n\t/**\n\t * Returns copy of the last position in the selection. Last position is the position that\n\t * {@link module:engine/view/position~Position#isAfter is after} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\treturn this._selection.getLastPosition();\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/view/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/view/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\treturn this._selection.getSelectedElement();\n\t}\n\n\t/**\n\t * Checks whether, this selection is equal to given selection. Selections are equal if they have same directions,\n\t * same number of ranges and all ranges from one selection equal to a range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are equal, `false` otherwise.\n\t */\n\tisEqual( otherSelection ) {\n\t\treturn this._selection.isEqual( otherSelection );\n\t}\n\n\t/**\n\t * Checks whether this selection is similar to given selection. Selections are similar if they have same directions, same\n\t * number of ranges, and all {@link module:engine/view/range~Range#getTrimmed trimmed} ranges from one selection are\n\t * equal to any trimmed range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are similar, `false` otherwise.\n\t */\n\tisSimilar( otherSelection ) {\n\t\treturn this._selection.isSimilar( otherSelection );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tdocSelection.is( 'selection' ); // -> true\n\t *\t\tdocSelection.is( 'documentSelection' ); // -> true\n\t *\t\tdocSelection.is( 'view:selection' ); // -> true\n\t *\t\tdocSelection.is( 'view:documentSelection' ); // -> true\n\t *\n\t *\t\tdocSelection.is( 'model:documentSelection' ); // -> false\n\t *\t\tdocSelection.is( 'element' ); // -> false\n\t *\t\tdocSelection.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'selection' ||\n\t\t\ttype == 'documentSelection' ||\n\t\t\ttype == 'view:selection' ||\n\t\t\ttype == 'view:documentSelection';\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/view/selection~Selectable selectable}.\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tdocumentSelection._setTo( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];\n\t *\t\tdocumentSelection._setTo( range );\n\t *\n\t *\t\t// Sets selection to the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tdocumentSelection._setTo( otherSelection );\n\t *\n\t * \t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionAt( root, offset );\n\t *\t\tdocumentSelection._setTo( position );\n\t *\n\t * \t\t// Sets collapsed selection at the position of given item and offset.\n\t *\t\tdocumentSelection._setTo( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t *\t\tdocumentSelection._setTo( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\tdocumentSelection._setTo( paragraph, 'on' );\n\t *\n\t * \t\t// Clears selection. Removes all ranges.\n\t *\t\tdocumentSelection._setTo( null );\n\t *\n\t * `Selection#_setTo()` method allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\tdocumentSelection._setTo( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to des cribe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tdocumentSelection._setTo( range, { fake: true, label: 'foo' } );\n\t *\n\t * @protected\n\t * @fires change\n\t * @param {module:engine/view/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\t_setTo( selectable, placeOrOffset, options ) {\n\t\tthis._selection.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Moves {@link #focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}\n\t * parameters.\n\t *\n\t * @protected\n\t * @fires change\n\t * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\t_setFocus( itemOrPosition, offset ) {\n\t\tthis._selection.setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Fired whenever selection ranges are changed through {@link ~DocumentSelection Selection API}.\n\t *\n\t * @event change\n\t */\n}\n\nmix( DocumentSelection, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/document\n */\n\nimport DocumentSelection from './documentselection';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport StylesMap from './stylesmap';\n\n// @if CK_DEBUG_ENGINE // const { logDocument } = require( '../dev-utils/utils' );\n\n/**\n * Document class creates an abstract layer over the content editable area, contains a tree of view elements and\n * {@link module:engine/view/documentselection~DocumentSelection view selection} associated with this document.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Document {\n\t/**\n\t * Creates a Document instance.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Selection done on this document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/documentselection~DocumentSelection} module:engine/view/document~Document#selection\n\t\t */\n\t\tthis.selection = new DocumentSelection();\n\n\t\t/**\n\t\t * Roots of the view tree. Collection of the {@link module:engine/view/element~Element view elements}.\n\t\t *\n\t\t * View roots are created as a result of binding between {@link module:engine/view/document~Document#roots} and\n\t\t * {@link module:engine/model/document~Document#roots} and this is handled by\n\t\t * {@link module:engine/controller/editingcontroller~EditingController}, so to create view root we need to create\n\t\t * model root using {@link module:engine/model/document~Document#createRoot}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/collection~Collection} module:engine/view/document~Document#roots\n\t\t */\n\t\tthis.roots = new Collection( { idProperty: 'rootName' } );\n\n\t\t/**\n\t\t * Defines whether document is in read-only mode.\n\t\t *\n\t\t * When document is read-ony then all roots are read-only as well and caret placed inside this root is hidden.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * True if document is focused.\n\t\t *\n\t\t * This property is updated by the {@link module:engine/view/observer/focusobserver~FocusObserver}.\n\t\t * If the {@link module:engine/view/observer/focusobserver~FocusObserver} is disabled this property will not change.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/document~Document#isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * True if composition is in progress inside the document.\n\t\t *\n\t\t * This property is updated by the {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n\t\t * If the {@link module:engine/view/observer/compositionobserver~CompositionObserver} is disabled this property will not change.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/document~Document#isComposing\n\t\t */\n\t\tthis.set( 'isComposing', false );\n\n\t\t/**\n\t\t * Post-fixer callbacks registered to the view document.\n\t\t *\n\t\t * @private\n\t\t * @member {Set}\n\t\t */\n\t\tthis._postFixers = new Set();\n\t}\n\n\t/**\n\t * Gets a {@link module:engine/view/document~Document#roots view root element} with the specified name. If the name is not\n\t * specific \"main\" root is returned.\n\t *\n\t * @param {String} [name='main'] Name of the root.\n\t * @returns {module:engine/view/rooteditableelement~RootEditableElement|null} The view root element with the specified name\n\t * or null when there is no root of given name.\n\t */\n\tgetRoot( name = 'main' ) {\n\t\treturn this.roots.get( name );\n\t}\n\n\t/**\n\t * Allows registering post-fixer callbacks. A post-fixers mechanism allows to update the view tree just before it is rendered\n\t * to the DOM.\n\t *\n\t * Post-fixers are executed right after all changes from the outermost change block were applied but\n\t * before the {@link module:engine/view/view~View#event:render render event} is fired. If a post-fixer callback made\n\t * a change, it should return `true`. When this happens, all post-fixers are fired again to check if something else should\n\t * not be fixed in the new document tree state.\n\t *\n\t * View post-fixers are useful when you want to apply some fixes whenever the view structure changes. Keep in mind that\n\t * changes executed in a view post-fixer should not break model-view mapping.\n\t *\n\t * The types of changes which should be safe:\n\t *\n\t * * adding or removing attribute from elements,\n\t * * changes inside of {@link module:engine/view/uielement~UIElement UI elements},\n\t * * {@link module:engine/model/differ~Differ#refreshItem marking some of the model elements to be re-converted}.\n\t *\n\t * Try to avoid changes which touch view structure:\n\t *\n\t * * you should not add or remove nor wrap or unwrap any view elements,\n\t * * you should not change the editor data model in a view post-fixer.\n\t *\n\t * As a parameter, a post-fixer callback receives a {@link module:engine/view/downcastwriter~DowncastWriter downcast writer}.\n\t *\n\t * Typically, a post-fixer will look like this:\n\t *\n\t *\t\teditor.editing.view.document.registerPostFixer( writer => {\n\t *\t\t\tif ( checkSomeCondition() ) {\n\t *\t\t\t\twriter.doSomething();\n\t *\n\t *\t\t\t\t// Let other post-fixers know that something changed.\n\t *\t\t\t\treturn true;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Note that nothing happens right after you register a post-fixer (e.g. execute such a code in the console).\n\t * That is because adding a post-fixer does not execute it.\n\t * The post-fixer will be executed as soon as any change in the document needs to cause its rendering.\n\t * If you want to re-render the editor's view after registering the post-fixer then you should do it manually by calling\n\t * {@link module:engine/view/view~View#forceRender `view.forceRender()`}.\n\t *\n\t * If you need to register a callback which is executed when DOM elements are already updated,\n\t * use {@link module:engine/view/view~View#event:render render event}.\n\t *\n\t * @param {Function} postFixer\n\t */\n\tregisterPostFixer( postFixer ) {\n\t\tthis._postFixers.add( postFixer );\n\t}\n\n\t/**\n\t * Destroys this instance. Makes sure that all observers are destroyed and listeners removed.\n\t */\n\tdestroy() {\n\t\tthis.roots.map( root => root.destroy() );\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Adds a style processor normalization rules.\n\t *\n\t * The available style processors:\n\t *\n\t * * background: {@link module:engine/view/styles/background~addBackgroundRules}\n\t * * border: {@link module:engine/view/styles/border~addBorderRules}\n\t * * margin: {@link module:engine/view/styles/margin~addMarginRules}\n\t * * padding: {@link module:engine/view/styles/padding~addPaddingRules}\n\t *\n\t * @param {Function} callback\n\t */\n\taddStyleProcessorRules( callback ) {\n\t\tcallback( StylesMap._styleProcessor );\n\t}\n\n\t/**\n\t * Performs post-fixer loops. Executes post-fixer callbacks as long as none of them has done any changes to the model.\n\t *\n\t * @protected\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\t_callPostFixers( writer ) {\n\t\tlet wasFixed = false;\n\n\t\tdo {\n\t\t\tfor ( const callback of this._postFixers ) {\n\t\t\t\twasFixed = callback( writer );\n\n\t\t\t\tif ( wasFixed ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} while ( wasFixed );\n\t}\n\n\t/**\n\t * Event fired whenever document content layout changes. It is fired whenever content is\n\t * {@link module:engine/view/view~View#event:render rendered}, but should be also fired by observers in case of\n\t * other actions which may change layout, for instance when image loads.\n\t *\n\t * @event layoutChanged\n\t */\n\n\t// @if CK_DEBUG_ENGINE // log( version ) {\n\t// @if CK_DEBUG_ENGINE //\tlogDocument( this, version );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\nmix( Document, ObservableMixin );\n\n/**\n * Enum representing type of the change.\n *\n * Possible values:\n *\n * * `children` - for child list changes,\n * * `attributes` - for element attributes changes,\n * * `text` - for text nodes changes.\n *\n * @typedef {String} module:engine/view/document~ChangeType\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/attributeelement\n */\n\nimport Element from './element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// Default attribute priority.\nconst DEFAULT_PRIORITY = 10;\n\n/**\n * Attribute elements are used to represent formatting elements in the view (think – `<b>`, `<span style=\"font-size: 2em\">`, etc.).\n * Most often they are created when downcasting model text attributes.\n *\n * Editing engine does not define a fixed HTML DTD. This is why a feature developer needs to choose between various\n * types (container element, {@link module:engine/view/attributeelement~AttributeElement attribute element},\n * {@link module:engine/view/emptyelement~EmptyElement empty element}, etc) when developing a feature.\n *\n * To create a new attribute element instance use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement `DowncastWriter#createAttributeElement()`} method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class AttributeElement extends Element {\n\t/**\n\t * Creates an attribute element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createAttributeElement\n\t * @see module:engine/view/element~Element\n\t * @protected\n\t */\n\tconstructor( name, attrs, children ) {\n\t\tsuper( name, attrs, children );\n\n\t\t/**\n\t\t * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {Number|null} Block filler offset or `null` if block filler is not needed.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\n\t\t/**\n\t\t * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Number}\n\t\t */\n\t\tthis._priority = DEFAULT_PRIORITY;\n\n\t\t/**\n\t\t * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},\n\t\t * and then two elements are considered similar if, and only if they have the same `_id`.\n\t\t *\n\t\t * @protected\n\t\t * @member {String|Number}\n\t\t */\n\t\tthis._id = null;\n\n\t\t/**\n\t\t * Keeps all the attribute elements that have the same {@link module:engine/view/attributeelement~AttributeElement#id ids}\n\t\t * and still exist in the view tree.\n\t\t *\n\t\t * This property is managed by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Set.<module:engine/view/attributeelement~AttributeElement>|null}\n\t\t */\n\t\tthis._clonesGroup = null;\n\t}\n\n\t/**\n\t * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget priority() {\n\t\treturn this._priority;\n\t}\n\n\t/**\n\t * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},\n\t * and then two elements are considered similar if, and only if they have the same `id`.\n\t *\n\t * @readonly\n\t * @type {String|Number}\n\t */\n\tget id() {\n\t\treturn this._id;\n\t}\n\n\t/**\n\t * Returns all {@link module:engine/view/attributeelement~AttributeElement attribute elements} that has the\n\t * same {@link module:engine/view/attributeelement~AttributeElement#id id} and are in the view tree (were not removed).\n\t *\n\t * Note: If this element has been removed from the tree, returned set will not include it.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError attribute-element-get-elements-with-same-id-no-id}\n\t * if this element has no `id`.\n\t *\n\t * @returns {Set.<module:engine/view/attributeelement~AttributeElement>} Set containing all the attribute elements\n\t * with the same `id` that were added and not removed from the view tree.\n\t */\n\tgetElementsWithSameId() {\n\t\tif ( this.id === null ) {\n\t\t\t/**\n\t\t\t * Cannot get elements with the same id for an attribute element without id.\n\t\t\t *\n\t\t\t * @error attribute-element-get-elements-with-same-id-no-id\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'attribute-element-get-elements-with-same-id-no-id: ' +\n\t\t\t\t'Cannot get elements with the same id for an attribute element without id.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\treturn new Set( this._clonesGroup );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tattributeElement.is( 'attributeElement' ); // -> true\n\t *\t\tattributeElement.is( 'element' ); // -> true\n\t *\t\tattributeElement.is( 'node' ); // -> true\n\t *\t\tattributeElement.is( 'view:attributeElement' ); // -> true\n\t *\t\tattributeElement.is( 'view:element' ); // -> true\n\t *\t\tattributeElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\tattributeElement.is( 'model:element' ); // -> false\n\t *\t\tattributeElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an attribute element, you can also check its\n\t * {@link module:engine/view/attributeelement~AttributeElement#name name}:\n\t *\n\t *\t\tattributeElement.is( 'b' ); // -> true if this is a bold element\n\t *\t\tattributeElement.is( 'attributeElement', 'b' ); // -> same as above\n\t *\t\ttext.is( 'b' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check when `name` parameter is present.\n\t * Otherwise, it acts like the `name` parameter.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tconst cutType = type && type.replace( /^view:/, '' );\n\n\t\tif ( !name ) {\n\t\t\treturn cutType == 'attributeElement' || super.is( type );\n\t\t} else {\n\t\t\treturn ( cutType == 'attributeElement' && name == this.name ) || super.is( type, name );\n\t\t}\n\t}\n\n\t/**\n\t * Checks if this element is similar to other element.\n\t *\n\t * If none of elements has set {@link module:engine/view/attributeelement~AttributeElement#id}, then both elements\n\t * should have the same name, attributes and priority to be considered as similar. Two similar elements can contain\n\t * different set of children nodes.\n\t *\n\t * If at least one element has {@link module:engine/view/attributeelement~AttributeElement#id} set, then both\n\t * elements have to have the same {@link module:engine/view/attributeelement~AttributeElement#id} value to be\n\t * considered similar.\n\t *\n\t * Similarity is important for {@link module:engine/view/downcastwriter~DowncastWriter}. For example:\n\t *\n\t * * two following similar elements can be merged together into one, longer element,\n\t * * {@link module:engine/view/downcastwriter~DowncastWriter#unwrap} checks similarity of passed element and processed element to\n\t * decide whether processed element should be unwrapped,\n\t * * etc.\n\t *\n\t * @param {module:engine/view/element~Element} otherElement\n\t * @returns {Boolean}\n\t */\n\tisSimilar( otherElement ) {\n\t\t// If any element has an `id` set, just compare the ids.\n\t\tif ( this.id !== null || otherElement.id !== null ) {\n\t\t\treturn this.id === otherElement.id;\n\t\t}\n\n\t\treturn super.isSimilar( otherElement ) && this.priority == otherElement.priority;\n\t}\n\n\t/**\n\t * Clones provided element with priority.\n\t *\n\t * @protected\n\t * @param {Boolean} deep If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any children.\n\t * @returns {module:engine/view/attributeelement~AttributeElement} Clone of this element.\n\t */\n\t_clone( deep ) {\n\t\tconst cloned = super._clone( deep );\n\n\t\t// Clone priority too.\n\t\tcloned._priority = this._priority;\n\n\t\t// And id too.\n\t\tcloned._id = this._id;\n\n\t\treturn cloned;\n\t}\n}\n\n/**\n * Default attribute priority.\n *\n * @member {Number} module:engine/view/attributeelement~AttributeElement.DEFAULT_PRIORITY\n */\nAttributeElement.DEFAULT_PRIORITY = DEFAULT_PRIORITY;\n\n// Returns block {@link module:engine/view/filler~Filler filler} offset or `null` if block filler is not needed.\n//\n// @returns {Number|null} Block filler offset or `null` if block filler is not needed.\nfunction getFillerOffset() {\n\t// <b>foo</b> does not need filler.\n\tif ( nonUiChildrenCount( this ) ) {\n\t\treturn null;\n\t}\n\n\tlet element = this.parent;\n\n\t// <p><b></b></p> needs filler -> <p><b><br></b></p>\n\twhile ( element && element.is( 'attributeElement' ) ) {\n\t\tif ( nonUiChildrenCount( element ) > 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\telement = element.parent;\n\t}\n\n\tif ( !element || nonUiChildrenCount( element ) > 1 ) {\n\t\treturn null;\n\t}\n\n\t// Render block filler at the end of element (after all ui elements).\n\treturn this.childCount;\n}\n\n// Returns total count of children that are not {@link module:engine/view/uielement~UIElement UIElements}.\n//\n// @param {module:engine/view/element~Element} element\n// @returns {Number}\nfunction nonUiChildrenCount( element ) {\n\treturn Array.from( element.getChildren() ).filter( element => !element.is( 'uiElement' ) ).length;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/emptyelement\n */\n\nimport Element from './element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Node from './node';\n\n/**\n * Empty element class. It is used to represent elements that cannot contain any child nodes (for example `<img>` elements).\n *\n * To create a new empty element use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement `downcastWriter#createEmptyElement()`} method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class EmptyElement extends Element {\n\t/**\n\t * Creates new instance of EmptyElement.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-emptyelement-cannot-add` when third parameter is passed,\n\t * to inform that usage of EmptyElement is incorrect (adding child nodes to EmptyElement is forbidden).\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createEmptyElement\n\t * @protected\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attributes] Collection of attributes.\n\t */\n\tconstructor( name, attributes, children ) {\n\t\tsuper( name, attributes, children );\n\n\t\t/**\n\t\t * Returns `null` because filler is not needed for EmptyElements.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {null} Always returns null.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\temptyElement.is( 'emptyElement' ); // -> true\n\t *\t\temptyElement.is( 'element' ); // -> true\n\t *\t\temptyElement.is( 'node' ); // -> true\n\t *\t\temptyElement.is( 'view:emptyElement' ); // -> true\n\t *\t\temptyElement.is( 'view:element' ); // -> true\n\t *\t\temptyElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\temptyElement.is( 'model:element' ); // -> false\n\t *\t\temptyElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an empty element, you can also check its\n\t * {@link module:engine/view/emptyelement~EmptyElement#name name}:\n\t *\n\t *\t\temptyElement.is( 'img' ); // -> true if this is a img element\n\t *\t\temptyElement.is( 'emptyElement', 'img' ); // -> same as above\n\t *\t\ttext.is( 'img' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check when `name` parameter is present.\n\t * Otherwise, it acts like the `name` parameter.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tconst cutType = type.replace( /^view:/, '' );\n\t\tif ( !name ) {\n\t\t\treturn cutType == 'emptyElement' || super.is( type );\n\t\t} else {\n\t\t\treturn ( cutType == 'emptyElement' && name == this.name ) || super.is( type, name );\n\t\t}\n\t}\n\n\t/**\n\t * Overrides {@link module:engine/view/element~Element#_insertChild} method.\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-emptyelement-cannot-add` to prevent\n\t * adding any child nodes to EmptyElement.\n\t *\n\t * @protected\n\t */\n\t_insertChild( index, nodes ) {\n\t\tif ( nodes && ( nodes instanceof Node || Array.from( nodes ).length > 0 ) ) {\n\t\t\t/**\n\t\t\t * Cannot add children to {@link module:engine/view/emptyelement~EmptyElement}.\n\t\t\t *\n\t\t\t * @error view-emptyelement-cannot-add\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.',\n\t\t\t\t[ this, nodes ]\n\t\t\t);\n\t\t}\n\t}\n}\n\n// Returns `null` because block filler is not needed for EmptyElements.\n//\n// @returns {null}\nfunction getFillerOffset() {\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals navigator:false */\n\n/**\n * @module utils/env\n */\n\nconst userAgent = navigator.userAgent.toLowerCase();\n\n/**\n * A namespace containing environment and browser information.\n *\n * @namespace\n */\nconst env = {\n\t/**\n\t * Indicates that the application is running on Macintosh.\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisMac: isMac( userAgent ),\n\n\t/**\n\t * Indicates that the application is running in Microsoft Edge.\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisEdge: isEdge( userAgent ),\n\n\t/**\n\t * Indicates that the application is running in Firefox (Gecko).\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisGecko: isGecko( userAgent ),\n\n\t/**\n\t * Indicates that the application is running in Safari.\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisSafari: isSafari( userAgent ),\n\n\t/**\n\t * Indicates that the application is running on Android mobile device.\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisAndroid: isAndroid( userAgent ),\n\n\t/**\n\t * Environment features information.\n\t *\n\t * @memberOf module:utils/env~env\n\t * @namespace\n\t */\n\tfeatures: {\n\t\t/**\n\t\t * Indicates that the environment supports ES2018 Unicode property escapes — like `\\p{P}` or `\\p{L}`.\n\t\t * More information about unicode properties might be found\n\t\t * [in Unicode Standard Annex #44](https://www.unicode.org/reports/tr44/#GC_Values_Table).\n\t\t *\n\t\t * @type {Boolean}\n\t\t */\n\t\tisRegExpUnicodePropertySupported: isRegExpUnicodePropertySupported()\n\t}\n};\n\nexport default env;\n\n/**\n * Checks if User Agent represented by the string is running on Macintosh.\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is running on Macintosh or not.\n */\nexport function isMac( userAgent ) {\n\treturn userAgent.indexOf( 'macintosh' ) > -1;\n}\n\n/**\n * Checks if User Agent represented by the string is Microsoft Edge.\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is Edge or not.\n */\nexport function isEdge( userAgent ) {\n\treturn !!userAgent.match( /edge\\/(\\d+.?\\d*)/ );\n}\n\n/**\n * Checks if User Agent represented by the string is Firefox (Gecko).\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is Firefox or not.\n */\nexport function isGecko( userAgent ) {\n\treturn !!userAgent.match( /gecko\\/\\d+/ );\n}\n\n/**\n * Checks if User Agent represented by the string is Safari.\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is Safari or not.\n */\nexport function isSafari( userAgent ) {\n\treturn userAgent.indexOf( ' applewebkit/' ) > -1 && userAgent.indexOf( 'chrome' ) === -1;\n}\n\n/**\n * Checks if User Agent represented by the string is Android mobile device.\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is Safari or not.\n */\nexport function isAndroid( userAgent ) {\n\treturn userAgent.indexOf( 'android' ) > -1;\n}\n\n/**\n * Checks if the current environment supports ES2018 Unicode properties like `\\p{P}` or `\\p{L}`.\n * More information about unicode properties might be found\n * [in Unicode Standard Annex #44](https://www.unicode.org/reports/tr44/#GC_Values_Table).\n *\n * @returns {Boolean}\n */\nexport function isRegExpUnicodePropertySupported() {\n\tlet isSupported = false;\n\n\t// Feature detection for Unicode properties. Added in ES2018. Currently Firefox and Edge do not support it.\n\t// See https://github.com/ckeditor/ckeditor5-mention/issues/44#issuecomment-487002174.\n\n\ttry {\n\t\t// Usage of regular expression literal cause error during build (ckeditor/ckeditor5-dev#534).\n\t\tisSupported = 'ć'.search( new RegExp( '[\\\\p{L}]', 'u' ) ) === 0;\n\t} catch ( error ) {\n\t\t// Firefox throws a SyntaxError when the group is unsupported.\n\t}\n\n\treturn isSupported;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * Set of utils related to keyboard support.\n *\n * @module utils/keyboard\n */\n\nimport CKEditorError from './ckeditorerror';\nimport env from './env';\n\nconst macGlyphsToModifiers = {\n\t'⌘': 'ctrl',\n\t'⇧': 'shift',\n\t'⌥': 'alt'\n};\n\nconst modifiersToMacGlyphs = {\n\t'ctrl': '⌘',\n\t'shift': '⇧',\n\t'alt': '⌥'\n};\n\n/**\n * Object with `keyName => keyCode` pairs for a set of known keys.\n *\n * Contains:\n *\n * * `a-z`,\n * * `0-9`,\n * * `f1-f12`,\n * * `arrow(left|up|right|bottom)`,\n * * `backspace`, `delete`, `enter`, `esc`, `tab`,\n * * `ctrl`, `cmd`, `shift`, `alt`.\n */\nexport const keyCodes = generateKnownKeyCodes();\n\n/**\n * Converts a key name or a {@link module:utils/keyboard~KeystrokeInfo keystroke info} into a key code.\n *\n * Note: Key names are matched with {@link module:utils/keyboard~keyCodes} in a case-insensitive way.\n *\n * @param {String|module:utils/keyboard~KeystrokeInfo} Key name (see {@link module:utils/keyboard~keyCodes})\n * or a keystroke data object.\n * @returns {Number} Key or keystroke code.\n */\nexport function getCode( key ) {\n\tlet keyCode;\n\n\tif ( typeof key == 'string' ) {\n\t\tkeyCode = keyCodes[ key.toLowerCase() ];\n\n\t\tif ( !keyCode ) {\n\t\t\t/**\n\t\t\t * Unknown key name. Only key names contained by the {@link module:utils/keyboard~keyCodes} can be used.\n\t\t\t *\n\t\t\t * @errror keyboard-unknown-key\n\t\t\t * @param {String} key\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'keyboard-unknown-key: Unknown key name.',\n\t\t\t\tnull, { key }\n\t\t\t);\n\t\t}\n\t} else {\n\t\tkeyCode = key.keyCode +\n\t\t\t( key.altKey ? keyCodes.alt : 0 ) +\n\t\t\t( key.ctrlKey ? keyCodes.ctrl : 0 ) +\n\t\t\t( key.shiftKey ? keyCodes.shift : 0 );\n\t}\n\n\treturn keyCode;\n}\n\n/**\n * Parses keystroke and returns a keystroke code that will match the code returned by\n * link {@link module:utils/keyboard.getCode} for a corresponding {@link module:utils/keyboard~KeystrokeInfo keystroke info}.\n *\n * The keystroke can be passed in two formats:\n *\n * * as a single string – e.g. `ctrl + A`,\n * * as an array of {@link module:utils/keyboard~keyCodes known key names} and key codes – e.g.:\n * * `[ 'ctrl', 32 ]` (ctrl + space),\n * * `[ 'ctrl', 'a' ]` (ctrl + A).\n *\n * Note: Key names are matched with {@link module:utils/keyboard~keyCodes} in a case-insensitive way.\n *\n * Note: Only keystrokes with a single non-modifier key are supported (e.g. `ctrl+A` is OK, but `ctrl+A+B` is not).\n *\n * @param {String|Array.<Number|String>} keystroke Keystroke definition.\n * @returns {Number} Keystroke code.\n */\nexport function parseKeystroke( keystroke ) {\n\tif ( typeof keystroke == 'string' ) {\n\t\tkeystroke = splitKeystrokeText( keystroke );\n\t}\n\n\treturn keystroke\n\t\t.map( key => ( typeof key == 'string' ) ? getCode( key ) : key )\n\t\t.reduce( ( key, sum ) => sum + key, 0 );\n}\n\n/**\n * It translates any keystroke string text like `\"CTRL+A\"` to an\n * environment–specific keystroke, i.e. `\"⌘A\"` on Mac OSX.\n *\n * @param {String} keystroke Keystroke text.\n * @returns {String} Keystroke text specific for the environment.\n */\nexport function getEnvKeystrokeText( keystroke ) {\n\tif ( !env.isMac ) {\n\t\treturn keystroke;\n\t}\n\n\treturn splitKeystrokeText( keystroke )\n\t\t// Replace modifiers (e.g. \"ctrl\") with Mac glyphs (e.g. \"⌘\") first.\n\t\t.map( key => modifiersToMacGlyphs[ key.toLowerCase() ] || key )\n\n\t\t// Decide whether to put \"+\" between keys in the keystroke or not.\n\t\t.reduce( ( value, key ) => {\n\t\t\tif ( value.slice( -1 ) in macGlyphsToModifiers ) {\n\t\t\t\treturn value + key;\n\t\t\t} else {\n\t\t\t\treturn value + '+' + key;\n\t\t\t}\n\t\t} );\n}\n\nfunction generateKnownKeyCodes() {\n\tconst keyCodes = {\n\t\tarrowleft: 37,\n\t\tarrowup: 38,\n\t\tarrowright: 39,\n\t\tarrowdown: 40,\n\t\tbackspace: 8,\n\t\tdelete: 46,\n\t\tenter: 13,\n\t\tspace: 32,\n\t\tesc: 27,\n\t\ttab: 9,\n\n\t\t// The idea about these numbers is that they do not collide with any real key codes, so we can use them\n\t\t// like bit masks.\n\t\tctrl: 0x110000,\n\t\t// Has the same code as ctrl, because their behaviour should be unified across the editor.\n\t\t// See http://ckeditor.github.io/editor-recommendations/general-policies#ctrl-vs-cmd\n\t\tcmd: 0x110000,\n\t\tshift: 0x220000,\n\t\talt: 0x440000\n\t};\n\n\t// a-z\n\tfor ( let code = 65; code <= 90; code++ ) {\n\t\tconst letter = String.fromCharCode( code );\n\n\t\tkeyCodes[ letter.toLowerCase() ] = code;\n\t}\n\n\t// 0-9\n\tfor ( let code = 48; code <= 57; code++ ) {\n\t\tkeyCodes[ code - 48 ] = code;\n\t}\n\n\t// F1-F12\n\tfor ( let code = 112; code <= 123; code++ ) {\n\t\tkeyCodes[ 'f' + ( code - 111 ) ] = code;\n\t}\n\n\treturn keyCodes;\n}\n\nfunction splitKeystrokeText( keystroke ) {\n\treturn keystroke.split( /\\s*\\+\\s*/ );\n}\n\n/**\n * Information about a keystroke.\n *\n * @interface module:utils/keyboard~KeystrokeInfo\n */\n\n/**\n * The [key code](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode).\n *\n * @member {Number} module:utils/keyboard~KeystrokeInfo#keyCode\n */\n\n/**\n * Whether the <kbd>Alt</kbd> modifier was pressed.\n *\n * @member {Bolean} module:utils/keyboard~KeystrokeInfo#altKey\n */\n\n/**\n * Whether the <kbd>Ctrl</kbd> or <kbd>Cmd</kbd> modifier was pressed.\n *\n * @member {Bolean} module:utils/keyboard~KeystrokeInfo#ctrlKey\n */\n\n/**\n * Whether the <kbd>Shift</kbd> modifier was pressed.\n *\n * @member {Bolean} module:utils/keyboard~KeystrokeInfo#shiftKey\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/uielement\n */\n\nimport Element from './element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Node from './node';\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\n\n/**\n * UI element class. It should be used to represent editing UI which needs to be injected into the editing view\n * If possible, you should keep your UI outside the editing view. However, if that is not possible,\n * UI elements can be used.\n *\n * How a UI element is rendered is in your control (you pass a callback to\n * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`}).\n * The editor will ignore your UI element – the selection cannot be placed in it, it is skipped (invisible) when\n * the user modifies the selection by using arrow keys and the editor does not listen to any mutations which\n * happen inside your UI elements.\n *\n * The limitation is that you cannot convert a model element to a UI element. UI elements need to be\n * created for {@link module:engine/model/markercollection~Marker markers} or as additinal elements\n * inside normal {@link module:engine/view/containerelement~ContainerElement container elements}.\n *\n * To create a new UI element use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`} method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class UIElement extends Element {\n\t/**\n\t * Creates new instance of UIElement.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-uielement-cannot-add` when third parameter is passed,\n\t * to inform that usage of UIElement is incorrect (adding child nodes to UIElement is forbidden).\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createUIElement\n\t * @protected\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attributes] Collection of attributes.\n\t */\n\tconstructor( name, attributes, children ) {\n\t\tsuper( name, attributes, children );\n\n\t\t/**\n\t\t * Returns `null` because filler is not needed for UIElements.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {null} Always returns null.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tuiElement.is( 'uiElement' ); // -> true\n\t *\t\tuiElement.is( 'element' ); // -> true\n\t *\t\tuiElement.is( 'node' ); // -> true\n\t *\t\tuiElement.is( 'view:uiElement' ); // -> true\n\t *\t\tuiElement.is( 'view:element' ); // -> true\n\t *\t\tuiElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\tuiElement.is( 'model:element' ); // -> false\n\t *\t\tuiElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an ui element, you can also check its\n\t * {@link module:engine/view/uielement~UIElement#name name}:\n\t *\n\t *\t\tuiElement.is( 'span' ); // -> true if this is a span ui element\n\t *\t\tuiElement.is( 'uiElement', 'span' ); // -> same as above\n\t *\t\ttext.is( 'span' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check when `name` parameter is present.\n\t * Otherwise, it acts like the `name` parameter.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tconst cutType = type.replace( /^view:/, '' );\n\t\tif ( !name ) {\n\t\t\treturn cutType == 'uiElement' || super.is( type );\n\t\t} else {\n\t\t\treturn ( cutType == 'uiElement' && name == this.name ) || super.is( type, name );\n\t\t}\n\t}\n\n\t/**\n\t * Overrides {@link module:engine/view/element~Element#_insertChild} method.\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-uielement-cannot-add` to prevent adding any child nodes\n\t * to UIElement.\n\t *\n\t * @protected\n\t */\n\t_insertChild( index, nodes ) {\n\t\tif ( nodes && ( nodes instanceof Node || Array.from( nodes ).length > 0 ) ) {\n\t\t\t/**\n\t\t\t * Cannot add children to {@link module:engine/view/uielement~UIElement}.\n\t\t\t *\n\t\t\t * @error view-uielement-cannot-add\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.', this );\n\t\t}\n\t}\n\n\t/**\n\t * Renders this {@link module:engine/view/uielement~UIElement} to DOM. This method is called by\n\t * {@link module:engine/view/domconverter~DomConverter}.\n\t * Do not use inheritance to create custom rendering method, replace `render()` method instead:\n\t *\n\t *\t\tconst myUIElement = downcastWriter.createUIElement( 'span' );\n\t *\t\tmyUIElement.render = function( domDocument ) {\n\t *\t\t\tconst domElement = this.toDomElement( domDocument );\n\t *\t\t\tdomElement.innerHTML = '<b>this is ui element</b>';\n\t *\n\t *\t\t\treturn domElement;\n\t *\t\t};\n\t *\n\t * If changes in your UI element should trigger some editor UI update you should call\n\t * the {@link module:core/editor/editorui~EditorUI#update `editor.ui.update()`} method\n\t * after rendering your UI element.\n\t *\n\t * @param {Document} domDocument\n\t * @returns {HTMLElement}\n\t */\n\trender( domDocument ) {\n\t\treturn this.toDomElement( domDocument );\n\t}\n\n\t/**\n\t * Creates DOM element based on this view UIElement.\n\t * Note that each time this method is called new DOM element is created.\n\t *\n\t * @param {Document} domDocument\n\t * @returns {HTMLElement}\n\t */\n\ttoDomElement( domDocument ) {\n\t\tconst domElement = domDocument.createElement( this.name );\n\n\t\tfor ( const key of this.getAttributeKeys() ) {\n\t\t\tdomElement.setAttribute( key, this.getAttribute( key ) );\n\t\t}\n\n\t\treturn domElement;\n\t}\n}\n\n/**\n * This function injects UI element handling to the given {@link module:engine/view/document~Document document}.\n *\n * A callback is added to {@link module:engine/view/document~Document#event:keydown document keydown event}.\n * The callback handles the situation when right arrow key is pressed and selection is collapsed before a UI element.\n * Without this handler, it would be impossible to \"jump over\" UI element using right arrow key.\n *\n * @param {module:engine/view/view~View} view View controller to which the quirks handling will be injected.\n */\nexport function injectUiElementHandling( view ) {\n\tview.document.on( 'keydown', ( evt, data ) => jumpOverUiElement( evt, data, view.domConverter ) );\n}\n\n// Returns `null` because block filler is not needed for UIElements.\n//\n// @returns {null}\nfunction getFillerOffset() {\n\treturn null;\n}\n\n// Selection cannot be placed in a `UIElement`. Whenever it is placed there, it is moved before it. This\n// causes a situation when it is impossible to jump over `UIElement` using right arrow key, because the selection\n// ends up in ui element (in DOM) and is moved back to the left. This handler fixes this situation.\nfunction jumpOverUiElement( evt, data, domConverter ) {\n\tif ( data.keyCode == keyCodes.arrowright ) {\n\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\t\tconst domSelectionCollapsed = domSelection.rangeCount == 1 && domSelection.getRangeAt( 0 ).collapsed;\n\n\t\t// Jump over UI element if selection is collapsed or shift key is pressed. These are the cases when selection would extend.\n\t\tif ( domSelectionCollapsed || data.shiftKey ) {\n\t\t\tconst domParent = domSelection.focusNode;\n\t\t\tconst domOffset = domSelection.focusOffset;\n\n\t\t\tconst viewPosition = domConverter.domPositionToView( domParent, domOffset );\n\n\t\t\t// In case if dom element is not converted to view or is not mapped or something. Happens for example in some tests.\n\t\t\tif ( viewPosition === null ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip all following ui elements.\n\t\t\tlet jumpedOverAnyUiElement = false;\n\n\t\t\tconst nextViewPosition = viewPosition.getLastMatchingPosition( value => {\n\t\t\t\tif ( value.item.is( 'uiElement' ) ) {\n\t\t\t\t\t// Remember that there was at least one ui element.\n\t\t\t\t\tjumpedOverAnyUiElement = true;\n\t\t\t\t}\n\n\t\t\t\t// Jump over ui elements, jump over empty attribute elements, move up from inside of attribute element.\n\t\t\t\tif ( value.item.is( 'uiElement' ) || value.item.is( 'attributeElement' ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\t// Don't jump over text or don't get out of container element.\n\t\t\t\treturn false;\n\t\t\t} );\n\n\t\t\t// If anything has been skipped, fix position.\n\t\t\t// This `if` could be possibly omitted but maybe it is better not to mess with DOM selection if not needed.\n\t\t\tif ( jumpedOverAnyUiElement ) {\n\t\t\t\tconst newDomPosition = domConverter.viewPositionToDom( nextViewPosition );\n\n\t\t\t\tif ( domSelectionCollapsed ) {\n\t\t\t\t\t// Selection was collapsed, so collapse it at further position.\n\t\t\t\t\tdomSelection.collapse( newDomPosition.parent, newDomPosition.offset );\n\t\t\t\t} else {\n\t\t\t\t\t// Selection was not collapse, so extend it instead of collapsing.\n\t\t\t\t\tdomSelection.extend( newDomPosition.parent, newDomPosition.offset );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/documentfragment\n */\n\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\n\n/**\n * Document fragment.\n *\n * To create a new document fragment instance use the\n * {@link module:engine/view/upcastwriter~UpcastWriter#createDocumentFragment `UpcastWriter#createDocumentFragment()`}\n * method.\n */\nexport default class DocumentFragment {\n\t/**\n\t * Creates new DocumentFragment instance.\n\t *\n\t * @protected\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into the created document fragment.\n\t */\n\tconstructor( children ) {\n\t\t/**\n\t\t * Array of child nodes.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.<module:engine/view/element~Element>} module:engine/view/documentfragment~DocumentFragment#_children\n\t\t */\n\t\tthis._children = [];\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over nodes added to this document fragment.\n\t *\n\t * @returns {Iterable.<module:engine/view/node~Node>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Number of child nodes in this document fragment.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this document fragment, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this.childCount === 0;\n\t}\n\n\t/**\n\t * Artificial root of `DocumentFragment`. Returns itself. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Artificial parent of `DocumentFragment`. Returns `null`. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {null}\n\t */\n\tget parent() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tdocFrag.is( 'documentFragment' ); // -> true\n\t *\t\tdocFrag.is( 'view:documentFragment' ); // -> true\n\t *\n\t *\t\tdocFrag.is( 'model:documentFragment' ); // -> false\n\t *\t\tdocFrag.is( 'element' ); // -> false\n\t *\t\tdocFrag.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'documentFragment' || type == 'view:documentFragment';\n\t}\n\n\t/**\n\t * {@link module:engine/view/documentfragment~DocumentFragment#_insertChild Insert} a child node or a list of child nodes at the end\n\t * and sets the parent of these nodes to this fragment.\n\t *\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @returns {Number} Number of appended nodes.\n\t */\n\t_appendChild( items ) {\n\t\treturn this._insertChild( this.childCount, items );\n\t}\n\n\t/**\n\t * Gets child at the given index.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/view/node~Node} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children[ index ];\n\t}\n\n\t/**\n\t * Gets index of the given child node. Returns `-1` if child node is not found.\n\t *\n\t * @param {module:engine/view/node~Node} node Child node.\n\t * @returns {Number} Index of the child node.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.indexOf( node );\n\t}\n\n\t/**\n\t * Gets child nodes iterator.\n\t *\n\t * @returns {Iterable.<module:engine/view/node~Node>} Child nodes iterator.\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to\n\t * this fragment.\n\t *\n\t * @param {Number} index Position where nodes should be inserted.\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @returns {Number} Number of inserted nodes.\n\t */\n\t_insertChild( index, items ) {\n\t\tthis._fireChange( 'children', this );\n\t\tlet count = 0;\n\n\t\tconst nodes = normalize( items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\n\t\t\tthis._children.splice( index, 0, node );\n\t\t\tindex++;\n\t\t\tcount++;\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/**\n\t * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.\n\t *\n\t * @param {Number} index Number of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.<module:engine/view/node~Node>} The array of removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tthis._fireChange( 'children', this );\n\n\t\tfor ( let i = index; i < index + howMany; i++ ) {\n\t\t\tthis._children[ i ].parent = null;\n\t\t}\n\n\t\treturn this._children.splice( index, howMany );\n\t}\n\n\t/**\n\t * Fires `change` event with given type of the change.\n\t *\n\t * @private\n\t * @param {module:engine/view/document~ChangeType} type Type of the change.\n\t * @param {module:engine/view/node~Node} node Changed node.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_fireChange( type, node ) {\n\t\tthis.fire( 'change:' + type, node );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // printTree() {\n\t// @if CK_DEBUG_ENGINE //\tlet string = 'ViewDocumentFragment: [';\n\n\t// @if CK_DEBUG_ENGINE //\tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE //\t\tif ( child.is( 'text' ) ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + '\\t'.repeat( 1 ) + child.data;\n\t// @if CK_DEBUG_ENGINE //\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + child.printTree( 1 );\n\t// @if CK_DEBUG_ENGINE //\t\t}\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tstring += '\\n]';\n\n\t// @if CK_DEBUG_ENGINE //\treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\nmix( DocumentFragment, EmitterMixin );\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/view/item~Item|Iterable.<String|module:engine/view/item~Item>}\n// @returns {Iterable.<module:engine/view/node~Node>}\nfunction normalize( nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( node.data );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 module:engine/view/downcastwriter\n */\n\nimport Position from './position';\nimport Range from './range';\nimport Selection from './selection';\nimport ContainerElement from './containerelement';\nimport AttributeElement from './attributeelement';\nimport EmptyElement from './emptyelement';\nimport UIElement from './uielement';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport DocumentFragment from './documentfragment';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport Text from './text';\nimport EditableElement from './editableelement';\nimport { isPlainObject } from 'lodash-es';\n\n/**\n * View downcast writer.\n *\n * It provides a set of methods used to manipulate view nodes.\n *\n * Do not create an instance of this writer manually. To modify a view structure, use\n * the {@link module:engine/view/view~View#change `View#change()`} block.\n *\n * The `DowncastWriter` is designed to work with semantic views which are the views that were/are being downcasted from the model.\n * To work with ordinary views (e.g. parsed from a pasted content) use the\n * {@link module:engine/view/upcastwriter~UpcastWriter upcast writer}.\n *\n * Read more about changing the view in the {@glink framework/guides/architecture/editing-engine#changing-the-view Changing the view}\n * section of the {@glink framework/guides/architecture/editing-engine Editing engine architecture} guide.\n */\nexport default class DowncastWriter {\n\tconstructor( document ) {\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\n\t\t/**\n\t\t * Holds references to the attribute groups that share the same {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t\t * The keys are `id`s, the values are `Set`s holding {@link module:engine/view/attributeelement~AttributeElement}s.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<String,Set>}\n\t\t */\n\t\tthis._cloneGroups = new Map();\n\t}\n\n\t/**\n\t * Sets {@link module:engine/view/documentselection~DocumentSelection selection's} ranges and direction to the\n\t * specified location based on the given {@link module:engine/view/selection~Selectable selectable}.\n\t *\n\t * Usage:\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets backward selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets selection to the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\twriter.setSelection( otherSelection );\n\t *\n\t * \t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\twriter.setSelection( position );\n\t *\n\t * \t\t// Sets collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'p' );\n\t *\t\twriter.setSelection( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n \t * that element and ends after the last child of that element.\n\t *\n\t * \t\twriter.setSelection( paragraph, 'in' );\n\t *\n\t * Creates a range on the {@link module:engine/view/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\twriter.setSelection( paragraph, 'on' );\n\t *\n\t * \t\t// Removes all ranges.\n\t *\t\twriter.setSelection( null );\n\t *\n\t * `DowncastWriter#setSelection()` allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\twriter.setSelection( range, { backward: true } );\n\t *\n\t *\t\t// Sets selection as fake.\n\t *\t\t// Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * \t\t// This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * \t\t// represented in other way, for example by applying proper CSS class.\n\t *\t\twriter.setSelection( range, { fake: true } );\n\t *\n\t * \t\t// Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * \t\t// (and be properly handled by screen readers).\n\t *\t\twriter.setSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tsetSelection( selectable, placeOrOffset, options ) {\n\t\tthis.document.selection._setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Moves {@link module:engine/view/documentselection~DocumentSelection#focus selection's focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}\n\t * parameters.\n\t *\n\t * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tsetSelectionFocus( itemOrPosition, offset ) {\n\t\tthis.document.selection._setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/text~Text text node}.\n\t *\n\t *\t\twriter.createText( 'foo' );\n\t *\n\t * @param {String} data The text's data.\n\t * @returns {module:engine/view/text~Text} The created text node.\n\t */\n\tcreateText( data ) {\n\t\treturn new Text( data );\n\t}\n\n\t/**\n\t * Creates new {@link module:engine/view/attributeelement~AttributeElement}.\n\t *\n\t *\t\twriter.createAttributeElement( 'strong' );\n\t *\t\twriter.createAttributeElement( 'a', { href: 'foo.bar' } );\n\t *\n\t *\t\t// Make `<a>` element contain other attributes element so the `<a>` element is not broken.\n\t *\t\twriter.createAttributeElement( 'a', { href: 'foo.bar' }, { priority: 5 } );\n\t *\n\t *\t\t// Set `id` of a marker element so it is not joined or merged with \"normal\" elements.\n\t *\t\twriter.createAttributeElement( 'span', { class: 'my-marker' }, { id: 'marker:my' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Element's attributes.\n\t * @param {Object} [options] Element's options.\n\t * @param {Number} [options.priority] Element's {@link module:engine/view/attributeelement~AttributeElement#priority priority}.\n\t * @param {Number|String} [options.id] Element's {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t * @returns {module:engine/view/attributeelement~AttributeElement} Created element.\n\t */\n\tcreateAttributeElement( name, attributes, options = {} ) {\n\t\tconst attributeElement = new AttributeElement( name, attributes );\n\n\t\tif ( options.priority ) {\n\t\t\tattributeElement._priority = options.priority;\n\t\t}\n\n\t\tif ( options.id ) {\n\t\t\tattributeElement._id = options.id;\n\t\t}\n\n\t\treturn attributeElement;\n\t}\n\n\t/**\n\t * Creates new {@link module:engine/view/containerelement~ContainerElement}.\n\t *\n\t *\t\twriter.createContainerElement( 'p' );\n\t *\n\t *\t\t// Create element with custom attributes.\n\t *\t\twriter.createContainerElement( 'div', { id: 'foo-bar', 'data-baz': '123' } );\n\t *\n\t *\t\t// Create element with custom styles.\n\t *\t\twriter.createContainerElement( 'p', { style: 'font-weight: bold; padding-bottom: 10px' } );\n\t *\n\t *\t\t// Create element with custom classes.\n\t *\t\twriter.createContainerElement( 'p', { class: 'foo bar baz' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @returns {module:engine/view/containerelement~ContainerElement} Created element.\n\t */\n\tcreateContainerElement( name, attributes ) {\n\t\treturn new ContainerElement( name, attributes );\n\t}\n\n\t/**\n\t * Creates new {@link module:engine/view/editableelement~EditableElement}.\n\t *\n\t *\t\twriter.createEditableElement( 'div' );\n\t *\t\twriter.createEditableElement( 'div', { id: 'foo-1234' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @returns {module:engine/view/editableelement~EditableElement} Created element.\n\t */\n\tcreateEditableElement( name, attributes ) {\n\t\tconst editableElement = new EditableElement( name, attributes );\n\t\teditableElement._document = this.document;\n\n\t\treturn editableElement;\n\t}\n\n\t/**\n\t * Creates new {@link module:engine/view/emptyelement~EmptyElement}.\n\t *\n\t *\t\twriter.createEmptyElement( 'img' );\n\t *\t\twriter.createEmptyElement( 'img', { id: 'foo-1234' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @returns {module:engine/view/emptyelement~EmptyElement} Created element.\n\t */\n\tcreateEmptyElement( name, attributes ) {\n\t\treturn new EmptyElement( name, attributes );\n\t}\n\n\t/**\n\t * Creates new {@link module:engine/view/uielement~UIElement}.\n\t *\n\t *\t\twriter.createUIElement( 'span' );\n\t *\t\twriter.createUIElement( 'span', { id: 'foo-1234' } );\n\t *\n\t * Custom render function can be provided as third parameter:\n\t *\n\t *\t\twriter.createUIElement( 'span', null, function( domDocument ) {\n\t *\t\t\tconst domElement = this.toDomElement( domDocument );\n\t *\t\t\tdomElement.innerHTML = '<b>this is ui element</b>';\n\t *\n\t *\t\t\treturn domElement;\n\t *\t\t} );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @param {Function} [renderFunction] Custom render function.\n\t * @returns {module:engine/view/uielement~UIElement} Created element.\n\t */\n\tcreateUIElement( name, attributes, renderFunction ) {\n\t\tconst uiElement = new UIElement( name, attributes );\n\n\t\tif ( renderFunction ) {\n\t\t\tuiElement.render = renderFunction;\n\t\t}\n\n\t\treturn uiElement;\n\t}\n\n\t/**\n\t * Adds or overwrite element's attribute with a specified key and value.\n\t *\n\t *\t\twriter.setAttribute( 'href', 'http://ckeditor.com', linkElement );\n\t *\n\t * @param {String} key Attribute key.\n\t * @param {String} value Attribute value.\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tsetAttribute( key, value, element ) {\n\t\telement._setAttribute( key, value );\n\t}\n\n\t/**\n\t * Removes attribute from the element.\n\t *\n\t *\t\twriter.removeAttribute( 'href', linkElement );\n\t *\n\t * @param {String} key Attribute key.\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tremoveAttribute( key, element ) {\n\t\telement._removeAttribute( key );\n\t}\n\n\t/**\n\t * Adds specified class to the element.\n\t *\n\t *\t\twriter.addClass( 'foo', linkElement );\n\t *\t\twriter.addClass( [ 'foo', 'bar' ], linkElement );\n\t *\n\t * @param {Array.<String>|String} className\n\t * @param {module:engine/view/element~Element} element\n\t */\n\taddClass( className, element ) {\n\t\telement._addClass( className );\n\t}\n\n\t/**\n\t * Removes specified class from the element.\n\t *\n\t *\t\twriter.removeClass( 'foo', linkElement );\n\t *\t\twriter.removeClass( [ 'foo', 'bar' ], linkElement );\n\t *\n\t * @param {Array.<String>|String} className\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tremoveClass( className, element ) {\n\t\telement._removeClass( className );\n\t}\n\n\t/**\n\t * Adds style to the element.\n\t *\n\t *\t\twriter.setStyle( 'color', 'red', element );\n\t *\t\twriter.setStyle( {\n\t *\t\t\tcolor: 'red',\n\t *\t\t\tposition: 'fixed'\n\t *\t\t}, element );\n\t *\n\t * **Note**: The passed style can be normalized if\n\t * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details.\n\t *\n\t * @param {String|Object} property Property name or object with key - value pairs.\n\t * @param {String} [value] Value to set. This parameter is ignored if object is provided as the first parameter.\n\t * @param {module:engine/view/element~Element} element Element to set styles on.\n\t */\n\tsetStyle( property, value, element ) {\n\t\tif ( isPlainObject( property ) && element === undefined ) {\n\t\t\telement = value;\n\t\t}\n\n\t\telement._setStyle( property, value );\n\t}\n\n\t/**\n\t * Removes specified style from the element.\n\t *\n\t *\t\twriter.removeStyle( 'color', element ); // Removes 'color' style.\n\t *\t\twriter.removeStyle( [ 'color', 'border-top' ], element ); // Removes both 'color' and 'border-top' styles.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.\n\t *\n\t * @param {Array.<String>|String} property\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tremoveStyle( property, element ) {\n\t\telement._removeStyle( property );\n\t}\n\n\t/**\n\t * Sets a custom property on element. Unlike attributes, custom properties are not rendered to the DOM,\n\t * so they can be used to add special data to elements.\n\t *\n\t * @param {String|Symbol} key\n\t * @param {*} value\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tsetCustomProperty( key, value, element ) {\n\t\telement._setCustomProperty( key, value );\n\t}\n\n\t/**\n\t * Removes a custom property stored under the given key.\n\t *\n\t * @param {String|Symbol} key\n\t * @param {module:engine/view/element~Element} element\n\t * @returns {Boolean} Returns true if property was removed.\n\t */\n\tremoveCustomProperty( key, element ) {\n\t\treturn element._removeCustomProperty( key );\n\t}\n\n\t/**\n\t * Breaks attribute nodes at provided position or at boundaries of provided range. It breaks attribute elements inside\n\t * up to a container element.\n\t *\n\t * In following examples `<p>` is a container, `<b>` and `<u>` are attribute nodes:\n\t *\n\t *\t\t<p>foo<b><u>bar{}</u></b></p> -> <p>foo<b><u>bar</u></b>[]</p>\n\t *\t\t<p>foo<b><u>{}bar</u></b></p> -> <p>foo{}<b><u>bar</u></b></p>\n\t *\t\t<p>foo<b><u>b{}ar</u></b></p> -> <p>foo<b><u>b</u></b>[]<b><u>ar</u></b></p>\n\t *\t\t<p><b>fo{o</b><u>ba}r</u></p> -> <p><b>fo</b><b>o</b><u>ba</u><u>r</u></b></p>\n\t *\n\t * **Note:** {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment} is treated like a container.\n\t *\n\t * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer} is that `breakAttributes` breaks all\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of given `position`,\n\t * up to the first encountered {@link module:engine/view/containerelement~ContainerElement container element}.\n\t * `breakContainer` assumes that given `position` is directly in container element and breaks that container element.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container`\n\t * when {@link module:engine/view/range~Range#start start}\n\t * and {@link module:engine/view/range~Range#end end} positions of a passed range are not placed inside same parent container.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-empty-element`\n\t * when trying to break attributes\n\t * inside {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-ui-element`\n\t * when trying to break attributes\n\t * inside {@link module:engine/view/uielement~UIElement UIElement}.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#breakContainer\n\t * @param {module:engine/view/position~Position|module:engine/view/range~Range} positionOrRange Position where\n\t * to break attribute elements.\n\t * @returns {module:engine/view/position~Position|module:engine/view/range~Range} New position or range, after breaking the attribute\n\t * elements.\n\t */\n\tbreakAttributes( positionOrRange ) {\n\t\tif ( positionOrRange instanceof Position ) {\n\t\t\treturn this._breakAttributes( positionOrRange );\n\t\t} else {\n\t\t\treturn this._breakAttributesRange( positionOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Breaks {@link module:engine/view/containerelement~ContainerElement container view element} into two, at the given position. Position\n\t * has to be directly inside container element and cannot be in root. Does not break if position is at the beginning\n\t * or at the end of it's parent element.\n\t *\n\t *\t\t<p>foo^bar</p> -> <p>foo</p><p>bar</p>\n\t *\t\t<div><p>foo</p>^<p>bar</p></div> -> <div><p>foo</p></div><div><p>bar</p></div>\n\t *\t\t<p>^foobar</p> -> ^<p>foobar</p>\n\t *\t\t<p>foobar^</p> -> <p>foobar</p>^\n\t *\n\t * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer} is that `breakAttributes` breaks all\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of given `position`,\n\t * up to the first encountered {@link module:engine/view/containerelement~ContainerElement container element}.\n\t * `breakContainer` assumes that given `position` is directly in container element and breaks that container element.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#breakAttributes\n\t * @param {module:engine/view/position~Position} position Position where to break element.\n\t * @returns {module:engine/view/position~Position} Position between broken elements. If element has not been broken,\n\t * the returned position is placed either before it or after it.\n\t */\n\tbreakContainer( position ) {\n\t\tconst element = position.parent;\n\n\t\tif ( !( element.is( 'containerElement' ) ) ) {\n\t\t\t/**\n\t\t\t * Trying to break an element which is not a container element.\n\t\t\t *\n\t\t\t * @error view-writer-break-non-container-element\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-writer-break-non-container-element: Trying to break an element which is not a container element.',\n\t\t\t\tthis.document\n\t\t\t);\n\t\t}\n\n\t\tif ( !element.parent ) {\n\t\t\t/**\n\t\t\t * Trying to break root element.\n\t\t\t *\n\t\t\t * @error view-writer-break-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-break-root: Trying to break root element.', this.document );\n\t\t}\n\n\t\tif ( position.isAtStart ) {\n\t\t\treturn Position._createBefore( element );\n\t\t} else if ( !position.isAtEnd ) {\n\t\t\tconst newElement = element._clone( false );\n\n\t\t\tthis.insert( Position._createAfter( element ), newElement );\n\n\t\t\tconst sourceRange = new Range( position, Position._createAt( element, 'end' ) );\n\t\t\tconst targetPosition = new Position( newElement, 0 );\n\n\t\t\tthis.move( sourceRange, targetPosition );\n\t\t}\n\n\t\treturn Position._createAfter( element );\n\t}\n\n\t/**\n\t * Merges {@link module:engine/view/attributeelement~AttributeElement attribute elements}. It also merges text nodes if needed.\n\t * Only {@link module:engine/view/attributeelement~AttributeElement#isSimilar similar} attribute elements can be merged.\n\t *\n\t * In following examples `<p>` is a container and `<b>` is an attribute element:\n\t *\n\t *\t\t<p>foo[]bar</p> -> <p>foo{}bar</p>\n\t *\t\t<p><b>foo</b>[]<b>bar</b></p> -> <p><b>foo{}bar</b></p>\n\t *\t\t<p><b foo=\"bar\">a</b>[]<b foo=\"baz\">b</b></p> -> <p><b foo=\"bar\">a</b>[]<b foo=\"baz\">b</b></p>\n\t *\n\t * It will also take care about empty attributes when merging:\n\t *\n\t *\t\t<p><b>[]</b></p> -> <p>[]</p>\n\t *\t\t<p><b>foo</b><i>[]</i><b>bar</b></p> -> <p><b>foo{}bar</b></p>\n\t *\n\t * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#mergeAttributes mergeAttributes} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#mergeContainers mergeContainers} is that `mergeAttributes` merges two\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} or {@link module:engine/view/text~Text text nodes}\n\t * while `mergeContainer` merges two {@link module:engine/view/containerelement~ContainerElement container elements}.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#mergeContainers\n\t * @param {module:engine/view/position~Position} position Merge position.\n\t * @returns {module:engine/view/position~Position} Position after merge.\n\t */\n\tmergeAttributes( position ) {\n\t\tconst positionOffset = position.offset;\n\t\tconst positionParent = position.parent;\n\n\t\t// When inside text node - nothing to merge.\n\t\tif ( positionParent.is( 'text' ) ) {\n\t\t\treturn position;\n\t\t}\n\n\t\t// When inside empty attribute - remove it.\n\t\tif ( positionParent.is( 'attributeElement' ) && positionParent.childCount === 0 ) {\n\t\t\tconst parent = positionParent.parent;\n\t\t\tconst offset = positionParent.index;\n\n\t\t\tpositionParent._remove();\n\t\t\tthis._removeFromClonedElementsGroup( positionParent );\n\n\t\t\treturn this.mergeAttributes( new Position( parent, offset ) );\n\t\t}\n\n\t\tconst nodeBefore = positionParent.getChild( positionOffset - 1 );\n\t\tconst nodeAfter = positionParent.getChild( positionOffset );\n\n\t\t// Position should be placed between two nodes.\n\t\tif ( !nodeBefore || !nodeAfter ) {\n\t\t\treturn position;\n\t\t}\n\n\t\t// When position is between two text nodes.\n\t\tif ( nodeBefore.is( 'text' ) && nodeAfter.is( 'text' ) ) {\n\t\t\treturn mergeTextNodes( nodeBefore, nodeAfter );\n\t\t}\n\t\t// When position is between two same attribute elements.\n\t\telse if ( nodeBefore.is( 'attributeElement' ) && nodeAfter.is( 'attributeElement' ) && nodeBefore.isSimilar( nodeAfter ) ) {\n\t\t\t// Move all children nodes from node placed after selection and remove that node.\n\t\t\tconst count = nodeBefore.childCount;\n\t\t\tnodeBefore._appendChild( nodeAfter.getChildren() );\n\n\t\t\tnodeAfter._remove();\n\t\t\tthis._removeFromClonedElementsGroup( nodeAfter );\n\n\t\t\t// New position is located inside the first node, before new nodes.\n\t\t\t// Call this method recursively to merge again if needed.\n\t\t\treturn this.mergeAttributes( new Position( nodeBefore, count ) );\n\t\t}\n\n\t\treturn position;\n\t}\n\n\t/**\n\t * Merges two {@link module:engine/view/containerelement~ContainerElement container elements} that are before and after given position.\n\t * Precisely, the element after the position is removed and it's contents are moved to element before the position.\n\t *\n\t *\t\t<p>foo</p>^<p>bar</p> -> <p>foo^bar</p>\n\t *\t\t<div>foo</div>^<p>bar</p> -> <div>foo^bar</div>\n\t *\n\t * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#mergeAttributes mergeAttributes} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#mergeContainers mergeContainers} is that `mergeAttributes` merges two\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} or {@link module:engine/view/text~Text text nodes}\n\t * while `mergeContainer` merges two {@link module:engine/view/containerelement~ContainerElement container elements}.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#mergeAttributes\n\t * @param {module:engine/view/position~Position} position Merge position.\n\t * @returns {module:engine/view/position~Position} Position after merge.\n\t */\n\tmergeContainers( position ) {\n\t\tconst prev = position.nodeBefore;\n\t\tconst next = position.nodeAfter;\n\n\t\tif ( !prev || !next || !prev.is( 'containerElement' ) || !next.is( 'containerElement' ) ) {\n\t\t\t/**\n\t\t\t * Element before and after given position cannot be merged.\n\t\t\t *\n\t\t\t * @error view-writer-merge-containers-invalid-position\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-merge-containers-invalid-position: ' +\n\t\t\t\t'Element before and after given position cannot be merged.', this.document );\n\t\t}\n\n\t\tconst lastChild = prev.getChild( prev.childCount - 1 );\n\t\tconst newPosition = lastChild instanceof Text ? Position._createAt( lastChild, 'end' ) : Position._createAt( prev, 'end' );\n\n\t\tthis.move( Range._createIn( next ), Position._createAt( prev, 'end' ) );\n\t\tthis.remove( Range._createOn( next ) );\n\n\t\treturn newPosition;\n\t}\n\n\t/**\n\t * Insert node or nodes at specified position. Takes care about breaking attributes before insertion\n\t * and merging them afterwards.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-insert-invalid-node` when nodes to insert\n\t * contains instances that are not {@link module:engine/view/text~Text Texts},\n\t * {@link module:engine/view/attributeelement~AttributeElement AttributeElements},\n\t * {@link module:engine/view/containerelement~ContainerElement ContainerElements},\n\t * {@link module:engine/view/emptyelement~EmptyElement EmptyElements} or\n\t * {@link module:engine/view/uielement~UIElement UIElements}.\n\t *\n\t * @param {module:engine/view/position~Position} position Insertion position.\n\t * @param {module:engine/view/text~Text|module:engine/view/attributeelement~AttributeElement|\n\t * module:engine/view/containerelement~ContainerElement|module:engine/view/emptyelement~EmptyElement|\n\t * module:engine/view/uielement~UIElement|Iterable.<module:engine/view/text~Text|\n\t * module:engine/view/attributeelement~AttributeElement|module:engine/view/containerelement~ContainerElement|\n\t * module:engine/view/emptyelement~EmptyElement|module:engine/view/uielement~UIElement>} nodes Node or nodes to insert.\n\t * @returns {module:engine/view/range~Range} Range around inserted nodes.\n\t */\n\tinsert( position, nodes ) {\n\t\tnodes = isIterable( nodes ) ? [ ...nodes ] : [ nodes ];\n\n\t\t// Check if nodes to insert are instances of AttributeElements, ContainerElements, EmptyElements, UIElements or Text.\n\t\tvalidateNodesToInsert( nodes, this.document );\n\n\t\tconst container = getParentContainer( position );\n\n\t\tif ( !container ) {\n\t\t\t/**\n\t\t\t * Position's parent container cannot be found.\n\t\t\t *\n\t\t\t * @error view-writer-invalid-position-container\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-invalid-position-container', this.document );\n\t\t}\n\n\t\tconst insertionPosition = this._breakAttributes( position, true );\n\t\tconst length = container._insertChild( insertionPosition.offset, nodes );\n\n\t\tfor ( const node of nodes ) {\n\t\t\tthis._addToClonedElementsGroup( node );\n\t\t}\n\n\t\tconst endPosition = insertionPosition.getShiftedBy( length );\n\t\tconst start = this.mergeAttributes( insertionPosition );\n\n\t\t// When no nodes were inserted - return collapsed range.\n\t\tif ( length === 0 ) {\n\t\t\treturn new Range( start, start );\n\t\t} else {\n\t\t\t// If start position was merged - move end position.\n\t\t\tif ( !start.isEqual( insertionPosition ) ) {\n\t\t\t\tendPosition.offset--;\n\t\t\t}\n\n\t\t\tconst end = this.mergeAttributes( endPosition );\n\n\t\t\treturn new Range( start, end );\n\t\t}\n\t}\n\n\t/**\n\t * Removes provided range from the container.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range|module:engine/view/item~Item} rangeOrItem Range to remove from container\n\t * or an {@link module:engine/view/item~Item item} to remove. If range is provided, after removing, it will be updated\n\t * to a collapsed range showing the new position.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} Document fragment containing removed nodes.\n\t */\n\tremove( rangeOrItem ) {\n\t\tconst range = rangeOrItem instanceof Range ? rangeOrItem : Range._createOn( rangeOrItem );\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// If range is collapsed - nothing to remove.\n\t\tif ( range.isCollapsed ) {\n\t\t\treturn new DocumentFragment();\n\t\t}\n\n\t\t// Break attributes at range start and end.\n\t\tconst { start: breakStart, end: breakEnd } = this._breakAttributesRange( range, true );\n\t\tconst parentContainer = breakStart.parent;\n\n\t\tconst count = breakEnd.offset - breakStart.offset;\n\n\t\t// Remove nodes in range.\n\t\tconst removed = parentContainer._removeChildren( breakStart.offset, count );\n\n\t\tfor ( const node of removed ) {\n\t\t\tthis._removeFromClonedElementsGroup( node );\n\t\t}\n\n\t\t// Merge after removing.\n\t\tconst mergePosition = this.mergeAttributes( breakStart );\n\t\trange.start = mergePosition;\n\t\trange.end = mergePosition.clone();\n\n\t\t// Return removed nodes.\n\t\treturn new DocumentFragment( removed );\n\t}\n\n\t/**\n\t * Removes matching elements from given range.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range} range Range to clear.\n\t * @param {module:engine/view/element~Element} element Element to remove.\n\t */\n\tclear( range, element ) {\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// Create walker on given range.\n\t\t// We walk backward because when we remove element during walk it modifies range end position.\n\t\tconst walker = range.getWalker( {\n\t\t\tdirection: 'backward',\n\t\t\tignoreElementEnd: true\n\t\t} );\n\n\t\t// Let's walk.\n\t\tfor ( const current of walker ) {\n\t\t\tconst item = current.item;\n\t\t\tlet rangeToRemove;\n\n\t\t\t// When current item matches to the given element.\n\t\t\tif ( item.is( 'element' ) && element.isSimilar( item ) ) {\n\t\t\t\t// Create range on this element.\n\t\t\t\trangeToRemove = Range._createOn( item );\n\t\t\t\t// When range starts inside Text or TextProxy element.\n\t\t\t} else if ( !current.nextPosition.isAfter( range.start ) && item.is( 'textProxy' ) ) {\n\t\t\t\t// We need to check if parent of this text matches to given element.\n\t\t\t\tconst parentElement = item.getAncestors().find( ancestor => {\n\t\t\t\t\treturn ancestor.is( 'element' ) && element.isSimilar( ancestor );\n\t\t\t\t} );\n\n\t\t\t\t// If it is then create range inside this element.\n\t\t\t\tif ( parentElement ) {\n\t\t\t\t\trangeToRemove = Range._createIn( parentElement );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we have found element to remove.\n\t\t\tif ( rangeToRemove ) {\n\t\t\t\t// We need to check if element range stick out of the given range and truncate if it is.\n\t\t\t\tif ( rangeToRemove.end.isAfter( range.end ) ) {\n\t\t\t\t\trangeToRemove.end = range.end;\n\t\t\t\t}\n\n\t\t\t\tif ( rangeToRemove.start.isBefore( range.start ) ) {\n\t\t\t\t\trangeToRemove.start = range.start;\n\t\t\t\t}\n\n\t\t\t\t// At the end we remove range with found element.\n\t\t\t\tthis.remove( rangeToRemove );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Moves nodes from provided range to target position.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range} sourceRange Range containing nodes to move.\n\t * @param {module:engine/view/position~Position} targetPosition Position to insert.\n\t * @returns {module:engine/view/range~Range} Range in target container. Inserted nodes are placed between\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions.\n\t */\n\tmove( sourceRange, targetPosition ) {\n\t\tlet nodes;\n\n\t\tif ( targetPosition.isAfter( sourceRange.end ) ) {\n\t\t\ttargetPosition = this._breakAttributes( targetPosition, true );\n\n\t\t\tconst parent = targetPosition.parent;\n\t\t\tconst countBefore = parent.childCount;\n\n\t\t\tsourceRange = this._breakAttributesRange( sourceRange, true );\n\n\t\t\tnodes = this.remove( sourceRange );\n\n\t\t\ttargetPosition.offset += ( parent.childCount - countBefore );\n\t\t} else {\n\t\t\tnodes = this.remove( sourceRange );\n\t\t}\n\n\t\treturn this.insert( targetPosition, nodes );\n\t}\n\n\t/**\n\t * Wraps elements within range with provided {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t * If a collapsed range is provided, it will be wrapped only if it is equal to view selection.\n\t *\n\t * If a collapsed range was passed and is same as selection, the selection\n\t * will be moved to the inside of the wrapped attribute element.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-invalid-range-container`\n\t * when {@link module:engine/view/range~Range#start}\n\t * and {@link module:engine/view/range~Range#end} positions are not placed inside same parent container.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n\t * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-nonselection-collapsed-range` when passed range\n\t * is collapsed and different than view selection.\n\t *\n\t * @param {module:engine/view/range~Range} range Range to wrap.\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute Attribute element to use as wrapper.\n\t * @returns {module:engine/view/range~Range} range Range after wrapping, spanning over wrapping attribute element.\n\t*/\n\twrap( range, attribute ) {\n\t\tif ( !( attribute instanceof AttributeElement ) ) {\n\t\t\tthrow new CKEditorError( 'view-writer-wrap-invalid-attribute', this.document );\n\t\t}\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\tif ( !range.isCollapsed ) {\n\t\t\t// Non-collapsed range. Wrap it with the attribute element.\n\t\t\treturn this._wrapRange( range, attribute );\n\t\t} else {\n\t\t\t// Collapsed range. Wrap position.\n\t\t\tlet position = range.start;\n\n\t\t\tif ( position.parent.is( 'element' ) && !_hasNonUiChildren( position.parent ) ) {\n\t\t\t\tposition = position.getLastMatchingPosition( value => value.item.is( 'uiElement' ) );\n\t\t\t}\n\n\t\t\tposition = this._wrapPosition( position, attribute );\n\t\t\tconst viewSelection = this.document.selection;\n\n\t\t\t// If wrapping position is equal to view selection, move view selection inside wrapping attribute element.\n\t\t\tif ( viewSelection.isCollapsed && viewSelection.getFirstPosition().isEqual( range.start ) ) {\n\t\t\t\tthis.setSelection( position );\n\t\t\t}\n\n\t\t\treturn new Range( position );\n\t\t}\n\t}\n\n\t/**\n\t * Unwraps nodes within provided range from attribute element.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range} range\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute\n\t */\n\tunwrap( range, attribute ) {\n\t\tif ( !( attribute instanceof AttributeElement ) ) {\n\t\t\t/**\n\t\t\t * Attribute element need to be instance of attribute element.\n\t\t\t *\n\t\t\t * @error view-writer-unwrap-invalid-attribute\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-unwrap-invalid-attribute', this.document );\n\t\t}\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// If range is collapsed - nothing to unwrap.\n\t\tif ( range.isCollapsed ) {\n\t\t\treturn range;\n\t\t}\n\n\t\t// Break attributes at range start and end.\n\t\tconst { start: breakStart, end: breakEnd } = this._breakAttributesRange( range, true );\n\t\tconst parentContainer = breakStart.parent;\n\n\t\t// Unwrap children located between break points.\n\t\tconst newRange = this._unwrapChildren( parentContainer, breakStart.offset, breakEnd.offset, attribute );\n\n\t\t// Merge attributes at the both ends and return a new range.\n\t\tconst start = this.mergeAttributes( newRange.start );\n\n\t\t// If start position was merged - move end position back.\n\t\tif ( !start.isEqual( newRange.start ) ) {\n\t\t\tnewRange.end.offset--;\n\t\t}\n\n\t\tconst end = this.mergeAttributes( newRange.end );\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Renames element by creating a copy of renamed element but with changed name and then moving contents of the\n\t * old element to the new one. Keep in mind that this will invalidate all {@link module:engine/view/position~Position positions} which\n\t * has renamed element as {@link module:engine/view/position~Position#parent a parent}.\n\t *\n\t * New element has to be created because `Element#tagName` property in DOM is readonly.\n\t *\n\t * Since this function creates a new element and removes the given one, the new element is returned to keep reference.\n\t *\n\t * @param {String} newName New name for element.\n\t * @param {module:engine/view/containerelement~ContainerElement} viewElement Element to be renamed.\n\t */\n\trename( newName, viewElement ) {\n\t\tconst newElement = new ContainerElement( newName, viewElement.getAttributes() );\n\n\t\tthis.insert( Position._createAfter( viewElement ), newElement );\n\t\tthis.move( Range._createIn( viewElement ), Position._createAt( newElement, 0 ) );\n\t\tthis.remove( Range._createOn( viewElement ) );\n\n\t\treturn newElement;\n\t}\n\n\t/**\n\t * Cleans up memory by removing obsolete cloned elements group from the writer.\n\t *\n\t * Should be used whenever all {@link module:engine/view/attributeelement~AttributeElement attribute elements}\n\t * with the same {@link module:engine/view/attributeelement~AttributeElement#id id} are going to be removed from the view and\n\t * the group will no longer be needed.\n\t *\n\t * Cloned elements group are not removed automatically in case if the group is still needed after all its elements\n\t * were removed from the view.\n\t *\n\t * Keep in mind that group names are equal to the `id` property of the attribute element.\n\t *\n\t * @param {String} groupName Name of the group to clear.\n\t */\n\tclearClonedElementsGroup( groupName ) {\n\t\tthis._cloneGroups.delete( groupName );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link #createPositionBefore},\n\t * * {@link #createPositionAfter},\n\t *\n\t * @param {module:engine/view/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn Position._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn Position._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn Position._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn Range._createOn( item );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn Range._createIn( element );\n\t}\n\n\t/**\n\t Creates new {@link module:engine/view/selection~Selection} instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = writer.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'p' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = writer.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t * @returns {module:engine/view/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn new Selection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Wraps children with provided `wrapElement`. Only children contained in `parent` element between\n\t * `startOffset` and `endOffset` will be wrapped.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} parent\n\t * @param {Number} startOffset\n\t * @param {Number} endOffset\n\t * @param {module:engine/view/element~Element} wrapElement\n\t */\n\t_wrapChildren( parent, startOffset, endOffset, wrapElement ) {\n\t\tlet i = startOffset;\n\t\tconst wrapPositions = [];\n\n\t\twhile ( i < endOffset ) {\n\t\t\tconst child = parent.getChild( i );\n\t\t\tconst isText = child.is( 'text' );\n\t\t\tconst isAttribute = child.is( 'attributeElement' );\n\t\t\tconst isEmpty = child.is( 'emptyElement' );\n\t\t\tconst isUI = child.is( 'uiElement' );\n\n\t\t\t//\n\t\t\t// (In all examples, assume that `wrapElement` is `<span class=\"foo\">` element.)\n\t\t\t//\n\t\t\t// Check if `wrapElement` can be joined with the wrapped element. One of requirements is having same name.\n\t\t\t// If possible, join elements.\n\t\t\t//\n\t\t\t// <p><span class=\"bar\">abc</span></p> --> <p><span class=\"foo bar\">abc</span></p>\n\t\t\t//\n\t\t\tif ( isAttribute && this._wrapAttributeElement( wrapElement, child ) ) {\n\t\t\t\twrapPositions.push( new Position( parent, i ) );\n\t\t\t}\n\t\t\t//\n\t\t\t// Wrap the child if it is not an attribute element or if it is an attribute element that should be inside\n\t\t\t// `wrapElement` (due to priority).\n\t\t\t//\n\t\t\t// <p>abc</p> --> <p><span class=\"foo\">abc</span></p>\n\t\t\t// <p><strong>abc</strong></p> --> <p><span class=\"foo\"><strong>abc</strong></span></p>\n\t\t\t//\n\t\t\telse if ( isText || isEmpty || isUI || ( isAttribute && shouldABeOutsideB( wrapElement, child ) ) ) {\n\t\t\t\t// Clone attribute.\n\t\t\t\tconst newAttribute = wrapElement._clone();\n\n\t\t\t\t// Wrap current node with new attribute.\n\t\t\t\tchild._remove();\n\t\t\t\tnewAttribute._appendChild( child );\n\n\t\t\t\tparent._insertChild( i, newAttribute );\n\t\t\t\tthis._addToClonedElementsGroup( newAttribute );\n\n\t\t\t\twrapPositions.push( new Position( parent, i ) );\n\t\t\t}\n\t\t\t//\n\t\t\t// If other nested attribute is found and it wasn't wrapped (see above), continue wrapping inside it.\n\t\t\t//\n\t\t\t// <p><a href=\"foo.html\">abc</a></p> --> <p><a href=\"foo.html\"><span class=\"foo\">abc</span></a></p>\n\t\t\t//\n\t\t\telse if ( isAttribute ) {\n\t\t\t\tthis._wrapChildren( child, 0, child.childCount, wrapElement );\n\t\t\t}\n\n\t\t\ti++;\n\t\t}\n\n\t\t// Merge at each wrap.\n\t\tlet offsetChange = 0;\n\n\t\tfor ( const position of wrapPositions ) {\n\t\t\tposition.offset -= offsetChange;\n\n\t\t\t// Do not merge with elements outside selected children.\n\t\t\tif ( position.offset == startOffset ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst newPosition = this.mergeAttributes( position );\n\n\t\t\t// If nodes were merged - other merge offsets will change.\n\t\t\tif ( !newPosition.isEqual( position ) ) {\n\t\t\t\toffsetChange++;\n\t\t\t\tendOffset--;\n\t\t\t}\n\t\t}\n\n\t\treturn Range._createFromParentsAndOffsets( parent, startOffset, parent, endOffset );\n\t}\n\n\t/**\n\t * Unwraps children from provided `unwrapElement`. Only children contained in `parent` element between\n\t * `startOffset` and `endOffset` will be unwrapped.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} parent\n\t * @param {Number} startOffset\n\t * @param {Number} endOffset\n\t * @param {module:engine/view/element~Element} unwrapElement\n\t */\n\t_unwrapChildren( parent, startOffset, endOffset, unwrapElement ) {\n\t\tlet i = startOffset;\n\t\tconst unwrapPositions = [];\n\n\t\t// Iterate over each element between provided offsets inside parent.\n\t\t// We don't use tree walker or range iterator because we will be removing and merging potentially multiple nodes,\n\t\t// so it could get messy. It is safer to it manually in this case.\n\t\twhile ( i < endOffset ) {\n\t\t\tconst child = parent.getChild( i );\n\n\t\t\t// Skip all text nodes. There should be no container element's here either.\n\t\t\tif ( !child.is( 'attributeElement' ) ) {\n\t\t\t\ti++;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// (In all examples, assume that `unwrapElement` is `<span class=\"foo\">` element.)\n\t\t\t//\n\t\t\t// If the child is similar to the given attribute element, unwrap it - it will be completely removed.\n\t\t\t//\n\t\t\t// <p><span class=\"foo\">abc</span>xyz</p> --> <p>abcxyz</p>\n\t\t\t//\n\t\t\tif ( child.isSimilar( unwrapElement ) ) {\n\t\t\t\tconst unwrapped = child.getChildren();\n\t\t\t\tconst count = child.childCount;\n\n\t\t\t\t// Replace wrapper element with its children\n\t\t\t\tchild._remove();\n\t\t\t\tparent._insertChild( i, unwrapped );\n\n\t\t\t\tthis._removeFromClonedElementsGroup( child );\n\n\t\t\t\t// Save start and end position of moved items.\n\t\t\t\tunwrapPositions.push(\n\t\t\t\t\tnew Position( parent, i ),\n\t\t\t\t\tnew Position( parent, i + count )\n\t\t\t\t);\n\n\t\t\t\t// Skip elements that were unwrapped. Assuming there won't be another element to unwrap in child elements.\n\t\t\t\ti += count;\n\t\t\t\tendOffset += count - 1;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// If the child is not similar but is an attribute element, try partial unwrapping - remove the same attributes/styles/classes.\n\t\t\t// Partial unwrapping will happen only if the elements have the same name.\n\t\t\t//\n\t\t\t// <p><span class=\"foo bar\">abc</span>xyz</p> --> <p><span class=\"bar\">abc</span>xyz</p>\n\t\t\t// <p><i class=\"foo\">abc</i>xyz</p> --> <p><i class=\"foo\">abc</i>xyz</p>\n\t\t\t//\n\t\t\tif ( this._unwrapAttributeElement( unwrapElement, child ) ) {\n\t\t\t\tunwrapPositions.push(\n\t\t\t\t\tnew Position( parent, i ),\n\t\t\t\t\tnew Position( parent, i + 1 )\n\t\t\t\t);\n\n\t\t\t\ti++;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// If other nested attribute is found, look through it's children for elements to unwrap.\n\t\t\t//\n\t\t\t// <p><i><span class=\"foo\">abc</span></i><p> --> <p><i>abc</i><p>\n\t\t\t//\n\t\t\tthis._unwrapChildren( child, 0, child.childCount, unwrapElement );\n\n\t\t\ti++;\n\t\t}\n\n\t\t// Merge at each unwrap.\n\t\tlet offsetChange = 0;\n\n\t\tfor ( const position of unwrapPositions ) {\n\t\t\tposition.offset -= offsetChange;\n\n\t\t\t// Do not merge with elements outside selected children.\n\t\t\tif ( position.offset == startOffset || position.offset == endOffset ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst newPosition = this.mergeAttributes( position );\n\n\t\t\t// If nodes were merged - other merge offsets will change.\n\t\t\tif ( !newPosition.isEqual( position ) ) {\n\t\t\t\toffsetChange++;\n\t\t\t\tendOffset--;\n\t\t\t}\n\t\t}\n\n\t\treturn Range._createFromParentsAndOffsets( parent, startOffset, parent, endOffset );\n\t}\n\n\t/**\n\t * Helper function for `view.writer.wrap`. Wraps range with provided attribute element.\n\t * This method will also merge newly added attribute element with its siblings whenever possible.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n\t * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute\n\t * @returns {module:engine/view/range~Range} New range after wrapping, spanning over wrapping attribute element.\n\t */\n\t_wrapRange( range, attribute ) {\n\t\t// Break attributes at range start and end.\n\t\tconst { start: breakStart, end: breakEnd } = this._breakAttributesRange( range, true );\n\t\tconst parentContainer = breakStart.parent;\n\n\t\t// Wrap all children with attribute.\n\t\tconst newRange = this._wrapChildren( parentContainer, breakStart.offset, breakEnd.offset, attribute );\n\n\t\t// Merge attributes at the both ends and return a new range.\n\t\tconst start = this.mergeAttributes( newRange.start );\n\n\t\t// If start position was merged - move end position back.\n\t\tif ( !start.isEqual( newRange.start ) ) {\n\t\t\tnewRange.end.offset--;\n\t\t}\n\t\tconst end = this.mergeAttributes( newRange.end );\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Helper function for {@link #wrap}. Wraps position with provided attribute element.\n\t * This method will also merge newly added attribute element with its siblings whenever possible.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n\t * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} position\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute\n\t * @returns {module:engine/view/position~Position} New position after wrapping.\n\t */\n\t_wrapPosition( position, attribute ) {\n\t\t// Return same position when trying to wrap with attribute similar to position parent.\n\t\tif ( attribute.isSimilar( position.parent ) ) {\n\t\t\treturn movePositionToTextNode( position.clone() );\n\t\t}\n\n\t\t// When position is inside text node - break it and place new position between two text nodes.\n\t\tif ( position.parent.is( 'text' ) ) {\n\t\t\tposition = breakTextNode( position );\n\t\t}\n\n\t\t// Create fake element that will represent position, and will not be merged with other attributes.\n\t\tconst fakePosition = this.createAttributeElement();\n\t\tfakePosition._priority = Number.POSITIVE_INFINITY;\n\t\tfakePosition.isSimilar = () => false;\n\n\t\t// Insert fake element in position location.\n\t\tposition.parent._insertChild( position.offset, fakePosition );\n\n\t\t// Range around inserted fake attribute element.\n\t\tconst wrapRange = new Range( position, position.getShiftedBy( 1 ) );\n\n\t\t// Wrap fake element with attribute (it will also merge if possible).\n\t\tthis.wrap( wrapRange, attribute );\n\n\t\t// Remove fake element and place new position there.\n\t\tconst newPosition = new Position( fakePosition.parent, fakePosition.index );\n\t\tfakePosition._remove();\n\n\t\t// If position is placed between text nodes - merge them and return position inside.\n\t\tconst nodeBefore = newPosition.nodeBefore;\n\t\tconst nodeAfter = newPosition.nodeAfter;\n\n\t\tif ( nodeBefore instanceof Text && nodeAfter instanceof Text ) {\n\t\t\treturn mergeTextNodes( nodeBefore, nodeAfter );\n\t\t}\n\n\t\t// If position is next to text node - move position inside.\n\t\treturn movePositionToTextNode( newPosition );\n\t}\n\n\t/**\n\t * \tWraps one {@link module:engine/view/attributeelement~AttributeElement AttributeElement} into another by\n\t * \tmerging them if possible. When merging is possible - all attributes, styles and classes are moved from wrapper\n\t * \telement to element being wrapped.\n\t *\n\t * \t@private\n\t * \t@param {module:engine/view/attributeelement~AttributeElement} wrapper Wrapper AttributeElement.\n\t * \t@param {module:engine/view/attributeelement~AttributeElement} toWrap AttributeElement to wrap using wrapper element.\n\t * \t@returns {Boolean} Returns `true` if elements are merged.\n\t */\n\t_wrapAttributeElement( wrapper, toWrap ) {\n\t\tif ( !canBeJoined( wrapper, toWrap ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Can't merge if name or priority differs.\n\t\tif ( wrapper.name !== toWrap.name || wrapper.priority !== toWrap.priority ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if attributes can be merged.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If some attributes are different we cannot wrap.\n\t\t\tif ( toWrap.hasAttribute( key ) && toWrap.getAttribute( key ) !== wrapper.getAttribute( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if styles can be merged.\n\t\tfor ( const key of wrapper.getStyleNames() ) {\n\t\t\tif ( toWrap.hasStyle( key ) && toWrap.getStyle( key ) !== wrapper.getStyle( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Move all attributes/classes/styles from wrapper to wrapped AttributeElement.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Move only these attributes that are not present - other are similar.\n\t\t\tif ( !toWrap.hasAttribute( key ) ) {\n\t\t\t\tthis.setAttribute( key, wrapper.getAttribute( key ), toWrap );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const key of wrapper.getStyleNames() ) {\n\t\t\tif ( !toWrap.hasStyle( key ) ) {\n\t\t\t\tthis.setStyle( key, wrapper.getStyle( key ), toWrap );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const key of wrapper.getClassNames() ) {\n\t\t\tif ( !toWrap.hasClass( key ) ) {\n\t\t\t\tthis.addClass( key, toWrap );\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Unwraps {@link module:engine/view/attributeelement~AttributeElement AttributeElement} from another by removing\n\t * corresponding attributes, classes and styles. All attributes, classes and styles from wrapper should be present\n\t * inside element being unwrapped.\n\t *\n\t * @private\n\t * @param {module:engine/view/attributeelement~AttributeElement} wrapper Wrapper AttributeElement.\n\t * @param {module:engine/view/attributeelement~AttributeElement} toUnwrap AttributeElement to unwrap using wrapper element.\n\t * @returns {Boolean} Returns `true` if elements are unwrapped.\n\t **/\n\t_unwrapAttributeElement( wrapper, toUnwrap ) {\n\t\tif ( !canBeJoined( wrapper, toUnwrap ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Can't unwrap if name or priority differs.\n\t\tif ( wrapper.name !== toUnwrap.name || wrapper.priority !== toUnwrap.priority ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if AttributeElement has all wrapper attributes.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If some attributes are missing or different we cannot unwrap.\n\t\t\tif ( !toUnwrap.hasAttribute( key ) || toUnwrap.getAttribute( key ) !== wrapper.getAttribute( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if AttributeElement has all wrapper classes.\n\t\tif ( !toUnwrap.hasClass( ...wrapper.getClassNames() ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if AttributeElement has all wrapper styles.\n\t\tfor ( const key of wrapper.getStyleNames() ) {\n\t\t\t// If some styles are missing or different we cannot unwrap.\n\t\t\tif ( !toUnwrap.hasStyle( key ) || toUnwrap.getStyle( key ) !== wrapper.getStyle( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Remove all wrapper's attributes from unwrapped element.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.removeAttribute( key, toUnwrap );\n\t\t}\n\n\t\t// Remove all wrapper's classes from unwrapped element.\n\t\tthis.removeClass( Array.from( wrapper.getClassNames() ), toUnwrap );\n\n\t\t// Remove all wrapper's styles from unwrapped element.\n\t\tthis.removeStyle( Array.from( wrapper.getStyleNames() ), toUnwrap );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Helper function used by other `DowncastWriter` methods. Breaks attribute elements at the boundaries of given range.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range Range which `start` and `end` positions will be used to break attributes.\n\t * @param {Boolean} [forceSplitText=false] If set to `true`, will break text nodes even if they are directly in container element.\n\t * This behavior will result in incorrect view state, but is needed by other view writing methods which then fixes view state.\n\t * @returns {module:engine/view/range~Range} New range with located at break positions.\n\t */\n\t_breakAttributesRange( range, forceSplitText = false ) {\n\t\tconst rangeStart = range.start;\n\t\tconst rangeEnd = range.end;\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// Break at the collapsed position. Return new collapsed range.\n\t\tif ( range.isCollapsed ) {\n\t\t\tconst position = this._breakAttributes( range.start, forceSplitText );\n\n\t\t\treturn new Range( position, position );\n\t\t}\n\n\t\tconst breakEnd = this._breakAttributes( rangeEnd, forceSplitText );\n\t\tconst count = breakEnd.parent.childCount;\n\t\tconst breakStart = this._breakAttributes( rangeStart, forceSplitText );\n\n\t\t// Calculate new break end offset.\n\t\tbreakEnd.offset += breakEnd.parent.childCount - count;\n\n\t\treturn new Range( breakStart, breakEnd );\n\t}\n\n\t/**\n\t * Helper function used by other `DowncastWriter` methods. Breaks attribute elements at given position.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-empty-element` when break position\n\t * is placed inside {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-ui-element` when break position\n\t * is placed inside {@link module:engine/view/uielement~UIElement UIElement}.\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} position Position where to break attributes.\n\t * @param {Boolean} [forceSplitText=false] If set to `true`, will break text nodes even if they are directly in container element.\n\t * This behavior will result in incorrect view state, but is needed by other view writing methods which then fixes view state.\n\t * @returns {module:engine/view/position~Position} New position after breaking the attributes.\n\t */\n\t_breakAttributes( position, forceSplitText = false ) {\n\t\tconst positionOffset = position.offset;\n\t\tconst positionParent = position.parent;\n\n\t\t// If position is placed inside EmptyElement - throw an exception as we cannot break inside.\n\t\tif ( position.parent.is( 'emptyElement' ) ) {\n\t\t\t/**\n\t\t\t * Cannot break inside EmptyElement instance.\n\t\t\t *\n\t\t\t * @error view-writer-cannot-break-empty-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-cannot-break-empty-element', this.document );\n\t\t}\n\n\t\t// If position is placed inside UIElement - throw an exception as we cannot break inside.\n\t\tif ( position.parent.is( 'uiElement' ) ) {\n\t\t\t/**\n\t\t\t * Cannot break inside UIElement instance.\n\t\t\t *\n\t\t\t * @error view-writer-cannot-break-ui-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-cannot-break-ui-element', this.document );\n\t\t}\n\n\t\t// There are no attributes to break and text nodes breaking is not forced.\n\t\tif ( !forceSplitText && positionParent.is( 'text' ) && isContainerOrFragment( positionParent.parent ) ) {\n\t\t\treturn position.clone();\n\t\t}\n\n\t\t// Position's parent is container, so no attributes to break.\n\t\tif ( isContainerOrFragment( positionParent ) ) {\n\t\t\treturn position.clone();\n\t\t}\n\n\t\t// Break text and start again in new position.\n\t\tif ( positionParent.is( 'text' ) ) {\n\t\t\treturn this._breakAttributes( breakTextNode( position ), forceSplitText );\n\t\t}\n\n\t\tconst length = positionParent.childCount;\n\n\t\t// <p>foo<b><u>bar{}</u></b></p>\n\t\t// <p>foo<b><u>bar</u>[]</b></p>\n\t\t// <p>foo<b><u>bar</u></b>[]</p>\n\t\tif ( positionOffset == length ) {\n\t\t\tconst newPosition = new Position( positionParent.parent, positionParent.index + 1 );\n\n\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t} else {\n\t\t\t// <p>foo<b><u>{}bar</u></b></p>\n\t\t\t// <p>foo<b>[]<u>bar</u></b></p>\n\t\t\t// <p>foo{}<b><u>bar</u></b></p>\n\t\t\tif ( positionOffset === 0 ) {\n\t\t\t\tconst newPosition = new Position( positionParent.parent, positionParent.index );\n\n\t\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t\t}\n\t\t\t// <p>foo<b><u>b{}ar</u></b></p>\n\t\t\t// <p>foo<b><u>b[]ar</u></b></p>\n\t\t\t// <p>foo<b><u>b</u>[]<u>ar</u></b></p>\n\t\t\t// <p>foo<b><u>b</u></b>[]<b><u>ar</u></b></p>\n\t\t\telse {\n\t\t\t\tconst offsetAfter = positionParent.index + 1;\n\n\t\t\t\t// Break element.\n\t\t\t\tconst clonedNode = positionParent._clone();\n\n\t\t\t\t// Insert cloned node to position's parent node.\n\t\t\t\tpositionParent.parent._insertChild( offsetAfter, clonedNode );\n\t\t\t\tthis._addToClonedElementsGroup( clonedNode );\n\n\t\t\t\t// Get nodes to move.\n\t\t\t\tconst count = positionParent.childCount - positionOffset;\n\t\t\t\tconst nodesToMove = positionParent._removeChildren( positionOffset, count );\n\n\t\t\t\t// Move nodes to cloned node.\n\t\t\t\tclonedNode._appendChild( nodesToMove );\n\n\t\t\t\t// Create new position to work on.\n\t\t\t\tconst newPosition = new Position( positionParent.parent, offsetAfter );\n\n\t\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Stores the information that an {@link module:engine/view/attributeelement~AttributeElement attribute element} was\n\t * added to the tree. Saves the reference to the group in the given element and updates the group, so other elements\n\t * from the group now keep a reference to the given attribute element.\n\t *\n\t * The clones group can be obtained using {@link module:engine/view/attributeelement~AttributeElement#getElementsWithSameId}.\n\t *\n\t * Does nothing if added element has no {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t *\n\t * @private\n\t * @param {module:engine/view/attributeelement~AttributeElement} element Attribute element to save.\n\t */\n\t_addToClonedElementsGroup( element ) {\n\t\t// Add only if the element is in document tree.\n\t\tif ( !element.root.is( 'rootElement' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Traverse the element's children recursively to find other attribute elements that also might got inserted.\n\t\t// The loop is at the beginning so we can make fast returns later in the code.\n\t\tif ( element.is( 'element' ) ) {\n\t\t\tfor ( const child of element.getChildren() ) {\n\t\t\t\tthis._addToClonedElementsGroup( child );\n\t\t\t}\n\t\t}\n\n\t\tconst id = element.id;\n\n\t\tif ( !id ) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet group = this._cloneGroups.get( id );\n\n\t\tif ( !group ) {\n\t\t\tgroup = new Set();\n\t\t\tthis._cloneGroups.set( id, group );\n\t\t}\n\n\t\tgroup.add( element );\n\t\telement._clonesGroup = group;\n\t}\n\n\t/**\n\t * Removes all the information about the given {@link module:engine/view/attributeelement~AttributeElement attribute element}\n\t * from its clones group.\n\t *\n\t * Keep in mind, that the element will still keep a reference to the group (but the group will not keep a reference to it).\n\t * This allows to reference the whole group even if the element was already removed from the tree.\n\t *\n\t * Does nothing if the element has no {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t *\n\t * @private\n\t * @param {module:engine/view/attributeelement~AttributeElement} element Attribute element to remove.\n\t */\n\t_removeFromClonedElementsGroup( element ) {\n\t\t// Traverse the element's children recursively to find other attribute elements that also got removed.\n\t\t// The loop is at the beginning so we can make fast returns later in the code.\n\t\tif ( element.is( 'element' ) ) {\n\t\t\tfor ( const child of element.getChildren() ) {\n\t\t\t\tthis._removeFromClonedElementsGroup( child );\n\t\t\t}\n\t\t}\n\n\t\tconst id = element.id;\n\n\t\tif ( !id ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst group = this._cloneGroups.get( id );\n\n\t\tif ( !group ) {\n\t\t\treturn;\n\t\t}\n\n\t\tgroup.delete( element );\n\t\t// Not removing group from element on purpose!\n\t\t// If other parts of code have reference to this element, they will be able to get references to other elements from the group.\n\t}\n}\n\n// Helper function for `view.writer.wrap`. Checks if given element has any children that are not ui elements.\nfunction _hasNonUiChildren( parent ) {\n\treturn Array.from( parent.getChildren() ).some( child => !child.is( 'uiElement' ) );\n}\n\n/**\n * Attribute element need to be instance of attribute element.\n *\n * @error view-writer-wrap-invalid-attribute\n */\n\n// Returns first parent container of specified {@link module:engine/view/position~Position Position}.\n// Position's parent node is checked as first, then next parents are checked.\n// Note that {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment} is treated like a container.\n//\n// @param {module:engine/view/position~Position} position Position used as a start point to locate parent container.\n// @returns {module:engine/view/containerelement~ContainerElement|module:engine/view/documentfragment~DocumentFragment|undefined}\n// Parent container element or `undefined` if container is not found.\nfunction getParentContainer( position ) {\n\tlet parent = position.parent;\n\n\twhile ( !isContainerOrFragment( parent ) ) {\n\t\tif ( !parent ) {\n\t\t\treturn undefined;\n\t\t}\n\t\tparent = parent.parent;\n\t}\n\n\treturn parent;\n}\n\n// Checks if first {@link module:engine/view/attributeelement~AttributeElement AttributeElement} provided to the function\n// can be wrapped otuside second element. It is done by comparing elements'\n// {@link module:engine/view/attributeelement~AttributeElement#priority priorities}, if both have same priority\n// {@link module:engine/view/element~Element#getIdentity identities} are compared.\n//\n// @param {module:engine/view/attributeelement~AttributeElement} a\n// @param {module:engine/view/attributeelement~AttributeElement} b\n// @returns {Boolean}\nfunction shouldABeOutsideB( a, b ) {\n\tif ( a.priority < b.priority ) {\n\t\treturn true;\n\t} else if ( a.priority > b.priority ) {\n\t\treturn false;\n\t}\n\n\t// When priorities are equal and names are different - use identities.\n\treturn a.getIdentity() < b.getIdentity();\n}\n\n// Returns new position that is moved to near text node. Returns same position if there is no text node before of after\n// specified position.\n//\n//\t\t<p>foo[]</p> -> <p>foo{}</p>\n//\t\t<p>[]foo</p> -> <p>{}foo</p>\n//\n// @param {module:engine/view/position~Position} position\n// @returns {module:engine/view/position~Position} Position located inside text node or same position if there is no text nodes\n// before or after position location.\nfunction movePositionToTextNode( position ) {\n\tconst nodeBefore = position.nodeBefore;\n\n\tif ( nodeBefore && nodeBefore.is( 'text' ) ) {\n\t\treturn new Position( nodeBefore, nodeBefore.data.length );\n\t}\n\n\tconst nodeAfter = position.nodeAfter;\n\n\tif ( nodeAfter && nodeAfter.is( 'text' ) ) {\n\t\treturn new Position( nodeAfter, 0 );\n\t}\n\n\treturn position;\n}\n\n// Breaks text node into two text nodes when possible.\n//\n//\t\t<p>foo{}bar</p> -> <p>foo[]bar</p>\n//\t\t<p>{}foobar</p> -> <p>[]foobar</p>\n//\t\t<p>foobar{}</p> -> <p>foobar[]</p>\n//\n// @param {module:engine/view/position~Position} position Position that need to be placed inside text node.\n// @returns {module:engine/view/position~Position} New position after breaking text node.\nfunction breakTextNode( position ) {\n\tif ( position.offset == position.parent.data.length ) {\n\t\treturn new Position( position.parent.parent, position.parent.index + 1 );\n\t}\n\n\tif ( position.offset === 0 ) {\n\t\treturn new Position( position.parent.parent, position.parent.index );\n\t}\n\n\t// Get part of the text that need to be moved.\n\tconst textToMove = position.parent.data.slice( position.offset );\n\n\t// Leave rest of the text in position's parent.\n\tposition.parent._data = position.parent.data.slice( 0, position.offset );\n\n\t// Insert new text node after position's parent text node.\n\tposition.parent.parent._insertChild( position.parent.index + 1, new Text( textToMove ) );\n\n\t// Return new position between two newly created text nodes.\n\treturn new Position( position.parent.parent, position.parent.index + 1 );\n}\n\n// Merges two text nodes into first node. Removes second node and returns merge position.\n//\n// @param {module:engine/view/text~Text} t1 First text node to merge. Data from second text node will be moved at the end of\n// this text node.\n// @param {module:engine/view/text~Text} t2 Second text node to merge. This node will be removed after merging.\n// @returns {module:engine/view/position~Position} Position after merging text nodes.\nfunction mergeTextNodes( t1, t2 ) {\n\t// Merge text data into first text node and remove second one.\n\tconst nodeBeforeLength = t1.data.length;\n\tt1._data += t2.data;\n\tt2._remove();\n\n\treturn new Position( t1, nodeBeforeLength );\n}\n\n// Checks if provided nodes are valid to insert. Checks if each node is an instance of\n// {@link module:engine/view/text~Text Text} or {@link module:engine/view/attributeelement~AttributeElement AttributeElement},\n// {@link module:engine/view/containerelement~ContainerElement ContainerElement},\n// {@link module:engine/view/emptyelement~EmptyElement EmptyElement} or\n// {@link module:engine/view/uielement~UIElement UIElement}.\n//\n// Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-insert-invalid-node` when nodes to insert\n// contains instances that are not {@link module:engine/view/text~Text Texts},\n// {@link module:engine/view/emptyelement~EmptyElement EmptyElements},\n// {@link module:engine/view/uielement~UIElement UIElements},\n// {@link module:engine/view/attributeelement~AttributeElement AttributeElements} or\n// {@link module:engine/view/containerelement~ContainerElement ContainerElements}.\n//\n// @param Iterable.<module:engine/view/text~Text|module:engine/view/attributeelement~AttributeElement\n// |module:engine/view/containerelement~ContainerElement> nodes\n// @param {Object} errorContext\nfunction validateNodesToInsert( nodes, errorContext ) {\n\tfor ( const node of nodes ) {\n\t\tif ( !validNodesToInsert.some( ( validNode => node instanceof validNode ) ) ) { // eslint-disable-line no-use-before-define\n\t\t\t/**\n\t\t\t * Inserted nodes should be valid to insert. of {@link module:engine/view/attributeelement~AttributeElement AttributeElement},\n\t\t\t * {@link module:engine/view/containerelement~ContainerElement ContainerElement},\n\t\t\t * {@link module:engine/view/emptyelement~EmptyElement EmptyElement},\n\t\t\t * {@link module:engine/view/uielement~UIElement UIElement}, {@link module:engine/view/text~Text Text}.\n\t\t\t *\n\t\t\t * @error view-writer-insert-invalid-node\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-insert-invalid-node', errorContext );\n\t\t}\n\n\t\tif ( !node.is( 'text' ) ) {\n\t\t\tvalidateNodesToInsert( node.getChildren(), errorContext );\n\t\t}\n\t}\n}\n\nconst validNodesToInsert = [ Text, AttributeElement, ContainerElement, EmptyElement, UIElement ];\n\n// Checks if node is ContainerElement or DocumentFragment, because in most cases they should be treated the same way.\n//\n// @param {module:engine/view/node~Node} node\n// @returns {Boolean} Returns `true` if node is instance of ContainerElement or DocumentFragment.\nfunction isContainerOrFragment( node ) {\n\treturn node && ( node.is( 'containerElement' ) || node.is( 'documentFragment' ) );\n}\n\n// Checks if {@link module:engine/view/range~Range#start range start} and {@link module:engine/view/range~Range#end range end} are placed\n// inside same {@link module:engine/view/containerelement~ContainerElement container element}.\n// Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when validation fails.\n//\n// @param {module:engine/view/range~Range} range\n// @param {Object} errorContext\nfunction validateRangeContainer( range, errorContext ) {\n\tconst startContainer = getParentContainer( range.start );\n\tconst endContainer = getParentContainer( range.end );\n\n\tif ( !startContainer || !endContainer || startContainer !== endContainer ) {\n\t\t/**\n\t\t * Range container is invalid. This can happen if {@link module:engine/view/range~Range#start range start} and\n\t\t * {@link module:engine/view/range~Range#end range end} positions are not placed inside same container or\n\t\t * parent container for these positions cannot be found.\n\t\t *\n\t\t * @error view-writer-invalid-range-container\n\t\t */\n\n\t\tthrow new CKEditorError( 'view-writer-invalid-range-container', errorContext );\n\t}\n}\n\n// Checks if two attribute elements can be joined together. Elements can be joined together if, and only if\n// they do not have ids specified.\n//\n// @private\n// @param {module:engine/view/element~Element} a\n// @param {module:engine/view/element~Element} b\n// @returns {Boolean}\nfunction canBeJoined( a, b ) {\n\treturn a.id === null && b.id === null;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/istext\n */\n\n/**\n * Checks if the object is a native DOM Text node.\n *\n * @param {*} obj\n * @returns {Boolean}\n */\nexport default function isText( obj ) {\n\treturn Object.prototype.toString.call( obj ) == '[object Text]';\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport isText from '@ckeditor/ckeditor5-utils/src/dom/istext';\n\n/**\n * Set of utils related to block and inline fillers handling.\n *\n * Browsers do not allow to put caret in elements which does not have height. Because of it, we need to fill all\n * empty elements which should be selectable with elements or characters called \"fillers\". Unfortunately there is no one\n * universal filler, this is why two types are uses:\n *\n * * Block filler is an element which fill block elements, like `<p>`. CKEditor uses `<br>` as a block filler during the editing,\n * as browsers do natively. So instead of an empty `<p>` there will be `<p><br></p>`. The advantage of block filler is that\n * it is transparent for the selection, so when the caret is before the `<br>` and user presses right arrow he will be\n * moved to the next paragraph, not after the `<br>`. The disadvantage is that it breaks a block, so it can not be used\n * in the middle of a line of text. The {@link module:engine/view/filler~BR_FILLER `<br>` filler} can be replaced with any other\n * character in the data output, for instance {@link module:engine/view/filler~NBSP_FILLER non-breaking space}.\n *\n * * Inline filler is a filler which does not break a line of text, so it can be used inside the text, for instance in the empty\n * `<b>` surrendered by text: `foo<b></b>bar`, if we want to put the caret there. CKEditor uses a sequence of the zero-width\n * spaces as an {@link module:engine/view/filler~INLINE_FILLER inline filler} having the predetermined\n * {@link module:engine/view/filler~INLINE_FILLER_LENGTH length}. A sequence is used, instead of a single character to\n * avoid treating random zero-width spaces as the inline filler. Disadvantage of the inline filler is that it is not\n * transparent for the selection. The arrow key moves the caret between zero-width spaces characters, so the additional\n * code is needed to handle the caret.\n *\n * Both inline and block fillers are handled by the {@link module:engine/view/renderer~Renderer renderer} and are not present in the\n * view.\n *\n * @module engine/view/filler\n */\n\n/**\n * Non-breaking space filler creator. This is a function which creates ` ` text node.\n * It defines how the filler is created.\n *\n * @see module:engine/view/filler~BR_FILLER\n * @function\n */\nexport const NBSP_FILLER = domDocument => domDocument.createTextNode( '\\u00A0' );\n\n/**\n * `<br>` filler creator. This is a function which creates `<br data-cke-filler=\"true\">` element.\n * It defines how the filler is created.\n *\n * @see module:engine/view/filler~NBSP_FILLER\n * @function\n */\nexport const BR_FILLER = domDocument => {\n\tconst fillerBr = domDocument.createElement( 'br' );\n\tfillerBr.dataset.ckeFiller = true;\n\n\treturn fillerBr;\n};\n\n/**\n * Length of the {@link module:engine/view/filler~INLINE_FILLER INLINE_FILLER}.\n */\nexport const INLINE_FILLER_LENGTH = 7;\n\n/**\n * Inline filler which is a sequence of the zero width spaces.\n */\nexport const INLINE_FILLER = ( () => {\n\tlet inlineFiller = '';\n\n\tfor ( let i = 0; i < INLINE_FILLER_LENGTH; i++ ) {\n\t\tinlineFiller += '\\u200b';\n\t}\n\n\treturn inlineFiller;\n} )(); // Usu IIF so the INLINE_FILLER appears as a constant in the docs.\n\n/**\n * Checks if the node is a text node which starts with the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n *\n *\t\tstartsWithFiller( document.createTextNode( INLINE_FILLER ) ); // true\n *\t\tstartsWithFiller( document.createTextNode( INLINE_FILLER + 'foo' ) ); // true\n *\t\tstartsWithFiller( document.createTextNode( 'foo' ) ); // false\n *\t\tstartsWithFiller( document.createElement( 'p' ) ); // false\n *\n * @param {Node} domNode DOM node.\n * @returns {Boolean} True if the text node starts with the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n */\nexport function startsWithFiller( domNode ) {\n\treturn isText( domNode ) && ( domNode.data.substr( 0, INLINE_FILLER_LENGTH ) === INLINE_FILLER );\n}\n\n/**\n * Checks if the text node contains only the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n *\n *\t\tisInlineFiller( document.createTextNode( INLINE_FILLER ) ); // true\n *\t\tisInlineFiller( document.createTextNode( INLINE_FILLER + 'foo' ) ); // false\n *\n * @param {Text} domText DOM text node.\n * @returns {Boolean} True if the text node contains only the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n */\nexport function isInlineFiller( domText ) {\n\treturn domText.data.length == INLINE_FILLER_LENGTH && startsWithFiller( domText );\n}\n\n/**\n * Get string data from the text node, removing an {@link module:engine/view/filler~INLINE_FILLER inline filler} from it,\n * if text node contains it.\n *\n *\t\tgetDataWithoutFiller( document.createTextNode( INLINE_FILLER + 'foo' ) ) == 'foo' // true\n *\t\tgetDataWithoutFiller( document.createTextNode( 'foo' ) ) == 'foo' // true\n *\n * @param {Text} domText DOM text node, possible with inline filler.\n * @returns {String} Data without filler.\n */\nexport function getDataWithoutFiller( domText ) {\n\tif ( startsWithFiller( domText ) ) {\n\t\treturn domText.data.slice( INLINE_FILLER_LENGTH );\n\t} else {\n\t\treturn domText.data;\n\t}\n}\n\n/**\n * Assign key observer which move cursor from the end of the inline filler to the beginning of it when\n * the left arrow is pressed, so the filler does not break navigation.\n *\n * @param {module:engine/view/view~View} view View controller instance we should inject quirks handling on.\n */\nexport function injectQuirksHandling( view ) {\n\tview.document.on( 'keydown', jumpOverInlineFiller );\n}\n\n// Move cursor from the end of the inline filler to the beginning of it when, so the filler does not break navigation.\nfunction jumpOverInlineFiller( evt, data ) {\n\tif ( data.keyCode == keyCodes.arrowleft ) {\n\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\n\t\tif ( domSelection.rangeCount == 1 && domSelection.getRangeAt( 0 ).collapsed ) {\n\t\t\tconst domParent = domSelection.getRangeAt( 0 ).startContainer;\n\t\t\tconst domOffset = domSelection.getRangeAt( 0 ).startOffset;\n\n\t\t\tif ( startsWithFiller( domParent ) && domOffset <= INLINE_FILLER_LENGTH ) {\n\t\t\t\tdomSelection.collapse( domParent, 0 );\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/fastdiff\n */\n\n/**\n * Finds positions of the first and last change in the given string/array and generates a set of changes:\n *\n *\t\tfastDiff( '12a', '12xyza' );\n *\t\t// [ { index: 2, type: 'insert', values: [ 'x', 'y', 'z' ] } ]\n *\n *\t\tfastDiff( '12a', '12aa' );\n *\t\t// [ { index: 3, type: 'insert', values: [ 'a' ] } ]\n *\n *\t\tfastDiff( '12xyza', '12a' );\n *\t\t// [ { index: 2, type: 'delete', howMany: 3 } ]\n *\n *\t\tfastDiff( [ '1', '2', 'a', 'a' ], [ '1', '2', 'a' ] );\n *\t\t// [ { index: 3, type: 'delete', howMany: 1 } ]\n *\n *\t\tfastDiff( [ '1', '2', 'a', 'b', 'c', '3' ], [ '2', 'a', 'b' ] );\n *\t\t// [ { index: 0, type: 'insert', values: [ '2', 'a', 'b' ] }, { index: 3, type: 'delete', howMany: 6 } ]\n *\n * Passed arrays can contain any type of data, however to compare them correctly custom comparator function\n * should be passed as a third parameter:\n *\n *\t\tfastDiff( [ { value: 1 }, { value: 2 } ], [ { value: 1 }, { value: 3 } ], ( a, b ) => {\n *\t\t\treturn a.value === b.value;\n *\t\t} );\n *\t\t// [ { index: 1, type: 'insert', values: [ { value: 3 } ] }, { index: 2, type: 'delete', howMany: 1 } ]\n *\n * The resulted set of changes can be applied to the input in order to transform it into the output, for example:\n *\n *\t\tlet input = '12abc3';\n *\t\tconst output = '2ab';\n *\t\tconst changes = fastDiff( input, output );\n *\n *\t\tchanges.forEach( change => {\n *\t\t\tif ( change.type == 'insert' ) {\n *\t\t\t\tinput = input.substring( 0, change.index ) + change.values.join( '' ) + input.substring( change.index );\n *\t\t\t} else if ( change.type == 'delete' ) {\n *\t\t\t\tinput = input.substring( 0, change.index ) + input.substring( change.index + change.howMany );\n *\t\t\t}\n *\t\t} );\n *\n *\t\t// input equals output now\n *\n * or in case of arrays:\n *\n *\t\tlet input = [ '1', '2', 'a', 'b', 'c', '3' ];\n *\t\tconst output = [ '2', 'a', 'b' ];\n *\t\tconst changes = fastDiff( input, output );\n *\n *\t\tchanges.forEach( change => {\n *\t\t\tif ( change.type == 'insert' ) {\n *\t\t\t\tinput = input.slice( 0, change.index ).concat( change.values, input.slice( change.index ) );\n *\t\t\t} else if ( change.type == 'delete' ) {\n *\t\t\t\tinput = input.slice( 0, change.index ).concat( input.slice( change.index + change.howMany ) );\n *\t\t\t}\n *\t\t} );\n *\n *\t\t// input equals output now\n *\n * By passing `true` as the fourth parameter (`atomicChanges`) the output of this function will become compatible with\n * the {@link module:utils/diff~diff `diff()`} function:\n *\n *\t\tfastDiff( '12a', '12xyza' );\n *\t\t// [ 'equal', 'equal', 'insert', 'insert', 'insert', 'equal' ]\n *\n * The default output format of this function is compatible with the output format of\n * {@link module:utils/difftochanges~diffToChanges `diffToChanges()`}. The `diffToChanges()` input format is, in turn,\n * compatible with the output of {@link module:utils/diff~diff `diff()`}:\n *\n *\t\tconst a = '1234';\n *\t\tconst b = '12xyz34';\n *\n *\t\t// Both calls will return the same results (grouped changes format).\n *\t\tfastDiff( a, b );\n *\t\tdiffToChanges( diff( a, b ) );\n *\n *\t\t// Again, both calls will return the same results (atomic changes format).\n *\t\tfastDiff( a, b, null, true );\n *\t\tdiff( a, b );\n *\n *\n * @param {Array|String} a Input array or string.\n * @param {Array|String} b Input array or string.\n * @param {Function} [cmp] Optional function used to compare array values, by default `===` (strict equal operator) is used.\n * @param {Boolean} [atomicChanges=false] Whether an array of `inset|delete|equal` operations should\n * be returned instead of changes set. This makes this function compatible with {@link module:utils/diff~diff `diff()`}.\n * @returns {Array} Array of changes.\n */\nexport default function fastDiff( a, b, cmp, atomicChanges = false ) {\n\t// Set the comparator function.\n\tcmp = cmp || function( a, b ) {\n\t\treturn a === b;\n\t};\n\n\t// Transform text or any iterable into arrays for easier, consistent processing.\n\tif ( !Array.isArray( a ) ) {\n\t\ta = Array.from( a );\n\t}\n\n\tif ( !Array.isArray( b ) ) {\n\t\tb = Array.from( b );\n\t}\n\n\t// Find first and last change.\n\tconst changeIndexes = findChangeBoundaryIndexes( a, b, cmp );\n\n\t// Transform into changes array.\n\treturn atomicChanges ? changeIndexesToAtomicChanges( changeIndexes, b.length ) : changeIndexesToChanges( b, changeIndexes );\n}\n\n// Finds position of the first and last change in the given arrays. For example:\n//\n//\t\tconst indexes = findChangeBoundaryIndexes( [ '1', '2', '3', '4' ], [ '1', '3', '4', '2', '4' ] );\n//\t\tconsole.log( indexes ); // { firstIndex: 1, lastIndexOld: 3, lastIndexNew: 4 }\n//\n// The above indexes means that in the first array the modified part is `1[23]4` and in the second array it is `1[342]4`.\n// Based on such indexes, array with `insert`/`delete` operations which allows transforming first value into the second one\n// can be generated.\n//\n// @param {Array} arr1\n// @param {Array} arr2\n// @param {Function} cmp Comparator function.\n// @returns {Object}\n// @returns {Number} return.firstIndex Index of the first change in both values (always the same for both).\n// @returns {Number} result.lastIndexOld Index of the last common value in `arr1`.\n// @returns {Number} result.lastIndexNew Index of the last common value in `arr2`.\nfunction findChangeBoundaryIndexes( arr1, arr2, cmp ) {\n\t// Find the first difference between passed values.\n\tconst firstIndex = findFirstDifferenceIndex( arr1, arr2, cmp );\n\n\t// If arrays are equal return -1 indexes object.\n\tif ( firstIndex === -1 ) {\n\t\treturn { firstIndex: -1, lastIndexOld: -1, lastIndexNew: -1 };\n\t}\n\n\t// Remove the common part of each value and reverse them to make it simpler to find the last difference between them.\n\tconst oldArrayReversed = cutAndReverse( arr1, firstIndex );\n\tconst newArrayReversed = cutAndReverse( arr2, firstIndex );\n\n\t// Find the first difference between reversed values.\n\t// It should be treated as \"how many elements from the end the last difference occurred\".\n\t//\n\t// For example:\n\t//\n\t// \t\t\t\tinitial\t->\tafter cut\t-> reversed:\n\t// oldValue:\t'321ba'\t->\t'21ba'\t\t-> 'ab12'\n\t// newValue:\t'31xba'\t->\t'1xba'\t\t-> 'abx1'\n\t// lastIndex:\t\t\t\t\t\t\t-> 2\n\t//\n\t// So the last change occurred two characters from the end of the arrays.\n\tconst lastIndex = findFirstDifferenceIndex( oldArrayReversed, newArrayReversed, cmp );\n\n\t// Use `lastIndex` to calculate proper offset, starting from the beginning (`lastIndex` kind of starts from the end).\n\tconst lastIndexOld = arr1.length - lastIndex;\n\tconst lastIndexNew = arr2.length - lastIndex;\n\n\treturn { firstIndex, lastIndexOld, lastIndexNew };\n}\n\n// Returns a first index on which given arrays differ. If both arrays are the same, -1 is returned.\n//\n// @param {Array} arr1\n// @param {Array} arr2\n// @param {Function} cmp Comparator function.\n// @returns {Number}\nfunction findFirstDifferenceIndex( arr1, arr2, cmp ) {\n\tfor ( let i = 0; i < Math.max( arr1.length, arr2.length ); i++ ) {\n\t\tif ( arr1[ i ] === undefined || arr2[ i ] === undefined || !cmp( arr1[ i ], arr2[ i ] ) ) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn -1; // Return -1 if arrays are equal.\n}\n\n// Returns a copy of the given array with `howMany` elements removed starting from the beginning and in reversed order.\n//\n// @param {Array} arr Array to be processed.\n// @param {Number} howMany How many elements from array beginning to remove.\n// @returns {Array} Shortened and reversed array.\nfunction cutAndReverse( arr, howMany ) {\n\treturn arr.slice( howMany ).reverse();\n}\n\n// Generates changes array based on change indexes from `findChangeBoundaryIndexes` function. This function will\n// generate array with 0 (no changes), 1 (deletion or insertion) or 2 records (insertion and deletion).\n//\n// @param {Array} newArray New array for which change indexes were calculated.\n// @param {Object} changeIndexes Change indexes object from `findChangeBoundaryIndexes` function.\n// @returns {Array.<Object>} Array of changes compatible with {@link module:utils/difftochanges~diffToChanges} format.\nfunction changeIndexesToChanges( newArray, changeIndexes ) {\n\tconst result = [];\n\tconst { firstIndex, lastIndexOld, lastIndexNew } = changeIndexes;\n\n\t// Order operations as 'insert', 'delete' array to keep compatibility with {@link module:utils/difftochanges~diffToChanges}\n\t// in most cases. However, 'diffToChanges' does not stick to any order so in some cases\n\t// (for example replacing '12345' with 'abcd') it will generate 'delete', 'insert' order.\n\tif ( lastIndexNew - firstIndex > 0 ) {\n\t\tresult.push( {\n\t\t\tindex: firstIndex,\n\t\t\ttype: 'insert',\n\t\t\tvalues: newArray.slice( firstIndex, lastIndexNew )\n\t\t} );\n\t}\n\n\tif ( lastIndexOld - firstIndex > 0 ) {\n\t\tresult.push( {\n\t\t\tindex: firstIndex + ( lastIndexNew - firstIndex ), // Increase index of what was inserted.\n\t\t\ttype: 'delete',\n\t\t\thowMany: lastIndexOld - firstIndex\n\t\t} );\n\t}\n\n\treturn result;\n}\n\n// Generates array with set `equal|insert|delete` operations based on change indexes from `findChangeBoundaryIndexes` function.\n//\n// @param {Object} changeIndexes Change indexes object from `findChangeBoundaryIndexes` function.\n// @param {Number} newLength Length of the new array on which `findChangeBoundaryIndexes` calculated change indexes.\n// @returns {Array.<String>} Array of changes compatible with {@link module:utils/diff~diff} format.\nfunction changeIndexesToAtomicChanges( changeIndexes, newLength ) {\n\tconst { firstIndex, lastIndexOld, lastIndexNew } = changeIndexes;\n\n\t// No changes.\n\tif ( firstIndex === -1 ) {\n\t\treturn Array( newLength ).fill( 'equal' );\n\t}\n\n\tlet result = [];\n\tif ( firstIndex > 0 ) {\n\t\tresult = result.concat( Array( firstIndex ).fill( 'equal' ) );\n\t}\n\n\tif ( lastIndexNew - firstIndex > 0 ) {\n\t\tresult = result.concat( Array( lastIndexNew - firstIndex ).fill( 'insert' ) );\n\t}\n\n\tif ( lastIndexOld - firstIndex > 0 ) {\n\t\tresult = result.concat( Array( lastIndexOld - firstIndex ).fill( 'delete' ) );\n\t}\n\n\tif ( lastIndexNew < newLength ) {\n\t\tresult = result.concat( Array( newLength - lastIndexNew ).fill( 'equal' ) );\n\t}\n\n\treturn result;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/diff\n */\n\nimport fastDiff from '../src/fastdiff';\n\n// The following code is based on the \"O(NP) Sequence Comparison Algorithm\"\n// by Sun Wu, Udi Manber, Gene Myers, Webb Miller.\n\n/**\n * Calculates the difference between two arrays or strings producing an array containing a list of changes\n * necessary to transform input into output.\n *\n *\t\tdiff( 'aba', 'acca' ); // [ 'equal', 'insert', 'insert', 'delete', 'equal' ]\n *\n * This function is based on the \"O(NP) Sequence Comparison Algorithm\" by Sun Wu, Udi Manber, Gene Myers, Webb Miller.\n * Unfortunately, while it gives the most precise results, its to complex for longer strings/arrow (above 200 items).\n * Therefore, `diff()` automatically switches to {@link module:utils/fastdiff~fastDiff `fastDiff()`} when detecting\n * such a scenario. The return formats of both functions are identical.\n *\n * @param {Array|String} a Input array or string.\n * @param {Array|String} b Output array or string.\n * @param {Function} [cmp] Optional function used to compare array values, by default === is used.\n * @returns {Array} Array of changes.\n */\nexport default function diff( a, b, cmp ) {\n\t// Set the comparator function.\n\tcmp = cmp || function( a, b ) {\n\t\treturn a === b;\n\t};\n\n\tconst aLength = a.length;\n\tconst bLength = b.length;\n\n\t// Perform `fastDiff` for longer strings/arrays (see #269).\n\tif ( aLength > 200 || bLength > 200 || aLength + bLength > 300 ) {\n\t\treturn diff.fastDiff( a, b, cmp, true );\n\t}\n\n\t// Temporary action type statics.\n\tlet _insert, _delete;\n\n\t// Swapped the arrays to use the shorter one as the first one.\n\tif ( bLength < aLength ) {\n\t\tconst tmp = a;\n\n\t\ta = b;\n\t\tb = tmp;\n\n\t\t// We swap the action types as well.\n\t\t_insert = 'delete';\n\t\t_delete = 'insert';\n\t} else {\n\t\t_insert = 'insert';\n\t\t_delete = 'delete';\n\t}\n\n\tconst m = a.length;\n\tconst n = b.length;\n\tconst delta = n - m;\n\n\t// Edit scripts, for each diagonal.\n\tconst es = {};\n\t// Furthest points, the furthest y we can get on each diagonal.\n\tconst fp = {};\n\n\tfunction snake( k ) {\n\t\t// We use -1 as an alternative below to handle initial values ( instead of filling the fp with -1 first ).\n\t\t// Furthest points (y) on the diagonal below k.\n\t\tconst y1 = ( fp[ k - 1 ] !== undefined ? fp[ k - 1 ] : -1 ) + 1;\n\t\t// Furthest points (y) on the diagonal above k.\n\t\tconst y2 = fp[ k + 1 ] !== undefined ? fp[ k + 1 ] : -1;\n\t\t// The way we should go to get further.\n\t\tconst dir = y1 > y2 ? -1 : 1;\n\n\t\t// Clone previous changes array (if any).\n\t\tif ( es[ k + dir ] ) {\n\t\t\tes[ k ] = es[ k + dir ].slice( 0 );\n\t\t}\n\n\t\t// Create changes array.\n\t\tif ( !es[ k ] ) {\n\t\t\tes[ k ] = [];\n\t\t}\n\n\t\t// Push the action.\n\t\tes[ k ].push( y1 > y2 ? _insert : _delete );\n\n\t\t// Set the beginning coordinates.\n\t\tlet y = Math.max( y1, y2 );\n\t\tlet x = y - k;\n\n\t\t// Traverse the diagonal as long as the values match.\n\t\twhile ( x < m && y < n && cmp( a[ x ], b[ y ] ) ) {\n\t\t\tx++;\n\t\t\ty++;\n\t\t\t// Push no change action.\n\t\t\tes[ k ].push( 'equal' );\n\t\t}\n\n\t\treturn y;\n\t}\n\n\tlet p = 0;\n\tlet k;\n\n\t// Traverse the graph until we reach the end of the longer string.\n\tdo {\n\t\t// Updates furthest points and edit scripts for diagonals below delta.\n\t\tfor ( k = -p; k < delta; k++ ) {\n\t\t\tfp[ k ] = snake( k );\n\t\t}\n\n\t\t// Updates furthest points and edit scripts for diagonals above delta.\n\t\tfor ( k = delta + p; k > delta; k-- ) {\n\t\t\tfp[ k ] = snake( k );\n\t\t}\n\n\t\t// Updates furthest point and edit script for the delta diagonal.\n\t\t// note that the delta diagonal is the one which goes through the sink (m, n).\n\t\tfp[ delta ] = snake( delta );\n\n\t\tp++;\n\t} while ( fp[ delta ] !== n );\n\n\t// Return the final list of edit changes.\n\t// We remove the first item that represents the action for the injected nulls.\n\treturn es[ delta ].slice( 1 );\n}\n\n// Store the API in static property to easily overwrite it in tests.\n// Too bad dependency injection does not work in Webpack + ES 6 (const) + Babel.\ndiff.fastDiff = fastDiff;\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/insertat\n */\n\n/**\n * Inserts node to the parent at given index.\n *\n * @param {Element} parentElement Parent element.\n * @param {Number} index Insertions index.\n * @param {Node} nodeToInsert Node to insert.\n */\nexport default function insertAt( parentElement, index, nodeToInsert ) {\n\tparentElement.insertBefore( nodeToInsert, parentElement.childNodes[ index ] || null );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/remove\n */\n\n/**\n * Removes given node from parent.\n *\n * @param {Node} node Node to remove.\n */\nexport default function remove( node ) {\n\tconst parent = node.parentNode;\n\n\tif ( parent ) {\n\t\tparent.removeChild( node );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/isnode\n */\n\n/**\n * Checks if the object is a native DOM Node.\n *\n * @param {*} obj\n * @returns {Boolean}\n */\nexport default function isNode( obj ) {\n\tif ( obj ) {\n\t\tif ( obj.defaultView ) {\n\t\t\treturn obj instanceof obj.defaultView.Document;\n\t\t} else if ( obj.ownerDocument && obj.ownerDocument.defaultView ) {\n\t\t\treturn obj instanceof obj.ownerDocument.defaultView.Node;\n\t\t}\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals Node */\n\n/**\n * @module engine/view/renderer\n */\n\nimport ViewText from './text';\nimport ViewPosition from './position';\nimport { INLINE_FILLER, INLINE_FILLER_LENGTH, startsWithFiller, isInlineFiller } from './filler';\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport diff from '@ckeditor/ckeditor5-utils/src/diff';\nimport insertAt from '@ckeditor/ckeditor5-utils/src/dom/insertat';\nimport remove from '@ckeditor/ckeditor5-utils/src/dom/remove';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport isText from '@ckeditor/ckeditor5-utils/src/dom/istext';\nimport isNode from '@ckeditor/ckeditor5-utils/src/dom/isnode';\nimport fastDiff from '@ckeditor/ckeditor5-utils/src/fastdiff';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * Renderer is responsible for updating the DOM structure and the DOM selection based on\n * the {@link module:engine/view/renderer~Renderer#markToSync information about updated view nodes}.\n * In other words, it renders the view to the DOM.\n *\n * Its main responsibility is to make only the necessary, minimal changes to the DOM. However, unlike in many\n * virtual DOM implementations, the primary reason for doing minimal changes is not the performance but ensuring\n * that native editing features such as text composition, autocompletion, spell checking, selection's x-index are\n * affected as little as possible.\n *\n * Renderer uses {@link module:engine/view/domconverter~DomConverter} to transform view nodes and positions\n * to and from the DOM.\n */\nexport default class Renderer {\n\t/**\n\t * Creates a renderer instance.\n\t *\n\t * @param {module:engine/view/domconverter~DomConverter} domConverter Converter instance.\n\t * @param {module:engine/view/documentselection~DocumentSelection} selection View selection.\n\t */\n\tconstructor( domConverter, selection ) {\n\t\t/**\n\t\t * Set of DOM Documents instances.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set.<Document>}\n\t\t */\n\t\tthis.domDocuments = new Set();\n\n\t\t/**\n\t\t * Converter instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/domconverter~DomConverter}\n\t\t */\n\t\tthis.domConverter = domConverter;\n\n\t\t/**\n\t\t * Set of nodes which attributes changed and may need to be rendered.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set.<module:engine/view/node~Node>}\n\t\t */\n\t\tthis.markedAttributes = new Set();\n\n\t\t/**\n\t\t * Set of elements which child lists changed and may need to be rendered.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set.<module:engine/view/node~Node>}\n\t\t */\n\t\tthis.markedChildren = new Set();\n\n\t\t/**\n\t\t * Set of text nodes which text data changed and may need to be rendered.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set.<module:engine/view/node~Node>}\n\t\t */\n\t\tthis.markedTexts = new Set();\n\n\t\t/**\n\t\t * View selection. Renderer updates DOM selection based on the view selection.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/documentselection~DocumentSelection}\n\t\t */\n\t\tthis.selection = selection;\n\n\t\t/**\n\t\t * Indicates if the view document is focused and selection can be rendered. Selection will not be rendered if\n\t\t * this is set to `false`.\n\t\t *\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.isFocused = false;\n\n\t\t/**\n\t\t * The text node in which the inline filler was rendered.\n\t\t *\n\t\t * @private\n\t\t * @member {Text}\n\t\t */\n\t\tthis._inlineFiller = null;\n\n\t\t/**\n\t\t * DOM element containing fake selection.\n\t\t *\n\t\t * @private\n\t\t * @type {null|HTMLElement}\n\t\t */\n\t\tthis._fakeSelectionContainer = null;\n\t}\n\n\t/**\n\t * Marks a view node to be updated in the DOM by {@link #render `render()`}.\n\t *\n\t * Note that only view nodes whose parents have corresponding DOM elements need to be marked to be synchronized.\n\t *\n\t * @see #markedAttributes\n\t * @see #markedChildren\n\t * @see #markedTexts\n\t *\n\t * @param {module:engine/view/document~ChangeType} type Type of the change.\n\t * @param {module:engine/view/node~Node} node Node to be marked.\n\t */\n\tmarkToSync( type, node ) {\n\t\tif ( type === 'text' ) {\n\t\t\tif ( this.domConverter.mapViewToDom( node.parent ) ) {\n\t\t\t\tthis.markedTexts.add( node );\n\t\t\t}\n\t\t} else {\n\t\t\t// If the node has no DOM element it is not rendered yet,\n\t\t\t// its children/attributes do not need to be marked to be sync.\n\t\t\tif ( !this.domConverter.mapViewToDom( node ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( type === 'attributes' ) {\n\t\t\t\tthis.markedAttributes.add( node );\n\t\t\t} else if ( type === 'children' ) {\n\t\t\t\tthis.markedChildren.add( node );\n\t\t\t} else {\n\t\t\t\t/**\n\t\t\t\t * Unknown type passed to Renderer.markToSync.\n\t\t\t\t *\n\t\t\t\t * @error renderer-unknown-type\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'view-renderer-unknown-type: Unknown type passed to Renderer.markToSync.', this );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Renders all buffered changes ({@link #markedAttributes}, {@link #markedChildren} and {@link #markedTexts}) and\n\t * the current view selection (if needed) to the DOM by applying a minimal set of changes to it.\n\t *\n\t * Renderer tries not to break the text composition (e.g. IME) and x-index of the selection,\n\t * so it does as little as it is needed to update the DOM.\n\t *\n\t * Renderer also handles {@link module:engine/view/filler fillers}. Especially, it checks if the inline filler is needed\n\t * at the selection position and adds or removes it. To prevent breaking text composition inline filler will not be\n\t * removed as long as the selection is in the text node which needed it at first.\n\t */\n\trender() {\n\t\tlet inlineFillerPosition;\n\n\t\t// Refresh mappings.\n\t\tfor ( const element of this.markedChildren ) {\n\t\t\tthis._updateChildrenMappings( element );\n\t\t}\n\n\t\t// There was inline filler rendered in the DOM but it's not\n\t\t// at the selection position any more, so we can remove it\n\t\t// (cause even if it's needed, it must be placed in another location).\n\t\tif ( this._inlineFiller && !this._isSelectionInInlineFiller() ) {\n\t\t\tthis._removeInlineFiller();\n\t\t}\n\n\t\t// If we've got the filler, let's try to guess its position in the view.\n\t\tif ( this._inlineFiller ) {\n\t\t\tinlineFillerPosition = this._getInlineFillerPosition();\n\t\t}\n\t\t// Otherwise, if it's needed, create it at the selection position.\n\t\telse if ( this._needsInlineFillerAtSelection() ) {\n\t\t\tinlineFillerPosition = this.selection.getFirstPosition();\n\n\t\t\t// Do not use `markToSync` so it will be added even if the parent is already added.\n\t\t\tthis.markedChildren.add( inlineFillerPosition.parent );\n\t\t}\n\n\t\tfor ( const element of this.markedAttributes ) {\n\t\t\tthis._updateAttrs( element );\n\t\t}\n\n\t\tfor ( const element of this.markedChildren ) {\n\t\t\tthis._updateChildren( element, { inlineFillerPosition } );\n\t\t}\n\n\t\tfor ( const node of this.markedTexts ) {\n\t\t\tif ( !this.markedChildren.has( node.parent ) && this.domConverter.mapViewToDom( node.parent ) ) {\n\t\t\t\tthis._updateText( node, { inlineFillerPosition } );\n\t\t\t}\n\t\t}\n\n\t\t// Check whether the inline filler is required and where it really is in the DOM.\n\t\t// At this point in most cases it will be in the DOM, but there are exceptions.\n\t\t// For example, if the inline filler was deep in the created DOM structure, it will not be created.\n\t\t// Similarly, if it was removed at the beginning of this function and then neither text nor children were updated,\n\t\t// it will not be present.\n\t\t// Fix those and similar scenarios.\n\t\tif ( inlineFillerPosition ) {\n\t\t\tconst fillerDomPosition = this.domConverter.viewPositionToDom( inlineFillerPosition );\n\t\t\tconst domDocument = fillerDomPosition.parent.ownerDocument;\n\n\t\t\tif ( !startsWithFiller( fillerDomPosition.parent ) ) {\n\t\t\t\t// Filler has not been created at filler position. Create it now.\n\t\t\t\tthis._inlineFiller = addInlineFiller( domDocument, fillerDomPosition.parent, fillerDomPosition.offset );\n\t\t\t} else {\n\t\t\t\t// Filler has been found, save it.\n\t\t\t\tthis._inlineFiller = fillerDomPosition.parent;\n\t\t\t}\n\t\t} else {\n\t\t\t// There is no filler needed.\n\t\t\tthis._inlineFiller = null;\n\t\t}\n\n\t\tthis._updateSelection();\n\t\tthis._updateFocus();\n\n\t\tthis.markedTexts.clear();\n\t\tthis.markedAttributes.clear();\n\t\tthis.markedChildren.clear();\n\t}\n\n\t/**\n\t * Updates mappings of view element's children.\n\t *\n\t * Children that were replaced in the view structure by similar elements (same tag name) are treated as 'replaced'.\n\t * This means that their mappings can be updated so the new view elements are mapped to the existing DOM elements.\n\t * Thanks to that these elements do not need to be re-rendered completely.\n\t *\n\t * @private\n\t * @param {module:engine/view/node~Node} viewElement The view element whose children mappings will be updated.\n\t */\n\t_updateChildrenMappings( viewElement ) {\n\t\tconst domElement = this.domConverter.mapViewToDom( viewElement );\n\n\t\tif ( !domElement ) {\n\t\t\t// If there is no `domElement` it means that it was already removed from DOM and there is no need to process it.\n\t\t\treturn;\n\t\t}\n\n\t\tconst actualDomChildren = this.domConverter.mapViewToDom( viewElement ).childNodes;\n\t\tconst expectedDomChildren = Array.from(\n\t\t\tthis.domConverter.viewChildrenToDom( viewElement, domElement.ownerDocument, { withChildren: false } )\n\t\t);\n\t\tconst diff = this._diffNodeLists( actualDomChildren, expectedDomChildren );\n\t\tconst actions = this._findReplaceActions( diff, actualDomChildren, expectedDomChildren );\n\n\t\tif ( actions.indexOf( 'replace' ) !== -1 ) {\n\t\t\tconst counter = { equal: 0, insert: 0, delete: 0 };\n\n\t\t\tfor ( const action of actions ) {\n\t\t\t\tif ( action === 'replace' ) {\n\t\t\t\t\tconst insertIndex = counter.equal + counter.insert;\n\t\t\t\t\tconst deleteIndex = counter.equal + counter.delete;\n\t\t\t\t\tconst viewChild = viewElement.getChild( insertIndex );\n\n\t\t\t\t\t// The 'uiElement' is a special one and its children are not stored in a view (#799),\n\t\t\t\t\t// so we cannot use it with replacing flow (since it uses view children during rendering\n\t\t\t\t\t// which will always result in rendering empty element).\n\t\t\t\t\tif ( viewChild && !viewChild.is( 'uiElement' ) ) {\n\t\t\t\t\t\tthis._updateElementMappings( viewChild, actualDomChildren[ deleteIndex ] );\n\t\t\t\t\t}\n\n\t\t\t\t\tremove( expectedDomChildren[ insertIndex ] );\n\t\t\t\t\tcounter.equal++;\n\t\t\t\t} else {\n\t\t\t\t\tcounter[ action ]++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Updates mappings of a given view element.\n\t *\n\t * @private\n\t * @param {module:engine/view/node~Node} viewElement The view element whose mappings will be updated.\n\t * @param {Node} domElement The DOM element representing the given view element.\n\t */\n\t_updateElementMappings( viewElement, domElement ) {\n\t\t// Remap 'DomConverter' bindings.\n\t\tthis.domConverter.unbindDomElement( domElement );\n\t\tthis.domConverter.bindElements( domElement, viewElement );\n\n\t\t// View element may have children which needs to be updated, but are not marked, mark them to update.\n\t\tthis.markedChildren.add( viewElement );\n\n\t\t// Because we replace new view element mapping with the existing one, the corresponding DOM element\n\t\t// will not be rerendered. The new view element may have different attributes than the previous one.\n\t\t// Since its corresponding DOM element will not be rerendered, new attributes will not be added\n\t\t// to the DOM, so we need to mark it here to make sure its attributes gets updated. See #1427 for more\n\t\t// detailed case study.\n\t\t// Also there are cases where replaced element is removed from the view structure and then has\n\t\t// its attributes changed or removed. In such cases the element will not be present in `markedAttributes`\n\t\t// and also may be the same (`element.isSimilar()`) as the reused element not having its attributes updated.\n\t\t// To prevent such situations we always mark reused element to have its attributes rerenderd (#1560).\n\t\tthis.markedAttributes.add( viewElement );\n\t}\n\n\t/**\n\t * Gets the position of the inline filler based on the current selection.\n\t * Here, we assume that we know that the filler is needed and\n\t * {@link #_isSelectionInInlineFiller is at the selection position}, and, since it is needed,\n\t * it is somewhere at the selection position.\n\t *\n\t * Note: The filler position cannot be restored based on the filler's DOM text node, because\n\t * when this method is called (before rendering), the bindings will often be broken. View-to-DOM\n\t * bindings are only dependable after rendering.\n\t *\n\t * @private\n\t * @returns {module:engine/view/position~Position}\n\t */\n\t_getInlineFillerPosition() {\n\t\tconst firstPos = this.selection.getFirstPosition();\n\n\t\tif ( firstPos.parent.is( 'text' ) ) {\n\t\t\treturn ViewPosition._createBefore( this.selection.getFirstPosition().parent );\n\t\t} else {\n\t\t\treturn firstPos;\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` if the selection has not left the inline filler's text node.\n\t * If it is `true`, it means that the filler had been added for a reason and the selection did not\n\t * leave the filler's text node. For example, the user can be in the middle of a composition so it should not be touched.\n\t *\n\t * @private\n\t * @returns {Boolean} `true` if the inline filler and selection are in the same place.\n\t */\n\t_isSelectionInInlineFiller() {\n\t\tif ( this.selection.rangeCount != 1 || !this.selection.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Note, we can't check if selection's position equals position of the\n\t\t// this._inlineFiller node, because of #663. We may not be able to calculate\n\t\t// the filler's position in the view at this stage.\n\t\t// Instead, we check it the other way – whether selection is anchored in\n\t\t// that text node or next to it.\n\n\t\t// Possible options are:\n\t\t// \"FILLER{}\"\n\t\t// \"FILLERadded-text{}\"\n\t\tconst selectionPosition = this.selection.getFirstPosition();\n\t\tconst position = this.domConverter.viewPositionToDom( selectionPosition );\n\n\t\tif ( position && isText( position.parent ) && startsWithFiller( position.parent ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Removes the inline filler.\n\t *\n\t * @private\n\t */\n\t_removeInlineFiller() {\n\t\tconst domFillerNode = this._inlineFiller;\n\n\t\t// Something weird happened and the stored node doesn't contain the filler's text.\n\t\tif ( !startsWithFiller( domFillerNode ) ) {\n\t\t\t/**\n\t\t\t * The inline filler node was lost. Most likely, something overwrote the filler text node\n\t\t\t * in the DOM.\n\t\t\t *\n\t\t\t * @error view-renderer-filler-was-lost\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-renderer-filler-was-lost: The inline filler node was lost.', this );\n\t\t}\n\n\t\tif ( isInlineFiller( domFillerNode ) ) {\n\t\t\tdomFillerNode.parentNode.removeChild( domFillerNode );\n\t\t} else {\n\t\t\tdomFillerNode.data = domFillerNode.data.substr( INLINE_FILLER_LENGTH );\n\t\t}\n\n\t\tthis._inlineFiller = null;\n\t}\n\n\t/**\n\t * Checks if the inline {@link module:engine/view/filler filler} should be added.\n\t *\n\t * @private\n\t * @returns {Boolean} `true` if the inline filler should be added.\n\t */\n\t_needsInlineFillerAtSelection() {\n\t\tif ( this.selection.rangeCount != 1 || !this.selection.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst selectionPosition = this.selection.getFirstPosition();\n\t\tconst selectionParent = selectionPosition.parent;\n\t\tconst selectionOffset = selectionPosition.offset;\n\n\t\t// If there is no DOM root we do not care about fillers.\n\t\tif ( !this.domConverter.mapViewToDom( selectionParent.root ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( !( selectionParent.is( 'element' ) ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Prevent adding inline filler inside elements with contenteditable=false.\n\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/1170\n\t\tif ( !isEditable( selectionParent ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// We have block filler, we do not need inline one.\n\t\tif ( selectionOffset === selectionParent.getFillerOffset() ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst nodeBefore = selectionPosition.nodeBefore;\n\t\tconst nodeAfter = selectionPosition.nodeAfter;\n\n\t\tif ( nodeBefore instanceof ViewText || nodeAfter instanceof ViewText ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks if text needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} viewText View text to update.\n\t * @param {Object} options\n\t * @param {module:engine/view/position~Position} options.inlineFillerPosition The position where the inline\n\t * filler should be rendered.\n\t */\n\t_updateText( viewText, options ) {\n\t\tconst domText = this.domConverter.findCorrespondingDomText( viewText );\n\t\tconst newDomText = this.domConverter.viewToDom( viewText, domText.ownerDocument );\n\n\t\tconst actualText = domText.data;\n\t\tlet expectedText = newDomText.data;\n\n\t\tconst filler = options.inlineFillerPosition;\n\n\t\tif ( filler && filler.parent == viewText.parent && filler.offset == viewText.index ) {\n\t\t\texpectedText = INLINE_FILLER + expectedText;\n\t\t}\n\n\t\tif ( actualText != expectedText ) {\n\t\t\tconst actions = fastDiff( actualText, expectedText );\n\n\t\t\tfor ( const action of actions ) {\n\t\t\t\tif ( action.type === 'insert' ) {\n\t\t\t\t\tdomText.insertData( action.index, action.values.join( '' ) );\n\t\t\t\t} else { // 'delete'\n\t\t\t\t\tdomText.deleteData( action.index, action.howMany );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if attribute list needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} viewElement The view element to update.\n\t */\n\t_updateAttrs( viewElement ) {\n\t\tconst domElement = this.domConverter.mapViewToDom( viewElement );\n\n\t\tif ( !domElement ) {\n\t\t\t// If there is no `domElement` it means that 'viewElement' is outdated as its mapping was updated\n\t\t\t// in 'this._updateChildrenMappings()'. There is no need to process it as new view element which\n\t\t\t// replaced old 'viewElement' mapping was also added to 'this.markedAttributes'\n\t\t\t// in 'this._updateChildrenMappings()' so it will be processed separately.\n\t\t\treturn;\n\t\t}\n\n\t\tconst domAttrKeys = Array.from( domElement.attributes ).map( attr => attr.name );\n\t\tconst viewAttrKeys = viewElement.getAttributeKeys();\n\n\t\t// Add or overwrite attributes.\n\t\tfor ( const key of viewAttrKeys ) {\n\t\t\tdomElement.setAttribute( key, viewElement.getAttribute( key ) );\n\t\t}\n\n\t\t// Remove from DOM attributes which do not exists in the view.\n\t\tfor ( const key of domAttrKeys ) {\n\t\t\tif ( !viewElement.hasAttribute( key ) ) {\n\t\t\t\tdomElement.removeAttribute( key );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if elements child list needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} viewElement View element to update.\n\t * @param {Object} options\n\t * @param {module:engine/view/position~Position} options.inlineFillerPosition The position where the inline\n\t * filler should be rendered.\n\t */\n\t_updateChildren( viewElement, options ) {\n\t\tconst domElement = this.domConverter.mapViewToDom( viewElement );\n\n\t\tif ( !domElement ) {\n\t\t\t// If there is no `domElement` it means that it was already removed from DOM.\n\t\t\t// There is no need to process it. It will be processed when re-inserted.\n\t\t\treturn;\n\t\t}\n\n\t\tconst inlineFillerPosition = options.inlineFillerPosition;\n\t\tconst actualDomChildren = this.domConverter.mapViewToDom( viewElement ).childNodes;\n\t\tconst expectedDomChildren = Array.from(\n\t\t\tthis.domConverter.viewChildrenToDom( viewElement, domElement.ownerDocument, { bind: true, inlineFillerPosition } )\n\t\t);\n\n\t\t// Inline filler element has to be created as it is present in the DOM, but not in the view. It is required\n\t\t// during diffing so text nodes could be compared correctly and also during rendering to maintain\n\t\t// proper order and indexes while updating the DOM.\n\t\tif ( inlineFillerPosition && inlineFillerPosition.parent === viewElement ) {\n\t\t\taddInlineFiller( domElement.ownerDocument, expectedDomChildren, inlineFillerPosition.offset );\n\t\t}\n\n\t\tconst diff = this._diffNodeLists( actualDomChildren, expectedDomChildren );\n\n\t\tlet i = 0;\n\t\tconst nodesToUnbind = new Set();\n\n\t\tfor ( const action of diff ) {\n\t\t\tif ( action === 'insert' ) {\n\t\t\t\tinsertAt( domElement, i, expectedDomChildren[ i ] );\n\t\t\t\ti++;\n\t\t\t} else if ( action === 'delete' ) {\n\t\t\t\tnodesToUnbind.add( actualDomChildren[ i ] );\n\t\t\t\tremove( actualDomChildren[ i ] );\n\t\t\t} else { // 'equal'\n\t\t\t\t// Force updating text nodes inside elements which did not change and do not need to be re-rendered (#1125).\n\t\t\t\tthis._markDescendantTextToSync( this.domConverter.domToView( expectedDomChildren[ i ] ) );\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\n\t\t// Unbind removed nodes. When node does not have a parent it means that it was removed from DOM tree during\n\t\t// comparision with the expected DOM. We don't need to check child nodes, because if child node was reinserted,\n\t\t// it was moved to DOM tree out of the removed node.\n\t\tfor ( const node of nodesToUnbind ) {\n\t\t\tif ( !node.parentNode ) {\n\t\t\t\tthis.domConverter.unbindDomElement( node );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Shorthand for diffing two arrays or node lists of DOM nodes.\n\t *\n\t * @private\n\t * @param {Array.<Node>|NodeList} actualDomChildren Actual DOM children\n\t * @param {Array.<Node>|NodeList} expectedDomChildren Expected DOM children.\n\t * @returns {Array.<String>} The list of actions based on the {@link module:utils/diff~diff} function.\n\t */\n\t_diffNodeLists( actualDomChildren, expectedDomChildren ) {\n\t\tactualDomChildren = filterOutFakeSelectionContainer( actualDomChildren, this._fakeSelectionContainer );\n\n\t\treturn diff( actualDomChildren, expectedDomChildren, sameNodes.bind( null, this.domConverter ) );\n\t}\n\n\t/**\n\t * Finds DOM nodes that were replaced with the similar nodes (same tag name) in the view. All nodes are compared\n\t * within one `insert`/`delete` action group, for example:\n\t *\n\t * \t\tActual DOM:\t\t<p><b>Foo</b>Bar<i>Baz</i><b>Bax</b></p>\n\t * \t\tExpected DOM:\t<p>Bar<b>123</b><i>Baz</i><b>456</b></p>\n\t * \t\tInput actions:\t[ insert, insert, delete, delete, equal, insert, delete ]\n\t * \t\tOutput actions:\t[ insert, replace, delete, equal, replace ]\n\t *\n\t * @private\n\t * @param {Array.<String>} actions Actions array which is a result of the {@link module:utils/diff~diff} function.\n\t * @param {Array.<Node>|NodeList} actualDom Actual DOM children\n\t * @param {Array.<Node>} expectedDom Expected DOM children.\n\t * @returns {Array.<String>} Actions array modified with the `replace` actions.\n\t */\n\t_findReplaceActions( actions, actualDom, expectedDom ) {\n\t\t// If there is no both 'insert' and 'delete' actions, no need to check for replaced elements.\n\t\tif ( actions.indexOf( 'insert' ) === -1 || actions.indexOf( 'delete' ) === -1 ) {\n\t\t\treturn actions;\n\t\t}\n\n\t\tlet newActions = [];\n\t\tlet actualSlice = [];\n\t\tlet expectedSlice = [];\n\n\t\tconst counter = { equal: 0, insert: 0, delete: 0 };\n\n\t\tfor ( const action of actions ) {\n\t\t\tif ( action === 'insert' ) {\n\t\t\t\texpectedSlice.push( expectedDom[ counter.equal + counter.insert ] );\n\t\t\t} else if ( action === 'delete' ) {\n\t\t\t\tactualSlice.push( actualDom[ counter.equal + counter.delete ] );\n\t\t\t} else { // equal\n\t\t\t\tnewActions = newActions.concat( diff( actualSlice, expectedSlice, areSimilar ).map( x => x === 'equal' ? 'replace' : x ) );\n\t\t\t\tnewActions.push( 'equal' );\n\t\t\t\t// Reset stored elements on 'equal'.\n\t\t\t\tactualSlice = [];\n\t\t\t\texpectedSlice = [];\n\t\t\t}\n\t\t\tcounter[ action ]++;\n\t\t}\n\n\t\treturn newActions.concat( diff( actualSlice, expectedSlice, areSimilar ).map( x => x === 'equal' ? 'replace' : x ) );\n\t}\n\n\t/**\n\t * Marks text nodes to be synchronized.\n\t *\n\t * If a text node is passed, it will be marked. If an element is passed, all descendant text nodes inside it will be marked.\n\t *\n\t * @private\n\t * @param {module:engine/view/node~Node} viewNode View node to sync.\n\t */\n\t_markDescendantTextToSync( viewNode ) {\n\t\tif ( !viewNode ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( viewNode.is( 'text' ) ) {\n\t\t\tthis.markedTexts.add( viewNode );\n\t\t} else if ( viewNode.is( 'element' ) ) {\n\t\t\tfor ( const child of viewNode.getChildren() ) {\n\t\t\t\tthis._markDescendantTextToSync( child );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if the selection needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t */\n\t_updateSelection() {\n\t\t// If there is no selection - remove DOM and fake selections.\n\t\tif ( this.selection.rangeCount === 0 ) {\n\t\t\tthis._removeDomSelection();\n\t\t\tthis._removeFakeSelection();\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst domRoot = this.domConverter.mapViewToDom( this.selection.editableElement );\n\n\t\t// Do nothing if there is no focus, or there is no DOM element corresponding to selection's editable element.\n\t\tif ( !this.isFocused || !domRoot ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Render selection.\n\t\tif ( this.selection.isFake ) {\n\t\t\tthis._updateFakeSelection( domRoot );\n\t\t} else {\n\t\t\tthis._removeFakeSelection();\n\t\t\tthis._updateDomSelection( domRoot );\n\t\t}\n\t}\n\n\t/**\n\t * Updates the fake selection.\n\t *\n\t * @private\n\t * @param {HTMLElement} domRoot A valid DOM root where the fake selection container should be added.\n\t */\n\t_updateFakeSelection( domRoot ) {\n\t\tconst domDocument = domRoot.ownerDocument;\n\n\t\tif ( !this._fakeSelectionContainer ) {\n\t\t\tthis._fakeSelectionContainer = createFakeSelectionContainer( domDocument );\n\t\t}\n\n\t\tconst container = this._fakeSelectionContainer;\n\n\t\t// Bind fake selection container with the current selection *position*.\n\t\tthis.domConverter.bindFakeSelection( container, this.selection );\n\n\t\tif ( !this._fakeSelectionNeedsUpdate( domRoot ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !container.parentElement || container.parentElement != domRoot ) {\n\t\t\tdomRoot.appendChild( container );\n\t\t}\n\n\t\tcontainer.textContent = this.selection.fakeSelectionLabel || '\\u00A0';\n\n\t\tconst domSelection = domDocument.getSelection();\n\t\tconst domRange = domDocument.createRange();\n\n\t\tdomSelection.removeAllRanges();\n\t\tdomRange.selectNodeContents( container );\n\t\tdomSelection.addRange( domRange );\n\t}\n\n\t/**\n\t * Updates the DOM selection.\n\t *\n\t * @private\n\t * @param {HTMLElement} domRoot A valid DOM root where the DOM selection should be rendered.\n\t */\n\t_updateDomSelection( domRoot ) {\n\t\tconst domSelection = domRoot.ownerDocument.defaultView.getSelection();\n\n\t\t// Let's check whether DOM selection needs updating at all.\n\t\tif ( !this._domSelectionNeedsUpdate( domSelection ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Multi-range selection is not available in most browsers, and, at least in Chrome, trying to\n\t\t// set such selection, that is not continuous, throws an error. Because of that, we will just use anchor\n\t\t// and focus of view selection.\n\t\t// Since we are not supporting multi-range selection, we also do not need to check if proper editable is\n\t\t// selected. If there is any editable selected, it is okay (editable is taken from selection anchor).\n\t\tconst anchor = this.domConverter.viewPositionToDom( this.selection.anchor );\n\t\tconst focus = this.domConverter.viewPositionToDom( this.selection.focus );\n\n\t\t// Focus the new editing host.\n\t\t// Otherwise, FF may throw an error (https://github.com/ckeditor/ckeditor5/issues/721).\n\t\tdomRoot.focus();\n\n\t\tdomSelection.collapse( anchor.parent, anchor.offset );\n\t\tdomSelection.extend( focus.parent, focus.offset );\n\n\t\t// Firefox–specific hack (https://github.com/ckeditor/ckeditor5-engine/issues/1439).\n\t\tif ( env.isGecko ) {\n\t\t\tfixGeckoSelectionAfterBr( focus, domSelection );\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether a given DOM selection needs to be updated.\n\t *\n\t * @private\n\t * @param {Selection} domSelection The DOM selection to check.\n\t * @returns {Boolean}\n\t */\n\t_domSelectionNeedsUpdate( domSelection ) {\n\t\tif ( !this.domConverter.isDomSelectionCorrect( domSelection ) ) {\n\t\t\t// Current DOM selection is in incorrect position. We need to update it.\n\t\t\treturn true;\n\t\t}\n\n\t\tconst oldViewSelection = domSelection && this.domConverter.domSelectionToView( domSelection );\n\n\t\tif ( oldViewSelection && this.selection.isEqual( oldViewSelection ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If selection is not collapsed, it does not need to be updated if it is similar.\n\t\tif ( !this.selection.isCollapsed && this.selection.isSimilar( oldViewSelection ) ) {\n\t\t\t// Selection did not changed and is correct, do not update.\n\t\t\treturn false;\n\t\t}\n\n\t\t// Selections are not similar.\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks whether the fake selection needs to be updated.\n\t *\n\t * @private\n\t * @param {HTMLElement} domRoot A valid DOM root where a new fake selection container should be added.\n\t * @returns {Boolean}\n\t */\n\t_fakeSelectionNeedsUpdate( domRoot ) {\n\t\tconst container = this._fakeSelectionContainer;\n\t\tconst domSelection = domRoot.ownerDocument.getSelection();\n\n\t\t// Fake selection needs to be updated if there's no fake selection container, or the container currently sits\n\t\t// in a different root.\n\t\tif ( !container || container.parentElement !== domRoot ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Make sure that the selection actually is within the fake selection.\n\t\tif ( domSelection.anchorNode !== container && !container.contains( domSelection.anchorNode ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn container.textContent !== this.selection.fakeSelectionLabel;\n\t}\n\n\t/**\n\t * Removes the DOM selection.\n\t *\n\t * @private\n\t */\n\t_removeDomSelection() {\n\t\tfor ( const doc of this.domDocuments ) {\n\t\t\tconst domSelection = doc.getSelection();\n\n\t\t\tif ( domSelection.rangeCount ) {\n\t\t\t\tconst activeDomElement = doc.activeElement;\n\t\t\t\tconst viewElement = this.domConverter.mapDomToView( activeDomElement );\n\n\t\t\t\tif ( activeDomElement && viewElement ) {\n\t\t\t\t\tdoc.getSelection().removeAllRanges();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Removes the fake selection.\n\t *\n\t * @private\n\t */\n\t_removeFakeSelection() {\n\t\tconst container = this._fakeSelectionContainer;\n\n\t\tif ( container ) {\n\t\t\tcontainer.remove();\n\t\t}\n\t}\n\n\t/**\n\t * Checks if focus needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t */\n\t_updateFocus() {\n\t\tif ( this.isFocused ) {\n\t\t\tconst editable = this.selection.editableElement;\n\n\t\t\tif ( editable ) {\n\t\t\t\tthis.domConverter.focus( editable );\n\t\t\t}\n\t\t}\n\t}\n}\n\nmix( Renderer, ObservableMixin );\n\n// Checks if provided element is editable.\n//\n// @private\n// @param {module:engine/view/element~Element} element\n// @returns {Boolean}\nfunction isEditable( element ) {\n\tif ( element.getAttribute( 'contenteditable' ) == 'false' ) {\n\t\treturn false;\n\t}\n\n\tconst parent = element.findAncestor( element => element.hasAttribute( 'contenteditable' ) );\n\n\treturn !parent || parent.getAttribute( 'contenteditable' ) == 'true';\n}\n\n// Adds inline filler at a given position.\n//\n// The position can be given as an array of DOM nodes and an offset in that array,\n// or a DOM parent element and an offset in that element.\n//\n// @private\n// @param {Document} domDocument\n// @param {Element|Array.<Node>} domParentOrArray\n// @param {Number} offset\n// @returns {Text} The DOM text node that contains an inline filler.\nfunction addInlineFiller( domDocument, domParentOrArray, offset ) {\n\tconst childNodes = domParentOrArray instanceof Array ? domParentOrArray : domParentOrArray.childNodes;\n\tconst nodeAfterFiller = childNodes[ offset ];\n\n\tif ( isText( nodeAfterFiller ) ) {\n\t\tnodeAfterFiller.data = INLINE_FILLER + nodeAfterFiller.data;\n\n\t\treturn nodeAfterFiller;\n\t} else {\n\t\tconst fillerNode = domDocument.createTextNode( INLINE_FILLER );\n\n\t\tif ( Array.isArray( domParentOrArray ) ) {\n\t\t\tchildNodes.splice( offset, 0, fillerNode );\n\t\t} else {\n\t\t\tinsertAt( domParentOrArray, offset, fillerNode );\n\t\t}\n\n\t\treturn fillerNode;\n\t}\n}\n\n// Whether two DOM nodes should be considered as similar.\n// Nodes are considered similar if they have the same tag name.\n//\n// @private\n// @param {Node} node1\n// @param {Node} node2\n// @returns {Boolean}\nfunction areSimilar( node1, node2 ) {\n\treturn isNode( node1 ) && isNode( node2 ) &&\n\t\t!isText( node1 ) && !isText( node2 ) &&\n\t\tnode1.tagName.toLowerCase() === node2.tagName.toLowerCase();\n}\n\n// Whether two dom nodes should be considered as the same.\n// Two nodes which are considered the same are:\n//\n//\t\t* Text nodes with the same text.\n//\t\t* Element nodes represented by the same object.\n//\t\t* Two block filler elements.\n//\n// @private\n// @param {String} blockFillerMode Block filler mode, see {@link module:engine/view/domconverter~DomConverter#blockFillerMode}.\n// @param {Node} node1\n// @param {Node} node2\n// @returns {Boolean}\nfunction sameNodes( domConverter, actualDomChild, expectedDomChild ) {\n\t// Elements.\n\tif ( actualDomChild === expectedDomChild ) {\n\t\treturn true;\n\t}\n\t// Texts.\n\telse if ( isText( actualDomChild ) && isText( expectedDomChild ) ) {\n\t\treturn actualDomChild.data === expectedDomChild.data;\n\t}\n\t// Block fillers.\n\telse if ( domConverter.isBlockFiller( actualDomChild ) &&\n\t\tdomConverter.isBlockFiller( expectedDomChild ) ) {\n\t\treturn true;\n\t}\n\n\t// Not matching types.\n\treturn false;\n}\n\n// The following is a Firefox–specific hack (https://github.com/ckeditor/ckeditor5-engine/issues/1439).\n// When the native DOM selection is at the end of the block and preceded by <br /> e.g.\n//\n//\t\t<p>foo<br/>[]</p>\n//\n// which happens a lot when using the soft line break, the browser fails to (visually) move the\n// caret to the new line. A quick fix is as simple as force–refreshing the selection with the same range.\nfunction fixGeckoSelectionAfterBr( focus, domSelection ) {\n\tconst parent = focus.parent;\n\n\t// This fix works only when the focus point is at the very end of an element.\n\t// There is no point in running it in cases unrelated to the browser bug.\n\tif ( parent.nodeType != Node.ELEMENT_NODE || focus.offset != parent.childNodes.length - 1 ) {\n\t\treturn;\n\t}\n\n\tconst childAtOffset = parent.childNodes[ focus.offset ];\n\n\t// To stay on the safe side, the fix being as specific as possible, it targets only the\n\t// selection which is at the very end of the element and preceded by <br />.\n\tif ( childAtOffset && childAtOffset.tagName == 'BR' ) {\n\t\tdomSelection.addRange( domSelection.getRangeAt( 0 ) );\n\t}\n}\n\nfunction filterOutFakeSelectionContainer( domChildList, fakeSelectionContainer ) {\n\tconst childList = Array.from( domChildList );\n\n\tif ( childList.length == 0 || !fakeSelectionContainer ) {\n\t\treturn childList;\n\t}\n\n\tconst last = childList[ childList.length - 1 ];\n\n\tif ( last == fakeSelectionContainer ) {\n\t\tchildList.pop();\n\t}\n\n\treturn childList;\n}\n\n// Creates a fake selection container for a given document.\n//\n// @private\n// @param {Document} domDocument\n// @returns {HTMLElement}\nfunction createFakeSelectionContainer( domDocument ) {\n\tconst container = domDocument.createElement( 'div' );\n\n\tObject.assign( container.style, {\n\t\tposition: 'fixed',\n\t\ttop: 0,\n\t\tleft: '-9999px',\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/752.\n\t\twidth: '42px'\n\t} );\n\n\t// Fill it with a text node so we can update it later.\n\tcontainer.textContent = '\\u00A0';\n\n\treturn container;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals window, document */\n\n/**\n * @module utils/dom/global\n */\n\n/**\n * A helper (module) giving an access to the global DOM objects such as `window` and\n * `document`. Accessing these objects using this helper allows easy and bulletproof\n * testing, i.e. stubbing native properties:\n *\n *\t\timport global from 'ckeditor5/utils/dom/global.js';\n *\n *\t\t// This stub will work for any code using global module.\n *\t\ttestUtils.sinon.stub( global, 'window', {\n *\t\t\tinnerWidth: 10000\n *\t\t} );\n *\n *\t\tconsole.log( global.window.innerWidth );\n */\nexport default { window, document };\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/indexof\n */\n\n/**\n * Returns index of the node in the parent element.\n *\n * @param {Node} node Node which index is tested.\n * @returns {Number} Index of the node in the parent element. Returns 0 if node has no parent.\n */\nexport default function indexOf( node ) {\n\tlet index = 0;\n\n\twhile ( node.previousSibling ) {\n\t\tnode = node.previousSibling;\n\t\tindex++;\n\t}\n\n\treturn index;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals Node */\n\n/**\n * @module utils/dom/getancestors\n */\n\n/**\n * Returns all ancestors of given DOM node, starting from the top-most (root). Includes the given node itself. If the\n * node is a part of `DocumentFragment` that `DocumentFragment` will be returned. In contrary, if the node is\n * appended to a `Document`, that `Document` will not be returned (algorithms operating on DOM tree care for `Document#documentElement`\n * at most, which will be returned).\n *\n * @param {Node} node DOM node.\n * @returns {Array.<Node|DocumentFragment>} Array of given `node` parents.\n */\nexport default function getAncestors( node ) {\n\tconst nodes = [];\n\n\t// We are interested in `Node`s `DocumentFragment`s only.\n\twhile ( node && node.nodeType != Node.DOCUMENT_NODE ) {\n\t\tnodes.unshift( node );\n\t\tnode = node.parentNode;\n\t}\n\n\treturn nodes;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/domconverter\n */\n\n/* globals document, Node, NodeFilter, Text */\n\nimport ViewText from './text';\nimport ViewElement from './element';\nimport ViewPosition from './position';\nimport ViewRange from './range';\nimport ViewSelection from './selection';\nimport ViewDocumentFragment from './documentfragment';\nimport ViewTreeWalker from './treewalker';\nimport { BR_FILLER, getDataWithoutFiller, INLINE_FILLER_LENGTH, isInlineFiller, NBSP_FILLER, startsWithFiller } from './filler';\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport indexOf from '@ckeditor/ckeditor5-utils/src/dom/indexof';\nimport getAncestors from '@ckeditor/ckeditor5-utils/src/dom/getancestors';\nimport getCommonAncestor from '@ckeditor/ckeditor5-utils/src/dom/getcommonancestor';\nimport isText from '@ckeditor/ckeditor5-utils/src/dom/istext';\nimport { isElement } from 'lodash-es';\n\n// eslint-disable-next-line new-cap\nconst BR_FILLER_REF = BR_FILLER( document );\n\n/**\n * DomConverter is a set of tools to do transformations between DOM nodes and view nodes. It also handles\n * {@link module:engine/view/domconverter~DomConverter#bindElements binding} these nodes.\n *\n * The instance of DOMConverter is available in {@link module:engine/view/view~View#domConverter `editor.editing.view.domConverter`}.\n *\n * DomConverter does not check which nodes should be rendered (use {@link module:engine/view/renderer~Renderer}), does not keep a\n * state of a tree nor keeps synchronization between tree view and DOM tree (use {@link module:engine/view/document~Document}).\n *\n * DomConverter keeps DOM elements to View element bindings, so when the converter will be destroyed, the binding will\n * be lost. Two converters will keep separate binding maps, so one tree view can be bound with two DOM trees.\n */\nexport default class DomConverter {\n\t/**\n\t * Creates DOM converter.\n\t *\n\t * @param {Object} options Object with configuration options.\n\t * @param {module:engine/view/filler~BlockFillerMode} [options.blockFillerMode='br'] The type of the block filler to use.\n\t */\n\tconstructor( options = {} ) {\n\t\t/**\n\t\t * The mode of a block filler used by DOM converter.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'br'|'nbsp'} module:engine/view/domconverter~DomConverter#blockFillerMode\n\t\t */\n\t\tthis.blockFillerMode = options.blockFillerMode || 'br';\n\n\t\t/**\n\t\t * Elements which are considered pre-formatted elements.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<String>} module:engine/view/domconverter~DomConverter#preElements\n\t\t */\n\t\tthis.preElements = [ 'pre' ];\n\n\t\t/**\n\t\t * Elements which are considered block elements (and hence should be filled with a\n\t\t * {@link #isBlockFiller block filler}).\n\t\t *\n\t\t * Whether an element is considered a block element also affects handling of trailing whitespaces.\n\t\t *\n\t\t * You can extend this array if you introduce support for block elements which are not yet recognized here.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<String>} module:engine/view/domconverter~DomConverter#blockElements\n\t\t */\n\t\tthis.blockElements = [ 'p', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li', 'dd', 'dt', 'figcaption' ];\n\n\t\t/**\n\t\t * Block {@link module:engine/view/filler filler} creator, which is used to create all block fillers during the\n\t\t * view to DOM conversion and to recognize block fillers during the DOM to view conversion.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {Function} module:engine/view/domconverter~DomConverter#_blockFiller\n\t\t */\n\t\tthis._blockFiller = this.blockFillerMode == 'br' ? BR_FILLER : NBSP_FILLER;\n\n\t\t/**\n\t\t * DOM to View mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap} module:engine/view/domconverter~DomConverter#_domToViewMapping\n\t\t */\n\t\tthis._domToViewMapping = new WeakMap();\n\n\t\t/**\n\t\t * View to DOM mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap} module:engine/view/domconverter~DomConverter#_viewToDomMapping\n\t\t */\n\t\tthis._viewToDomMapping = new WeakMap();\n\n\t\t/**\n\t\t * Holds mapping between fake selection containers and corresponding view selections.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap} module:engine/view/domconverter~DomConverter#_fakeSelectionMapping\n\t\t */\n\t\tthis._fakeSelectionMapping = new WeakMap();\n\t}\n\n\t/**\n\t * Binds given DOM element that represents fake selection to a **position** of a\n\t * {@link module:engine/view/documentselection~DocumentSelection document selection}.\n\t * Document selection copy is stored and can be retrieved by\n\t * {@link module:engine/view/domconverter~DomConverter#fakeSelectionToView} method.\n\t *\n\t * @param {HTMLElement} domElement\n\t * @param {module:engine/view/documentselection~DocumentSelection} viewDocumentSelection\n\t */\n\tbindFakeSelection( domElement, viewDocumentSelection ) {\n\t\tthis._fakeSelectionMapping.set( domElement, new ViewSelection( viewDocumentSelection ) );\n\t}\n\n\t/**\n\t * Returns {@link module:engine/view/selection~Selection view selection} instance corresponding to\n\t * given DOM element that represents fake selection. Returns `undefined` if binding to given DOM element does not exists.\n\t *\n\t * @param {HTMLElement} domElement\n\t * @returns {module:engine/view/selection~Selection|undefined}\n\t */\n\tfakeSelectionToView( domElement ) {\n\t\treturn this._fakeSelectionMapping.get( domElement );\n\t}\n\n\t/**\n\t * Binds DOM and View elements, so it will be possible to get corresponding elements using\n\t * {@link module:engine/view/domconverter~DomConverter#mapDomToView} and\n\t * {@link module:engine/view/domconverter~DomConverter#mapViewToDom}.\n\t *\n\t * @param {HTMLElement} domElement DOM element to bind.\n\t * @param {module:engine/view/element~Element} viewElement View element to bind.\n\t */\n\tbindElements( domElement, viewElement ) {\n\t\tthis._domToViewMapping.set( domElement, viewElement );\n\t\tthis._viewToDomMapping.set( viewElement, domElement );\n\t}\n\n\t/**\n\t * Unbinds given `domElement` from the view element it was bound to. Unbinding is deep, meaning that all children of\n\t * `domElement` will be unbound too.\n\t *\n\t * @param {HTMLElement} domElement DOM element to unbind.\n\t */\n\tunbindDomElement( domElement ) {\n\t\tconst viewElement = this._domToViewMapping.get( domElement );\n\n\t\tif ( viewElement ) {\n\t\t\tthis._domToViewMapping.delete( domElement );\n\t\t\tthis._viewToDomMapping.delete( viewElement );\n\n\t\t\t// Use Array.from because of MS Edge (#923).\n\t\t\tfor ( const child of Array.from( domElement.childNodes ) ) {\n\t\t\t\tthis.unbindDomElement( child );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Binds DOM and View document fragments, so it will be possible to get corresponding document fragments using\n\t * {@link module:engine/view/domconverter~DomConverter#mapDomToView} and\n\t * {@link module:engine/view/domconverter~DomConverter#mapViewToDom}.\n\t *\n\t * @param {DocumentFragment} domFragment DOM document fragment to bind.\n\t * @param {module:engine/view/documentfragment~DocumentFragment} viewFragment View document fragment to bind.\n\t */\n\tbindDocumentFragments( domFragment, viewFragment ) {\n\t\tthis._domToViewMapping.set( domFragment, viewFragment );\n\t\tthis._viewToDomMapping.set( viewFragment, domFragment );\n\t}\n\n\t/**\n\t * Converts view to DOM. For all text nodes, not bound elements and document fragments new items will\n\t * be created. For bound elements and document fragments function will return corresponding items.\n\t *\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} viewNode\n\t * View node or document fragment to transform.\n\t * @param {Document} domDocument Document which will be used to create DOM nodes.\n\t * @param {Object} [options] Conversion options.\n\t * @param {Boolean} [options.bind=false] Determines whether new elements will be bound.\n\t * @param {Boolean} [options.withChildren=true] If `true`, node's and document fragment's children will be converted too.\n\t * @returns {Node|DocumentFragment} Converted node or DocumentFragment.\n\t */\n\tviewToDom( viewNode, domDocument, options = {} ) {\n\t\tif ( viewNode.is( 'text' ) ) {\n\t\t\tconst textData = this._processDataFromViewText( viewNode );\n\n\t\t\treturn domDocument.createTextNode( textData );\n\t\t} else {\n\t\t\tif ( this.mapViewToDom( viewNode ) ) {\n\t\t\t\treturn this.mapViewToDom( viewNode );\n\t\t\t}\n\n\t\t\tlet domElement;\n\n\t\t\tif ( viewNode.is( 'documentFragment' ) ) {\n\t\t\t\t// Create DOM document fragment.\n\t\t\t\tdomElement = domDocument.createDocumentFragment();\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindDocumentFragments( domElement, viewNode );\n\t\t\t\t}\n\t\t\t} else if ( viewNode.is( 'uiElement' ) ) {\n\t\t\t\t// UIElement has its own render() method (see #799).\n\t\t\t\tdomElement = viewNode.render( domDocument );\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindElements( domElement, viewNode );\n\t\t\t\t}\n\n\t\t\t\treturn domElement;\n\t\t\t} else {\n\t\t\t\t// Create DOM element.\n\t\t\t\tif ( viewNode.hasAttribute( 'xmlns' ) ) {\n\t\t\t\t\tdomElement = domDocument.createElementNS( viewNode.getAttribute( 'xmlns' ), viewNode.name );\n\t\t\t\t} else {\n\t\t\t\t\tdomElement = domDocument.createElement( viewNode.name );\n\t\t\t\t}\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindElements( domElement, viewNode );\n\t\t\t\t}\n\n\t\t\t\t// Copy element's attributes.\n\t\t\t\tfor ( const key of viewNode.getAttributeKeys() ) {\n\t\t\t\t\tdomElement.setAttribute( key, viewNode.getAttribute( key ) );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( options.withChildren || options.withChildren === undefined ) {\n\t\t\t\tfor ( const child of this.viewChildrenToDom( viewNode, domDocument, options ) ) {\n\t\t\t\t\tdomElement.appendChild( child );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn domElement;\n\t\t}\n\t}\n\n\t/**\n\t * Converts children of the view element to DOM using the\n\t * {@link module:engine/view/domconverter~DomConverter#viewToDom} method.\n\t * Additionally, this method adds block {@link module:engine/view/filler filler} to the list of children, if needed.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewElement Parent view element.\n\t * @param {Document} domDocument Document which will be used to create DOM nodes.\n\t * @param {Object} options See {@link module:engine/view/domconverter~DomConverter#viewToDom} options parameter.\n\t * @returns {Iterable.<Node>} DOM nodes.\n\t */\n\t* viewChildrenToDom( viewElement, domDocument, options = {} ) {\n\t\tconst fillerPositionOffset = viewElement.getFillerOffset && viewElement.getFillerOffset();\n\t\tlet offset = 0;\n\n\t\tfor ( const childView of viewElement.getChildren() ) {\n\t\t\tif ( fillerPositionOffset === offset ) {\n\t\t\t\tyield this._blockFiller( domDocument );\n\t\t\t}\n\n\t\t\tyield this.viewToDom( childView, domDocument, options );\n\n\t\t\toffset++;\n\t\t}\n\n\t\tif ( fillerPositionOffset === offset ) {\n\t\t\tyield this._blockFiller( domDocument );\n\t\t}\n\t}\n\n\t/**\n\t * Converts view {@link module:engine/view/range~Range} to DOM range.\n\t * Inline and block {@link module:engine/view/filler fillers} are handled during the conversion.\n\t *\n\t * @param {module:engine/view/range~Range} viewRange View range.\n\t * @returns {Range} DOM range.\n\t */\n\tviewRangeToDom( viewRange ) {\n\t\tconst domStart = this.viewPositionToDom( viewRange.start );\n\t\tconst domEnd = this.viewPositionToDom( viewRange.end );\n\n\t\tconst domRange = document.createRange();\n\t\tdomRange.setStart( domStart.parent, domStart.offset );\n\t\tdomRange.setEnd( domEnd.parent, domEnd.offset );\n\n\t\treturn domRange;\n\t}\n\n\t/**\n\t * Converts view {@link module:engine/view/position~Position} to DOM parent and offset.\n\t *\n\t * Inline and block {@link module:engine/view/filler fillers} are handled during the conversion.\n\t * If the converted position is directly before inline filler it is moved inside the filler.\n\t *\n\t * @param {module:engine/view/position~Position} viewPosition View position.\n\t * @returns {Object|null} position DOM position or `null` if view position could not be converted to DOM.\n\t * @returns {Node} position.parent DOM position parent.\n\t * @returns {Number} position.offset DOM position offset.\n\t */\n\tviewPositionToDom( viewPosition ) {\n\t\tconst viewParent = viewPosition.parent;\n\n\t\tif ( viewParent.is( 'text' ) ) {\n\t\t\tconst domParent = this.findCorrespondingDomText( viewParent );\n\n\t\t\tif ( !domParent ) {\n\t\t\t\t// Position is in a view text node that has not been rendered to DOM yet.\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tlet offset = viewPosition.offset;\n\n\t\t\tif ( startsWithFiller( domParent ) ) {\n\t\t\t\toffset += INLINE_FILLER_LENGTH;\n\t\t\t}\n\n\t\t\treturn { parent: domParent, offset };\n\t\t} else {\n\t\t\t// viewParent is instance of ViewElement.\n\t\t\tlet domParent, domBefore, domAfter;\n\n\t\t\tif ( viewPosition.offset === 0 ) {\n\t\t\t\tdomParent = this.mapViewToDom( viewParent );\n\n\t\t\t\tif ( !domParent ) {\n\t\t\t\t\t// Position is in a view element that has not been rendered to DOM yet.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tdomAfter = domParent.childNodes[ 0 ];\n\t\t\t} else {\n\t\t\t\tconst nodeBefore = viewPosition.nodeBefore;\n\n\t\t\t\tdomBefore = nodeBefore.is( 'text' ) ?\n\t\t\t\t\tthis.findCorrespondingDomText( nodeBefore ) :\n\t\t\t\t\tthis.mapViewToDom( viewPosition.nodeBefore );\n\n\t\t\t\tif ( !domBefore ) {\n\t\t\t\t\t// Position is after a view element that has not been rendered to DOM yet.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tdomParent = domBefore.parentNode;\n\t\t\t\tdomAfter = domBefore.nextSibling;\n\t\t\t}\n\n\t\t\t// If there is an inline filler at position return position inside the filler. We should never return\n\t\t\t// the position before the inline filler.\n\t\t\tif ( isText( domAfter ) && startsWithFiller( domAfter ) ) {\n\t\t\t\treturn { parent: domAfter, offset: INLINE_FILLER_LENGTH };\n\t\t\t}\n\n\t\t\tconst offset = domBefore ? indexOf( domBefore ) + 1 : 0;\n\n\t\t\treturn { parent: domParent, offset };\n\t\t}\n\t}\n\n\t/**\n\t * Converts DOM to view. For all text nodes, not bound elements and document fragments new items will\n\t * be created. For bound elements and document fragments function will return corresponding items. For\n\t * {@link module:engine/view/filler fillers} `null` will be returned.\n\t * For all DOM elements rendered by {@link module:engine/view/uielement~UIElement} that UIElement will be returned.\n\t *\n\t * @param {Node|DocumentFragment} domNode DOM node or document fragment to transform.\n\t * @param {Object} [options] Conversion options.\n\t * @param {Boolean} [options.bind=false] Determines whether new elements will be bound.\n\t * @param {Boolean} [options.withChildren=true] If `true`, node's and document fragment's children will be converted too.\n\t * @param {Boolean} [options.keepOriginalCase=false] If `false`, node's tag name will be converter to lower case.\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null} Converted node or document fragment\n\t * or `null` if DOM node is a {@link module:engine/view/filler filler} or the given node is an empty text node.\n\t */\n\tdomToView( domNode, options = {} ) {\n\t\tif ( this.isBlockFiller( domNode, this.blockFillerMode ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// When node is inside UIElement return that UIElement as it's view representation.\n\t\tconst uiElement = this.getParentUIElement( domNode, this._domToViewMapping );\n\n\t\tif ( uiElement ) {\n\t\t\treturn uiElement;\n\t\t}\n\n\t\tif ( isText( domNode ) ) {\n\t\t\tif ( isInlineFiller( domNode ) ) {\n\t\t\t\treturn null;\n\t\t\t} else {\n\t\t\t\tconst textData = this._processDataFromDomText( domNode );\n\n\t\t\t\treturn textData === '' ? null : new ViewText( textData );\n\t\t\t}\n\t\t} else if ( this.isComment( domNode ) ) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\tif ( this.mapDomToView( domNode ) ) {\n\t\t\t\treturn this.mapDomToView( domNode );\n\t\t\t}\n\n\t\t\tlet viewElement;\n\n\t\t\tif ( this.isDocumentFragment( domNode ) ) {\n\t\t\t\t// Create view document fragment.\n\t\t\t\tviewElement = new ViewDocumentFragment();\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindDocumentFragments( domNode, viewElement );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Create view element.\n\t\t\t\tconst viewName = options.keepOriginalCase ? domNode.tagName : domNode.tagName.toLowerCase();\n\t\t\t\tviewElement = new ViewElement( viewName );\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindElements( domNode, viewElement );\n\t\t\t\t}\n\n\t\t\t\t// Copy element's attributes.\n\t\t\t\tconst attrs = domNode.attributes;\n\n\t\t\t\tfor ( let i = attrs.length - 1; i >= 0; i-- ) {\n\t\t\t\t\tviewElement._setAttribute( attrs[ i ].name, attrs[ i ].value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( options.withChildren || options.withChildren === undefined ) {\n\t\t\t\tfor ( const child of this.domChildrenToView( domNode, options ) ) {\n\t\t\t\t\tviewElement._appendChild( child );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn viewElement;\n\t\t}\n\t}\n\n\t/**\n\t * Converts children of the DOM element to view nodes using\n\t * the {@link module:engine/view/domconverter~DomConverter#domToView} method.\n\t * Additionally this method omits block {@link module:engine/view/filler filler}, if it exists in the DOM parent.\n\t *\n\t * @param {HTMLElement} domElement Parent DOM element.\n\t * @param {Object} options See {@link module:engine/view/domconverter~DomConverter#domToView} options parameter.\n\t * @returns {Iterable.<module:engine/view/node~Node>} View nodes.\n\t */\n\t* domChildrenToView( domElement, options = {} ) {\n\t\tfor ( let i = 0; i < domElement.childNodes.length; i++ ) {\n\t\t\tconst domChild = domElement.childNodes[ i ];\n\t\t\tconst viewChild = this.domToView( domChild, options );\n\n\t\t\tif ( viewChild !== null ) {\n\t\t\t\tyield viewChild;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Converts DOM selection to view {@link module:engine/view/selection~Selection}.\n\t * Ranges which cannot be converted will be omitted.\n\t *\n\t * @param {Selection} domSelection DOM selection.\n\t * @returns {module:engine/view/selection~Selection} View selection.\n\t */\n\tdomSelectionToView( domSelection ) {\n\t\t// DOM selection might be placed in fake selection container.\n\t\t// If container contains fake selection - return corresponding view selection.\n\t\tif ( domSelection.rangeCount === 1 ) {\n\t\t\tlet container = domSelection.getRangeAt( 0 ).startContainer;\n\n\t\t\t// The DOM selection might be moved to the text node inside the fake selection container.\n\t\t\tif ( isText( container ) ) {\n\t\t\t\tcontainer = container.parentNode;\n\t\t\t}\n\n\t\t\tconst viewSelection = this.fakeSelectionToView( container );\n\n\t\t\tif ( viewSelection ) {\n\t\t\t\treturn viewSelection;\n\t\t\t}\n\t\t}\n\n\t\tconst isBackward = this.isDomSelectionBackward( domSelection );\n\n\t\tconst viewRanges = [];\n\n\t\tfor ( let i = 0; i < domSelection.rangeCount; i++ ) {\n\t\t\t// DOM Range have correct start and end, no matter what is the DOM Selection direction. So we don't have to fix anything.\n\t\t\tconst domRange = domSelection.getRangeAt( i );\n\t\t\tconst viewRange = this.domRangeToView( domRange );\n\n\t\t\tif ( viewRange ) {\n\t\t\t\tviewRanges.push( viewRange );\n\t\t\t}\n\t\t}\n\n\t\treturn new ViewSelection( viewRanges, { backward: isBackward } );\n\t}\n\n\t/**\n\t * Converts DOM Range to view {@link module:engine/view/range~Range}.\n\t * If the start or end position can not be converted `null` is returned.\n\t *\n\t * @param {Range} domRange DOM range.\n\t * @returns {module:engine/view/range~Range|null} View range.\n\t */\n\tdomRangeToView( domRange ) {\n\t\tconst viewStart = this.domPositionToView( domRange.startContainer, domRange.startOffset );\n\t\tconst viewEnd = this.domPositionToView( domRange.endContainer, domRange.endOffset );\n\n\t\tif ( viewStart && viewEnd ) {\n\t\t\treturn new ViewRange( viewStart, viewEnd );\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Converts DOM parent and offset to view {@link module:engine/view/position~Position}.\n\t *\n\t * If the position is inside a {@link module:engine/view/filler filler} which has no corresponding view node,\n\t * position of the filler will be converted and returned.\n\t *\n\t * If the position is inside DOM element rendered by {@link module:engine/view/uielement~UIElement}\n\t * that position will be converted to view position before that UIElement.\n\t *\n\t * If structures are too different and it is not possible to find corresponding position then `null` will be returned.\n\t *\n\t * @param {Node} domParent DOM position parent.\n\t * @param {Number} domOffset DOM position offset.\n\t * @returns {module:engine/view/position~Position} viewPosition View position.\n\t */\n\tdomPositionToView( domParent, domOffset ) {\n\t\tif ( this.isBlockFiller( domParent, this.blockFillerMode ) ) {\n\t\t\treturn this.domPositionToView( domParent.parentNode, indexOf( domParent ) );\n\t\t}\n\n\t\t// If position is somewhere inside UIElement - return position before that element.\n\t\tconst viewElement = this.mapDomToView( domParent );\n\n\t\tif ( viewElement && viewElement.is( 'uiElement' ) ) {\n\t\t\treturn ViewPosition._createBefore( viewElement );\n\t\t}\n\n\t\tif ( isText( domParent ) ) {\n\t\t\tif ( isInlineFiller( domParent ) ) {\n\t\t\t\treturn this.domPositionToView( domParent.parentNode, indexOf( domParent ) );\n\t\t\t}\n\n\t\t\tconst viewParent = this.findCorrespondingViewText( domParent );\n\t\t\tlet offset = domOffset;\n\n\t\t\tif ( !viewParent ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( startsWithFiller( domParent ) ) {\n\t\t\t\toffset -= INLINE_FILLER_LENGTH;\n\t\t\t\toffset = offset < 0 ? 0 : offset;\n\t\t\t}\n\n\t\t\treturn new ViewPosition( viewParent, offset );\n\t\t}\n\t\t// domParent instanceof HTMLElement.\n\t\telse {\n\t\t\tif ( domOffset === 0 ) {\n\t\t\t\tconst viewParent = this.mapDomToView( domParent );\n\n\t\t\t\tif ( viewParent ) {\n\t\t\t\t\treturn new ViewPosition( viewParent, 0 );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst domBefore = domParent.childNodes[ domOffset - 1 ];\n\t\t\t\tconst viewBefore = isText( domBefore ) ?\n\t\t\t\t\tthis.findCorrespondingViewText( domBefore ) :\n\t\t\t\t\tthis.mapDomToView( domBefore );\n\n\t\t\t\t// TODO #663\n\t\t\t\tif ( viewBefore && viewBefore.parent ) {\n\t\t\t\t\treturn new ViewPosition( viewBefore.parent, viewBefore.index + 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Returns corresponding view {@link module:engine/view/element~Element Element} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment} for provided DOM element or\n\t * document fragment. If there is no view item {@link module:engine/view/domconverter~DomConverter#bindElements bound}\n\t * to the given DOM - `undefined` is returned.\n\t * For all DOM elements rendered by {@link module:engine/view/uielement~UIElement} that UIElement will be returned.\n\t *\n\t * @param {DocumentFragment|Element} domElementOrDocumentFragment DOM element or document fragment.\n\t * @returns {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|undefined}\n\t * Corresponding view element, document fragment or `undefined` if no element was bound.\n\t */\n\tmapDomToView( domElementOrDocumentFragment ) {\n\t\treturn this.getParentUIElement( domElementOrDocumentFragment ) || this._domToViewMapping.get( domElementOrDocumentFragment );\n\t}\n\n\t/**\n\t * Finds corresponding text node. Text nodes are not {@link module:engine/view/domconverter~DomConverter#bindElements bound},\n\t * corresponding text node is returned based on the sibling or parent.\n\t *\n\t * If the directly previous sibling is a {@link module:engine/view/domconverter~DomConverter#bindElements bound} element, it is used\n\t * to find the corresponding text node.\n\t *\n\t * If this is a first child in the parent and the parent is a {@link module:engine/view/domconverter~DomConverter#bindElements bound}\n\t * element, it is used to find the corresponding text node.\n\t *\n\t * For all text nodes rendered by {@link module:engine/view/uielement~UIElement} that UIElement will be returned.\n\t *\n\t * Otherwise `null` is returned.\n\t *\n\t * Note that for the block or inline {@link module:engine/view/filler filler} this method returns `null`.\n\t *\n\t * @param {Text} domText DOM text node.\n\t * @returns {module:engine/view/text~Text|null} Corresponding view text node or `null`, if it was not possible to find a\n\t * corresponding node.\n\t */\n\tfindCorrespondingViewText( domText ) {\n\t\tif ( isInlineFiller( domText ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// If DOM text was rendered by UIElement - return that element.\n\t\tconst uiElement = this.getParentUIElement( domText );\n\n\t\tif ( uiElement ) {\n\t\t\treturn uiElement;\n\t\t}\n\n\t\tconst previousSibling = domText.previousSibling;\n\n\t\t// Try to use previous sibling to find the corresponding text node.\n\t\tif ( previousSibling ) {\n\t\t\tif ( !( this.isElement( previousSibling ) ) ) {\n\t\t\t\t// The previous is text or comment.\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst viewElement = this.mapDomToView( previousSibling );\n\n\t\t\tif ( viewElement ) {\n\t\t\t\tconst nextSibling = viewElement.nextSibling;\n\n\t\t\t\t// It might be filler which has no corresponding view node.\n\t\t\t\tif ( nextSibling instanceof ViewText ) {\n\t\t\t\t\treturn viewElement.nextSibling;\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Try to use parent to find the corresponding text node.\n\t\telse {\n\t\t\tconst viewElement = this.mapDomToView( domText.parentNode );\n\n\t\t\tif ( viewElement ) {\n\t\t\t\tconst firstChild = viewElement.getChild( 0 );\n\n\t\t\t\t// It might be filler which has no corresponding view node.\n\t\t\t\tif ( firstChild instanceof ViewText ) {\n\t\t\t\t\treturn firstChild;\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns corresponding DOM item for provided {@link module:engine/view/element~Element Element} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment}.\n\t * To find a corresponding text for {@link module:engine/view/text~Text view Text instance}\n\t * use {@link #findCorrespondingDomText}.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewNode\n\t * View element or document fragment.\n\t * @returns {Node|DocumentFragment|undefined} Corresponding DOM node or document fragment.\n\t */\n\tmapViewToDom( documentFragmentOrElement ) {\n\t\treturn this._viewToDomMapping.get( documentFragmentOrElement );\n\t}\n\n\t/**\n\t * Finds corresponding text node. Text nodes are not {@link module:engine/view/domconverter~DomConverter#bindElements bound},\n\t * corresponding text node is returned based on the sibling or parent.\n\t *\n\t * If the directly previous sibling is a {@link module:engine/view/domconverter~DomConverter#bindElements bound} element, it is used\n\t * to find the corresponding text node.\n\t *\n\t * If this is a first child in the parent and the parent is a {@link module:engine/view/domconverter~DomConverter#bindElements bound}\n\t * element, it is used to find the corresponding text node.\n\t *\n\t * Otherwise `null` is returned.\n\t *\n\t * @param {module:engine/view/text~Text} viewText View text node.\n\t * @returns {Text|null} Corresponding DOM text node or `null`, if it was not possible to find a corresponding node.\n\t */\n\tfindCorrespondingDomText( viewText ) {\n\t\tconst previousSibling = viewText.previousSibling;\n\n\t\t// Try to use previous sibling to find the corresponding text node.\n\t\tif ( previousSibling && this.mapViewToDom( previousSibling ) ) {\n\t\t\treturn this.mapViewToDom( previousSibling ).nextSibling;\n\t\t}\n\n\t\t// If this is a first node, try to use parent to find the corresponding text node.\n\t\tif ( !previousSibling && viewText.parent && this.mapViewToDom( viewText.parent ) ) {\n\t\t\treturn this.mapViewToDom( viewText.parent ).childNodes[ 0 ];\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Focuses DOM editable that is corresponding to provided {@link module:engine/view/editableelement~EditableElement}.\n\t *\n\t * @param {module:engine/view/editableelement~EditableElement} viewEditable\n\t */\n\tfocus( viewEditable ) {\n\t\tconst domEditable = this.mapViewToDom( viewEditable );\n\n\t\tif ( domEditable && domEditable.ownerDocument.activeElement !== domEditable ) {\n\t\t\t// Save the scrollX and scrollY positions before the focus.\n\t\t\tconst { scrollX, scrollY } = global.window;\n\t\t\tconst scrollPositions = [];\n\n\t\t\t// Save all scrollLeft and scrollTop values starting from domEditable up to\n\t\t\t// document#documentElement.\n\t\t\tforEachDomNodeAncestor( domEditable, node => {\n\t\t\t\tconst { scrollLeft, scrollTop } = node;\n\n\t\t\t\tscrollPositions.push( [ scrollLeft, scrollTop ] );\n\t\t\t} );\n\n\t\t\tdomEditable.focus();\n\n\t\t\t// Restore scrollLeft and scrollTop values starting from domEditable up to\n\t\t\t// document#documentElement.\n\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/951\n\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/957\n\t\t\tforEachDomNodeAncestor( domEditable, node => {\n\t\t\t\tconst [ scrollLeft, scrollTop ] = scrollPositions.shift();\n\n\t\t\t\tnode.scrollLeft = scrollLeft;\n\t\t\t\tnode.scrollTop = scrollTop;\n\t\t\t} );\n\n\t\t\t// Restore the scrollX and scrollY positions after the focus.\n\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/951\n\t\t\tglobal.window.scrollTo( scrollX, scrollY );\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` when `node.nodeType` equals `Node.ELEMENT_NODE`.\n\t *\n\t * @param {Node} node Node to check.\n\t * @returns {Boolean}\n\t */\n\tisElement( node ) {\n\t\treturn node && node.nodeType == Node.ELEMENT_NODE;\n\t}\n\n\t/**\n\t * Returns `true` when `node.nodeType` equals `Node.DOCUMENT_FRAGMENT_NODE`.\n\t *\n\t * @param {Node} node Node to check.\n\t * @returns {Boolean}\n\t */\n\tisDocumentFragment( node ) {\n\t\treturn node && node.nodeType == Node.DOCUMENT_FRAGMENT_NODE;\n\t}\n\n\t/**\n\t * Returns `true` when `node.nodeType` equals `Node.COMMENT_NODE`.\n\t *\n\t * @param {Node} node Node to check.\n\t * @returns {Boolean}\n\t */\n\tisComment( node ) {\n\t\treturn node && node.nodeType == Node.COMMENT_NODE;\n\t}\n\n\t/**\n\t * Checks if the node is an instance of the block filler for this DOM converter.\n\t *\n\t *\t\tconst converter = new DomConverter( { blockFillerMode: 'br' } );\n\t *\n\t *\t\tconverter.isBlockFiller( BR_FILLER( document ) ); // true\n\t *\t\tconverter.isBlockFiller( NBSP_FILLER( document ) ); // false\n\t *\n\t * **Note:**: For the `'nbsp'` mode the method also checks context of a node so it cannot be a detached node.\n\t *\n\t * **Note:** A special case in the `'nbsp'` mode exists where the `<br>` in `<p><br></p>` is treated as a block filler.\n\t *\n\t * @param {Node} domNode DOM node to check.\n\t * @returns {Boolean} True if a node is considered a block filler for given mode.\n\t */\n\tisBlockFiller( domNode ) {\n\t\tif ( this.blockFillerMode == 'br' ) {\n\t\t\treturn domNode.isEqualNode( BR_FILLER_REF );\n\t\t}\n\n\t\t// Special case for <p><br></p> in which case the <br> should be treated as filler even\n\t\t// when we're in the 'nbsp' mode. See ckeditor5#5564.\n\t\tif ( domNode.tagName === 'BR' && hasBlockParent( domNode, this.blockElements ) && domNode.parentNode.childNodes.length === 1 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn isNbspBlockFiller( domNode, this.blockElements );\n\t}\n\n\t/**\n\t * Returns `true` if given selection is a backward selection, that is, if it's `focus` is before `anchor`.\n\t *\n\t * @param {Selection} DOM Selection instance to check.\n\t * @returns {Boolean}\n\t */\n\tisDomSelectionBackward( selection ) {\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Since it takes multiple lines of code to check whether a \"DOM Position\" is before/after another \"DOM Position\",\n\t\t// we will use the fact that range will collapse if it's end is before it's start.\n\t\tconst range = document.createRange();\n\n\t\trange.setStart( selection.anchorNode, selection.anchorOffset );\n\t\trange.setEnd( selection.focusNode, selection.focusOffset );\n\n\t\tconst backward = range.collapsed;\n\n\t\trange.detach();\n\n\t\treturn backward;\n\t}\n\n\t/**\n\t * Returns parent {@link module:engine/view/uielement~UIElement} for provided DOM node. Returns `null` if there is no\n\t * parent UIElement.\n\t *\n\t * @param {Node} domNode\n\t * @returns {module:engine/view/uielement~UIElement|null}\n\t */\n\tgetParentUIElement( domNode ) {\n\t\tconst ancestors = getAncestors( domNode );\n\n\t\t// Remove domNode from the list.\n\t\tancestors.pop();\n\n\t\twhile ( ancestors.length ) {\n\t\t\tconst domNode = ancestors.pop();\n\t\t\tconst viewNode = this._domToViewMapping.get( domNode );\n\n\t\t\tif ( viewNode && viewNode.is( 'uiElement' ) ) {\n\t\t\t\treturn viewNode;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Checks if given selection's boundaries are at correct places.\n\t *\n\t * The following places are considered as incorrect for selection boundaries:\n\t * * before or in the middle of the inline filler sequence,\n\t * * inside the DOM element which represents {@link module:engine/view/uielement~UIElement a view ui element}.\n\t *\n\t * @param {Selection} domSelection DOM Selection object to be checked.\n\t * @returns {Boolean} `true` if the given selection is at a correct place, `false` otherwise.\n\t */\n\tisDomSelectionCorrect( domSelection ) {\n\t\treturn this._isDomSelectionPositionCorrect( domSelection.anchorNode, domSelection.anchorOffset ) &&\n\t\t\tthis._isDomSelectionPositionCorrect( domSelection.focusNode, domSelection.focusOffset );\n\t}\n\n\t/**\n\t * Checks if the given DOM position is a correct place for selection boundary. See {@link #isDomSelectionCorrect}.\n\t *\n\t * @private\n\t * @param {Element} domParent Position parent.\n\t * @param {Number} offset Position offset.\n\t * @returns {Boolean} `true` if given position is at a correct place for selection boundary, `false` otherwise.\n\t */\n\t_isDomSelectionPositionCorrect( domParent, offset ) {\n\t\t// If selection is before or in the middle of inline filler string, it is incorrect.\n\t\tif ( isText( domParent ) && startsWithFiller( domParent ) && offset < INLINE_FILLER_LENGTH ) {\n\t\t\t// Selection in a text node, at wrong position (before or in the middle of filler).\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this.isElement( domParent ) && startsWithFiller( domParent.childNodes[ offset ] ) ) {\n\t\t\t// Selection in an element node, before filler text node.\n\t\t\treturn false;\n\t\t}\n\n\t\tconst viewParent = this.mapDomToView( domParent );\n\n\t\t// If selection is in `view.UIElement`, it is incorrect. Note that `mapDomToView()` returns `view.UIElement`\n\t\t// also for any dom element that is inside the view ui element (so we don't need to perform any additional checks).\n\t\tif ( viewParent && viewParent.is( 'uiElement' ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Takes text data from a given {@link module:engine/view/text~Text#data} and processes it so\n\t * it is correctly displayed in the DOM.\n\t *\n\t * Following changes are done:\n\t *\n\t * * a space at the beginning is changed to ` ` if this is the first text node in its container\n\t * element or if a previous text node ends with a space character,\n\t * * space at the end of the text node is changed to ` ` if there are two spaces at the end of a node or if next node\n\t * starts with a space or if it is the last text node in its container,\n\t * * remaining spaces are replaced to a chain of spaces and ` ` (e.g. `'x x'` becomes `'x x'`).\n\t *\n\t * Content of {@link #preElements} is not processed.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} node View text node to process.\n\t * @returns {String} Processed text data.\n\t */\n\t_processDataFromViewText( node ) {\n\t\tlet data = node.data;\n\n\t\t// If any of node ancestors has a name which is in `preElements` array, then currently processed\n\t\t// view text node is (will be) in preformatted element. We should not change whitespaces then.\n\t\tif ( node.getAncestors().some( parent => this.preElements.includes( parent.name ) ) ) {\n\t\t\treturn data;\n\t\t}\n\n\t\t// 1. Replace the first space with a nbsp if the previous node ends with a space or there is no previous node\n\t\t// (container element boundary).\n\t\tif ( data.charAt( 0 ) == ' ' ) {\n\t\t\tconst prevNode = this._getTouchingViewTextNode( node, false );\n\t\t\tconst prevEndsWithSpace = prevNode && this._nodeEndsWithSpace( prevNode );\n\n\t\t\tif ( prevEndsWithSpace || !prevNode ) {\n\t\t\t\tdata = '\\u00A0' + data.substr( 1 );\n\t\t\t}\n\t\t}\n\n\t\t// 2. Replace the last space with nbsp if there are two spaces at the end or if the next node starts with space or there is no\n\t\t// next node (container element boundary).\n\t\t//\n\t\t// Keep in mind that Firefox prefers $nbsp; before tag, not inside it:\n\t\t//\n\t\t// Foo <span> bar</span> <-- bad.\n\t\t// Foo <span> bar</span> <-- good.\n\t\t//\n\t\t// More here: https://github.com/ckeditor/ckeditor5-engine/issues/1747.\n\t\tif ( data.charAt( data.length - 1 ) == ' ' ) {\n\t\t\tconst nextNode = this._getTouchingViewTextNode( node, true );\n\n\t\t\tif ( data.charAt( data.length - 2 ) == ' ' || !nextNode || nextNode.data.charAt( 0 ) == ' ' ) {\n\t\t\t\tdata = data.substr( 0, data.length - 1 ) + '\\u00A0';\n\t\t\t}\n\t\t}\n\n\t\t// 3. Create space+nbsp pairs.\n\t\treturn data.replace( / {2}/g, ' \\u00A0' );\n\t}\n\n\t/**\n\t * Checks whether given node ends with a space character after changing appropriate space characters to ` `s.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} node Node to check.\n\t * @returns {Boolean} `true` if given `node` ends with space, `false` otherwise.\n\t */\n\t_nodeEndsWithSpace( node ) {\n\t\tif ( node.getAncestors().some( parent => this.preElements.includes( parent.name ) ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst data = this._processDataFromViewText( node );\n\n\t\treturn data.charAt( data.length - 1 ) == ' ';\n\t}\n\n\t/**\n\t * Takes text data from native `Text` node and processes it to a correct {@link module:engine/view/text~Text view text node} data.\n\t *\n\t * Following changes are done:\n\t *\n\t * * multiple whitespaces are replaced to a single space,\n\t * * space at the beginning of a text node is removed if it is the first text node in its container\n\t * element or if the previous text node ends with a space character,\n\t * * space at the end of the text node is removed if there are two spaces at the end of a node or if next node\n\t * starts with a space or if it is the last text node in its container\n\t * * nbsps are converted to spaces.\n\t *\n\t * @param {Node} node DOM text node to process.\n\t * @returns {String} Processed data.\n\t * @private\n\t */\n\t_processDataFromDomText( node ) {\n\t\tlet data = node.data;\n\n\t\tif ( _hasDomParentOfType( node, this.preElements ) ) {\n\t\t\treturn getDataWithoutFiller( node );\n\t\t}\n\n\t\t// Change all consecutive whitespace characters (from the [ \\n\\t\\r] set –\n\t\t// see https://github.com/ckeditor/ckeditor5-engine/issues/822#issuecomment-311670249) to a single space character.\n\t\t// That's how multiple whitespaces are treated when rendered, so we normalize those whitespaces.\n\t\t// We're replacing 1+ (and not 2+) to also normalize singular \\n\\t\\r characters (#822).\n\t\tdata = data.replace( /[ \\n\\t\\r]{1,}/g, ' ' );\n\n\t\tconst prevNode = this._getTouchingInlineDomNode( node, false );\n\t\tconst nextNode = this._getTouchingInlineDomNode( node, true );\n\n\t\tconst shouldLeftTrim = this._checkShouldLeftTrimDomText( prevNode );\n\t\tconst shouldRightTrim = this._checkShouldRightTrimDomText( node, nextNode );\n\n\t\t// If the previous dom text node does not exist or it ends by whitespace character, remove space character from the beginning\n\t\t// of this text node. Such space character is treated as a whitespace.\n\t\tif ( shouldLeftTrim ) {\n\t\t\tdata = data.replace( /^ /, '' );\n\t\t}\n\n\t\t// If the next text node does not exist remove space character from the end of this text node.\n\t\tif ( shouldRightTrim ) {\n\t\t\tdata = data.replace( / $/, '' );\n\t\t}\n\n\t\t// At the beginning and end of a block element, Firefox inserts normal space + <br> instead of non-breaking space.\n\t\t// This means that the text node starts/end with normal space instead of non-breaking space.\n\t\t// This causes a problem because the normal space would be removed in `.replace` calls above. To prevent that,\n\t\t// the inline filler is removed only after the data is initially processed (by the `.replace` above). See ckeditor5#692.\n\t\tdata = getDataWithoutFiller( new Text( data ) );\n\n\t\t// At this point we should have removed all whitespaces from DOM text data.\n\t\t//\n\t\t// Now, We will reverse the process that happens in `_processDataFromViewText`.\n\t\t//\n\t\t// We have to change chars, that were in DOM text data because of rendering reasons, to spaces.\n\t\t// First, change all ` \\u00A0` pairs (space + ) to two spaces. DOM converter changes two spaces from model/view to\n\t\t// ` \\u00A0` to ensure proper rendering. Since here we convert back, we recognize those pairs and change them back to ` `.\n\t\tdata = data.replace( / \\u00A0/g, ' ' );\n\n\t\t// Then, let's change the last nbsp to a space.\n\t\tif ( /( |\\u00A0)\\u00A0$/.test( data ) || !nextNode || ( nextNode.data && nextNode.data.charAt( 0 ) == ' ' ) ) {\n\t\t\tdata = data.replace( /\\u00A0$/, ' ' );\n\t\t}\n\n\t\t// Then, change character that is at the beginning of the text node to space character.\n\t\t// We do that replacement only if this is the first node or the previous node ends on whitespace character.\n\t\tif ( shouldLeftTrim ) {\n\t\t\tdata = data.replace( /^\\u00A0/, ' ' );\n\t\t}\n\n\t\t// At this point, all whitespaces should be removed and all created for rendering reasons should be\n\t\t// changed to normal space. All left are inserted intentionally.\n\t\treturn data;\n\t}\n\n\t/**\n\t * Helper function which checks if a DOM text node, preceded by the given `prevNode` should\n\t * be trimmed from the left side.\n\t *\n\t * @param {Node} prevNode\n\t */\n\t_checkShouldLeftTrimDomText( prevNode ) {\n\t\tif ( !prevNode ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ( isElement( prevNode ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn /[^\\S\\u00A0]/.test( prevNode.data.charAt( prevNode.data.length - 1 ) );\n\t}\n\n\t/**\n\t * Helper function which checks if a DOM text node, succeeded by the given `nextNode` should\n\t * be trimmed from the right side.\n\t *\n\t * @param {Node} node\n\t * @param {Node} nextNode\n\t */\n\t_checkShouldRightTrimDomText( node, nextNode ) {\n\t\tif ( nextNode ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !startsWithFiller( node );\n\t}\n\n\t/**\n\t * Helper function. For given {@link module:engine/view/text~Text view text node}, it finds previous or next sibling\n\t * that is contained in the same container element. If there is no such sibling, `null` is returned.\n\t *\n\t * @param {module:engine/view/text~Text} node Reference node.\n\t * @param {Boolean} getNext\n\t * @returns {module:engine/view/text~Text|null} Touching text node or `null` if there is no next or previous touching text node.\n\t */\n\t_getTouchingViewTextNode( node, getNext ) {\n\t\tconst treeWalker = new ViewTreeWalker( {\n\t\t\tstartPosition: getNext ? ViewPosition._createAfter( node ) : ViewPosition._createBefore( node ),\n\t\t\tdirection: getNext ? 'forward' : 'backward'\n\t\t} );\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\t// ViewContainerElement is found on a way to next ViewText node, so given `node` was first/last\n\t\t\t// text node in its container element.\n\t\t\tif ( value.item.is( 'containerElement' ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// <br> found – it works like a block boundary, so do not scan further.\n\t\t\telse if ( value.item.is( 'br' ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// Found a text node in the same container element.\n\t\t\telse if ( value.item.is( 'textProxy' ) ) {\n\t\t\t\treturn value.item;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Helper function. For the given text node, it finds the closest touching node which is either\n\t * a text node or a `<br>`. The search is terminated at block element boundaries and if a matching node\n\t * wasn't found so far, `null` is returned.\n\t *\n\t * In the following DOM structure:\n\t *\n\t *\t\t<p>foo<b>bar</b><br>bom</p>\n\t *\n\t * * `foo` doesn't have its previous touching inline node (`null` is returned),\n\t * * `foo`'s next touching inline node is `bar`\n\t * * `bar`'s next touching inline node is `<br>`\n\t *\n\t * This method returns text nodes and `<br>` elements because these types of nodes affect how\n\t * spaces in the given text node need to be converted.\n\t *\n\t * @private\n\t * @param {Text} node\n\t * @param {Boolean} getNext\n\t * @returns {Text|Element|null}\n\t */\n\t_getTouchingInlineDomNode( node, getNext ) {\n\t\tif ( !node.parentNode ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst direction = getNext ? 'nextNode' : 'previousNode';\n\t\tconst document = node.ownerDocument;\n\t\tconst topmostParent = getAncestors( node )[ 0 ];\n\n\t\tconst treeWalker = document.createTreeWalker( topmostParent, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, {\n\t\t\tacceptNode( node ) {\n\t\t\t\tif ( isText( node ) ) {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\n\t\t\t\tif ( node.tagName == 'BR' ) {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\n\t\t\t\treturn NodeFilter.FILTER_SKIP;\n\t\t\t}\n\t\t} );\n\n\t\ttreeWalker.currentNode = node;\n\n\t\tconst touchingNode = treeWalker[ direction ]();\n\n\t\tif ( touchingNode !== null ) {\n\t\t\tconst lca = getCommonAncestor( node, touchingNode );\n\n\t\t\t// If there is common ancestor between the text node and next/prev text node,\n\t\t\t// and there are no block elements on a way from the text node to that ancestor,\n\t\t\t// and there are no block elements on a way from next/prev text node to that ancestor...\n\t\t\tif (\n\t\t\t\tlca &&\n\t\t\t\t!_hasDomParentOfType( node, this.blockElements, lca ) &&\n\t\t\t\t!_hasDomParentOfType( touchingNode, this.blockElements, lca )\n\t\t\t) {\n\t\t\t\t// Then they are in the same container element.\n\t\t\t\treturn touchingNode;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\n// Helper function.\n// Used to check if given native `Element` or `Text` node has parent with tag name from `types` array.\n//\n// @param {Node} node\n// @param {Array.<String>} types\n// @param {Boolean} [boundaryParent] Can be given if parents should be checked up to a given element (excluding that element).\n// @returns {Boolean} `true` if such parent exists or `false` if it does not.\nfunction _hasDomParentOfType( node, types, boundaryParent ) {\n\tlet parents = getAncestors( node );\n\n\tif ( boundaryParent ) {\n\t\tparents = parents.slice( parents.indexOf( boundaryParent ) + 1 );\n\t}\n\n\treturn parents.some( parent => parent.tagName && types.includes( parent.tagName.toLowerCase() ) );\n}\n\n// A helper that executes given callback for each DOM node's ancestor, starting from the given node\n// and ending in document#documentElement.\n//\n// @param {Node} node\n// @param {Function} callback A callback to be executed for each ancestor.\nfunction forEachDomNodeAncestor( node, callback ) {\n\twhile ( node && node != global.document ) {\n\t\tcallback( node );\n\t\tnode = node.parentNode;\n\t}\n}\n\n// Checks if given node is a nbsp block filler.\n//\n// A is a block filler only if it is a single child of a block element.\n//\n// @param {Node} domNode DOM node.\n// @returns {Boolean}\nfunction isNbspBlockFiller( domNode, blockElements ) {\n\tconst isNBSP = isText( domNode ) && domNode.data == '\\u00A0';\n\n\treturn isNBSP && hasBlockParent( domNode, blockElements ) && domNode.parentNode.childNodes.length === 1;\n}\n\n// Checks if domNode has block parent.\n//\n// @param {Node} domNode DOM node.\n// @returns {Boolean}\nfunction hasBlockParent( domNode, blockElements ) {\n\tconst parent = domNode.parentNode;\n\n\treturn parent && parent.tagName && blockElements.includes( parent.tagName.toLowerCase() );\n}\n\n/**\n * Enum representing type of the block filler.\n *\n * Possible values:\n *\n * * `br` - for `<br>` block filler used in editing view,\n * * `nbsp` - for ` ` block fillers used in the data.\n *\n * @typedef {String} module:engine/view/filler~BlockFillerMode\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/getcommonancestor\n */\n\nimport getAncestors from './getancestors';\n\n/**\n * Searches and returns the lowest common ancestor of two given nodes.\n *\n * @param {Node} nodeA First node.\n * @param {Node} nodeB Second node.\n * @returns {Node|DocumentFragment|Document|null} Lowest common ancestor of both nodes or `null` if nodes do not have a common ancestor.\n */\nexport default function getCommonAncestor( nodeA, nodeB ) {\n\tconst ancestorsA = getAncestors( nodeA );\n\tconst ancestorsB = getAncestors( nodeB );\n\n\tlet i = 0;\n\n\t// It does not matter which array is shorter.\n\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\ti++;\n\t}\n\n\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/iswindow\n */\n\n/**\n * Checks if the object is a native DOM Window.\n *\n * @param {*} obj\n * @returns {Boolean}\n */\nexport default function isWindow( obj ) {\n\tconst stringifiedObject = Object.prototype.toString.apply( obj );\n\n\t// Returns `true` for the `window` object in browser environments.\n\tif ( stringifiedObject == '[object Window]' ) {\n\t\treturn true;\n\t}\n\n\t// Returns `true` for the `window` object in the Electron environment.\n\tif ( stringifiedObject == '[object global]' ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/emittermixin\n */\n\nimport { default as EmitterMixin, _getEmitterListenedTo, _setEmitterId } from '../emittermixin';\nimport uid from '../uid';\nimport isNode from './isnode';\nimport isWindow from './iswindow';\nimport { extend } from 'lodash-es';\n\n/**\n * Mixin that injects the DOM events API into its host. It provides the API\n * compatible with {@link module:utils/emittermixin~EmitterMixin}.\n *\n * DOM emitter mixin is by default available in the {@link module:ui/view~View} class,\n * but it can also be mixed into any other class:\n *\n *\t\timport mix from '../utils/mix.js';\n *\t\timport DomEmitterMixin from '../utils/dom/emittermixin.js';\n *\n *\t\tclass SomeView {}\n *\t\tmix( SomeView, DomEmitterMixin );\n *\n *\t\tconst view = new SomeView();\n *\t\tview.listenTo( domElement, ( evt, domEvt ) => {\n *\t\t\tconsole.log( evt, domEvt );\n *\t\t} );\n *\n * @mixin EmitterMixin\n * @mixes module:utils/emittermixin~EmitterMixin\n * @implements module:utils/dom/emittermixin~Emitter\n */\nconst DomEmitterMixin = extend( {}, EmitterMixin, {\n\t/**\n\t * Registers a callback function to be executed when an event is fired in a specific Emitter or DOM Node.\n\t * It is backwards compatible with {@link module:utils/emittermixin~EmitterMixin#listenTo}.\n\t *\n\t * @param {module:utils/emittermixin~Emitter|Node} emitter The object that fires the event.\n\t * @param {String} event The name of the event.\n\t * @param {Function} callback The function to be called on event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n\t * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n\t * order they were added.\n\t * @param {Boolean} [options.useCapture=false] Indicates that events of this type will be dispatched to the registered\n\t * listener before being dispatched to any EventTarget beneath it in the DOM tree.\n\t */\n\tlistenTo( emitter, ...rest ) {\n\t\t// Check if emitter is an instance of DOM Node. If so, replace the argument with\n\t\t// corresponding ProxyEmitter (or create one if not existing).\n\t\tif ( isNode( emitter ) || isWindow( emitter ) ) {\n\t\t\tconst proxy = this._getProxyEmitter( emitter ) || new ProxyEmitter( emitter );\n\n\t\t\tproxy.attach( ...rest );\n\n\t\t\temitter = proxy;\n\t\t}\n\n\t\t// Execute parent class method with Emitter (or ProxyEmitter) instance.\n\t\tEmitterMixin.listenTo.call( this, emitter, ...rest );\n\t},\n\n\t/**\n\t * Stops listening for events. It can be used at different levels:\n\t * It is backwards compatible with {@link module:utils/emittermixin~EmitterMixin#listenTo}.\n\t *\n\t * * To stop listening to a specific callback.\n\t * * To stop listening to a specific event.\n\t * * To stop listening to all events fired by a specific object.\n\t * * To stop listening to all events fired by all object.\n\t *\n\t * @param {module:utils/emittermixin~Emitter|Node} [emitter] The object to stop listening to. If omitted, stops it for all objects.\n\t * @param {String} [event] (Requires the `emitter`) The name of the event to stop listening to. If omitted, stops it\n\t * for all events from `emitter`.\n\t * @param {Function} [callback] (Requires the `event`) The function to be removed from the call list for the given\n\t * `event`.\n\t */\n\tstopListening( emitter, event, callback ) {\n\t\t// Check if emitter is an instance of DOM Node. If so, replace the argument with corresponding ProxyEmitter.\n\t\tif ( isNode( emitter ) || isWindow( emitter ) ) {\n\t\t\tconst proxy = this._getProxyEmitter( emitter );\n\n\t\t\t// Element has no listeners.\n\t\t\tif ( !proxy ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\temitter = proxy;\n\t\t}\n\n\t\t// Execute parent class method with Emitter (or ProxyEmitter) instance.\n\t\tEmitterMixin.stopListening.call( this, emitter, event, callback );\n\n\t\tif ( emitter instanceof ProxyEmitter ) {\n\t\t\temitter.detach( event );\n\t\t}\n\t},\n\n\t/**\n\t * Retrieves ProxyEmitter instance for given DOM Node residing in this Host.\n\t *\n\t * @private\n\t * @param {Node} node DOM Node of the ProxyEmitter.\n\t * @returns {module:utils/dom/emittermixin~ProxyEmitter} ProxyEmitter instance or null.\n\t */\n\t_getProxyEmitter( node ) {\n\t\treturn _getEmitterListenedTo( this, getNodeUID( node ) );\n\t}\n} );\n\nexport default DomEmitterMixin;\n\n/**\n * Creates a ProxyEmitter instance. Such an instance is a bridge between a DOM Node firing events\n * and any Host listening to them. It is backwards compatible with {@link module:utils/emittermixin~EmitterMixin#on}.\n *\n * listenTo( click, ... )\n * +-----------------------------------------+\n * | stopListening( ... ) |\n * +----------------------------+ | addEventListener( click, ... )\n * | Host | | +---------------------------------------------+\n * +----------------------------+ | | removeEventListener( click, ... ) |\n * | _listeningTo: { | +----------v-------------+ |\n * | UID: { | | ProxyEmitter | |\n * | emitter: ProxyEmitter, | +------------------------+ +------------v----------+\n * | callbacks: { | | events: { | | Node (HTMLElement) |\n * | click: [ callbacks ] | | click: [ callbacks ] | +-----------------------+\n * | } | | }, | | data-ck-expando: UID |\n * | } | | _domNode: Node, | +-----------------------+\n * | } | | _domListeners: {}, | |\n * | +------------------------+ | | _emitterId: UID | |\n * | | DomEmitterMixin | | +--------------^---------+ |\n * | +------------------------+ | | | |\n * +--------------^-------------+ | +---------------------------------------------+\n * | | click (DOM Event)\n * +-----------------------------------------+\n * fire( click, DOM Event )\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n * @implements module:utils/dom/emittermixin~Emitter\n * @private\n */\nclass ProxyEmitter {\n\t/**\n\t * @param {Node} node DOM Node that fires events.\n\t * @returns {Object} ProxyEmitter instance bound to the DOM Node.\n\t */\n\tconstructor( node ) {\n\t\t// Set emitter ID to match DOM Node \"expando\" property.\n\t\t_setEmitterId( this, getNodeUID( node ) );\n\n\t\t// Remember the DOM Node this ProxyEmitter is bound to.\n\t\tthis._domNode = node;\n\t}\n}\n\nextend( ProxyEmitter.prototype, EmitterMixin, {\n\t/**\n\t * Collection of native DOM listeners.\n\t *\n\t * @private\n\t * @member {Object} module:utils/dom/emittermixin~ProxyEmitter#_domListeners\n\t */\n\n\t/**\n\t * Registers a callback function to be executed when an event is fired.\n\t *\n\t * It attaches a native DOM listener to the DOM Node. When fired,\n\t * a corresponding Emitter event will also fire with DOM Event object as an argument.\n\t *\n\t * @method module:utils/dom/emittermixin~ProxyEmitter#attach\n\t * @param {String} event The name of the event.\n\t * @param {Function} callback The function to be called on event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {Boolean} [options.useCapture=false] Indicates that events of this type will be dispatched to the registered\n\t * listener before being dispatched to any EventTarget beneath it in the DOM tree.\n\t */\n\tattach( event, callback, options = {} ) {\n\t\t// If the DOM Listener for given event already exist it is pointless\n\t\t// to attach another one.\n\t\tif ( this._domListeners && this._domListeners[ event ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst domListener = this._createDomListener( event, !!options.useCapture );\n\n\t\t// Attach the native DOM listener to DOM Node.\n\t\tthis._domNode.addEventListener( event, domListener, !!options.useCapture );\n\n\t\tif ( !this._domListeners ) {\n\t\t\tthis._domListeners = {};\n\t\t}\n\n\t\t// Store the native DOM listener in this ProxyEmitter. It will be helpful\n\t\t// when stopping listening to the event.\n\t\tthis._domListeners[ event ] = domListener;\n\t},\n\n\t/**\n\t * Stops executing the callback on the given event.\n\t *\n\t * @method module:utils/dom/emittermixin~ProxyEmitter#detach\n\t * @param {String} event The name of the event.\n\t */\n\tdetach( event ) {\n\t\tlet events;\n\n\t\t// Remove native DOM listeners which are orphans. If no callbacks\n\t\t// are awaiting given event, detach native DOM listener from DOM Node.\n\t\t// See: {@link attach}.\n\n\t\tif ( this._domListeners[ event ] && ( !( events = this._events[ event ] ) || !events.callbacks.length ) ) {\n\t\t\tthis._domListeners[ event ].removeListener();\n\t\t}\n\t},\n\n\t/**\n\t * Creates a native DOM listener callback. When the native DOM event\n\t * is fired it will fire corresponding event on this ProxyEmitter.\n\t * Note: A native DOM Event is passed as an argument.\n\t *\n\t * @private\n\t * @method module:utils/dom/emittermixin~ProxyEmitter#_createDomListener\n\t * @param {String} event The name of the event.\n\t * @param {Boolean} useCapture Indicates whether the listener was created for capturing event.\n\t * @returns {Function} The DOM listener callback.\n\t */\n\t_createDomListener( event, useCapture ) {\n\t\tconst domListener = domEvt => {\n\t\t\tthis.fire( event, domEvt );\n\t\t};\n\n\t\t// Supply the DOM listener callback with a function that will help\n\t\t// detach it from the DOM Node, when it is no longer necessary.\n\t\t// See: {@link detach}.\n\t\tdomListener.removeListener = () => {\n\t\t\tthis._domNode.removeEventListener( event, domListener, useCapture );\n\t\t\tdelete this._domListeners[ event ];\n\t\t};\n\n\t\treturn domListener;\n\t}\n} );\n\n// Gets an unique DOM Node identifier. The identifier will be set if not defined.\n//\n// @private\n// @param {Node} node\n// @returns {String} UID for given DOM Node.\nfunction getNodeUID( node ) {\n\treturn node[ 'data-ck-expando' ] || ( node[ 'data-ck-expando' ] = uid() );\n}\n\n/**\n * Interface representing classes which mix in {@link module:utils/dom/emittermixin~EmitterMixin}.\n *\n * @interface Emitter\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/observer/observer\n */\n\nimport DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Abstract base observer class. Observers are classes which listen to DOM events, do the preliminary\n * processing and fire events on the {@link module:engine/view/document~Document} objects.\n * Observers can also add features to the view, for instance by updating its status or marking elements\n * which need refresh on DOM events.\n *\n * @abstract\n */\nexport default class Observer {\n\t/**\n\t * Creates an instance of the observer.\n\t *\n\t * @param {module:engine/view/view~View} view\n\t */\n\tconstructor( view ) {\n\t\t/**\n\t\t * Instance of the view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/view~View}\n\t\t */\n\t\tthis.view = view;\n\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/document~Document} object.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = view.document;\n\n\t\t/**\n\t\t * State of the observer. If it is disabled events will not be fired.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.isEnabled = false;\n\t}\n\n\t/**\n\t * Enables the observer. This method is called when the observer is registered to the\n\t * {@link module:engine/view/view~View} and after {@link module:engine/view/view~View#forceRender rendering}\n\t * (all observers are {@link #disable disabled} before rendering).\n\t *\n\t * A typical use case for disabling observers is that mutation observers need to be disabled for the rendering.\n\t * However, a child class may not need to be disabled, so it can implement an empty method.\n\t *\n\t * @see module:engine/view/observer/observer~Observer#disable\n\t */\n\tenable() {\n\t\tthis.isEnabled = true;\n\t}\n\n\t/**\n\t * Disables the observer. This method is called before\n\t * {@link module:engine/view/view~View#forceRender rendering} to prevent firing events during rendering.\n\t *\n\t * @see module:engine/view/observer/observer~Observer#enable\n\t */\n\tdisable() {\n\t\tthis.isEnabled = false;\n\t}\n\n\t/**\n\t * Disables and destroys the observer, among others removes event listeners created by the observer.\n\t */\n\tdestroy() {\n\t\tthis.disable();\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Starts observing the given root element.\n\t *\n\t * @method #observe\n\t * @param {HTMLElement} domElement\n\t * @param {String} name The name of the root element.\n\t */\n}\n\nmix( Observer, DomEmitterMixin );\n","/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\nexport default setCacheAdd;\n","/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\nexport default setCacheHas;\n","import MapCache from './_MapCache.js';\nimport setCacheAdd from './_setCacheAdd.js';\nimport setCacheHas from './_setCacheHas.js';\n\n/**\n *\n * Creates an array cache object to store unique values.\n *\n * @private\n * @constructor\n * @param {Array} [values] The values to cache.\n */\nfunction SetCache(values) {\n var index = -1,\n length = values == null ? 0 : values.length;\n\n this.__data__ = new MapCache;\n while (++index < length) {\n this.add(values[index]);\n }\n}\n\n// Add methods to `SetCache`.\nSetCache.prototype.add = SetCache.prototype.push = setCacheAdd;\nSetCache.prototype.has = setCacheHas;\n\nexport default SetCache;\n","/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n * else `false`.\n */\nfunction arraySome(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (predicate(array[index], index, array)) {\n return true;\n }\n }\n return false;\n}\n\nexport default arraySome;\n","/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\nexport default cacheHas;\n","import SetCache from './_SetCache.js';\nimport arraySome from './_arraySome.js';\nimport cacheHas from './_cacheHas.js';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n COMPARE_UNORDERED_FLAG = 2;\n\n/**\n * A specialized version of `baseIsEqualDeep` for arrays with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Array} array The array to compare.\n * @param {Array} other The other array to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `array` and `other` objects.\n * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.\n */\nfunction equalArrays(array, other, bitmask, customizer, equalFunc, stack) {\n var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n arrLength = array.length,\n othLength = other.length;\n\n if (arrLength != othLength && !(isPartial && othLength > arrLength)) {\n return false;\n }\n // Assume cyclic values are equal.\n var stacked = stack.get(array);\n if (stacked && stack.get(other)) {\n return stacked == other;\n }\n var index = -1,\n result = true,\n seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;\n\n stack.set(array, other);\n stack.set(other, array);\n\n // Ignore non-index properties.\n while (++index < arrLength) {\n var arrValue = array[index],\n othValue = other[index];\n\n if (customizer) {\n var compared = isPartial\n ? customizer(othValue, arrValue, index, other, array, stack)\n : customizer(arrValue, othValue, index, array, other, stack);\n }\n if (compared !== undefined) {\n if (compared) {\n continue;\n }\n result = false;\n break;\n }\n // Recursively compare arrays (susceptible to call stack limits).\n if (seen) {\n if (!arraySome(other, function(othValue, othIndex) {\n if (!cacheHas(seen, othIndex) &&\n (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {\n return seen.push(othIndex);\n }\n })) {\n result = false;\n break;\n }\n } else if (!(\n arrValue === othValue ||\n equalFunc(arrValue, othValue, bitmask, customizer, stack)\n )) {\n result = false;\n break;\n }\n }\n stack['delete'](array);\n stack['delete'](other);\n return result;\n}\n\nexport default equalArrays;\n","/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1,\n result = Array(map.size);\n\n map.forEach(function(value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n\nexport default mapToArray;\n","/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\nexport default setToArray;\n","import Symbol from './_Symbol.js';\nimport Uint8Array from './_Uint8Array.js';\nimport eq from './eq.js';\nimport equalArrays from './_equalArrays.js';\nimport mapToArray from './_mapToArray.js';\nimport setToArray from './_setToArray.js';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n COMPARE_UNORDERED_FLAG = 2;\n\n/** `Object#toString` result references. */\nvar boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]';\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * A specialized version of `baseIsEqualDeep` for comparing objects of\n * the same `toStringTag`.\n *\n * **Note:** This function only supports comparing values with tags of\n * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {string} tag The `toStringTag` of the objects to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {\n switch (tag) {\n case dataViewTag:\n if ((object.byteLength != other.byteLength) ||\n (object.byteOffset != other.byteOffset)) {\n return false;\n }\n object = object.buffer;\n other = other.buffer;\n\n case arrayBufferTag:\n if ((object.byteLength != other.byteLength) ||\n !equalFunc(new Uint8Array(object), new Uint8Array(other))) {\n return false;\n }\n return true;\n\n case boolTag:\n case dateTag:\n case numberTag:\n // Coerce booleans to `1` or `0` and dates to milliseconds.\n // Invalid dates are coerced to `NaN`.\n return eq(+object, +other);\n\n case errorTag:\n return object.name == other.name && object.message == other.message;\n\n case regexpTag:\n case stringTag:\n // Coerce regexes to strings and treat strings, primitives and objects,\n // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring\n // for more details.\n return object == (other + '');\n\n case mapTag:\n var convert = mapToArray;\n\n case setTag:\n var isPartial = bitmask & COMPARE_PARTIAL_FLAG;\n convert || (convert = setToArray);\n\n if (object.size != other.size && !isPartial) {\n return false;\n }\n // Assume cyclic values are equal.\n var stacked = stack.get(object);\n if (stacked) {\n return stacked == other;\n }\n bitmask |= COMPARE_UNORDERED_FLAG;\n\n // Recursively compare objects (susceptible to call stack limits).\n stack.set(object, other);\n var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);\n stack['delete'](object);\n return result;\n\n case symbolTag:\n if (symbolValueOf) {\n return symbolValueOf.call(object) == symbolValueOf.call(other);\n }\n }\n return false;\n}\n\nexport default equalByTag;\n","import getAllKeys from './_getAllKeys.js';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1;\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * A specialized version of `baseIsEqualDeep` for objects with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction equalObjects(object, other, bitmask, customizer, equalFunc, stack) {\n var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n objProps = getAllKeys(object),\n objLength = objProps.length,\n othProps = getAllKeys(other),\n othLength = othProps.length;\n\n if (objLength != othLength && !isPartial) {\n return false;\n }\n var index = objLength;\n while (index--) {\n var key = objProps[index];\n if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {\n return false;\n }\n }\n // Assume cyclic values are equal.\n var stacked = stack.get(object);\n if (stacked && stack.get(other)) {\n return stacked == other;\n }\n var result = true;\n stack.set(object, other);\n stack.set(other, object);\n\n var skipCtor = isPartial;\n while (++index < objLength) {\n key = objProps[index];\n var objValue = object[key],\n othValue = other[key];\n\n if (customizer) {\n var compared = isPartial\n ? customizer(othValue, objValue, key, other, object, stack)\n : customizer(objValue, othValue, key, object, other, stack);\n }\n // Recursively compare objects (susceptible to call stack limits).\n if (!(compared === undefined\n ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))\n : compared\n )) {\n result = false;\n break;\n }\n skipCtor || (skipCtor = key == 'constructor');\n }\n if (result && !skipCtor) {\n var objCtor = object.constructor,\n othCtor = other.constructor;\n\n // Non `Object` object instances with different constructors are not equal.\n if (objCtor != othCtor &&\n ('constructor' in object && 'constructor' in other) &&\n !(typeof objCtor == 'function' && objCtor instanceof objCtor &&\n typeof othCtor == 'function' && othCtor instanceof othCtor)) {\n result = false;\n }\n }\n stack['delete'](object);\n stack['delete'](other);\n return result;\n}\n\nexport default equalObjects;\n","import Stack from './_Stack.js';\nimport equalArrays from './_equalArrays.js';\nimport equalByTag from './_equalByTag.js';\nimport equalObjects from './_equalObjects.js';\nimport getTag from './_getTag.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isTypedArray from './isTypedArray.js';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n objectTag = '[object Object]';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * A specialized version of `baseIsEqual` for arrays and objects which performs\n * deep comparisons and tracks traversed objects enabling objects with circular\n * references to be compared.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} [stack] Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {\n var objIsArr = isArray(object),\n othIsArr = isArray(other),\n objTag = objIsArr ? arrayTag : getTag(object),\n othTag = othIsArr ? arrayTag : getTag(other);\n\n objTag = objTag == argsTag ? objectTag : objTag;\n othTag = othTag == argsTag ? objectTag : othTag;\n\n var objIsObj = objTag == objectTag,\n othIsObj = othTag == objectTag,\n isSameTag = objTag == othTag;\n\n if (isSameTag && isBuffer(object)) {\n if (!isBuffer(other)) {\n return false;\n }\n objIsArr = true;\n objIsObj = false;\n }\n if (isSameTag && !objIsObj) {\n stack || (stack = new Stack);\n return (objIsArr || isTypedArray(object))\n ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)\n : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);\n }\n if (!(bitmask & COMPARE_PARTIAL_FLAG)) {\n var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),\n othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');\n\n if (objIsWrapped || othIsWrapped) {\n var objUnwrapped = objIsWrapped ? object.value() : object,\n othUnwrapped = othIsWrapped ? other.value() : other;\n\n stack || (stack = new Stack);\n return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);\n }\n }\n if (!isSameTag) {\n return false;\n }\n stack || (stack = new Stack);\n return equalObjects(object, other, bitmask, customizer, equalFunc, stack);\n}\n\nexport default baseIsEqualDeep;\n","import baseIsEqualDeep from './_baseIsEqualDeep.js';\nimport isObjectLike from './isObjectLike.js';\n\n/**\n * The base implementation of `_.isEqual` which supports partial comparisons\n * and tracks traversed objects.\n *\n * @private\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @param {boolean} bitmask The bitmask flags.\n * 1 - Unordered comparison\n * 2 - Partial comparison\n * @param {Function} [customizer] The function to customize comparisons.\n * @param {Object} [stack] Tracks traversed `value` and `other` objects.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n */\nfunction baseIsEqual(value, other, bitmask, customizer, stack) {\n if (value === other) {\n return true;\n }\n if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {\n return value !== value && other !== other;\n }\n return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);\n}\n\nexport default baseIsEqual;\n","import baseIsEqual from './_baseIsEqual.js';\n\n/**\n * This method is like `_.isEqual` except that it accepts `customizer` which\n * is invoked to compare values. If `customizer` returns `undefined`, comparisons\n * are handled by the method instead. The `customizer` is invoked with up to\n * six arguments: (objValue, othValue [, index|key, object, other, stack]).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @param {Function} [customizer] The function to customize comparisons.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * function isGreeting(value) {\n * return /^h(?:i|ello)$/.test(value);\n * }\n *\n * function customizer(objValue, othValue) {\n * if (isGreeting(objValue) && isGreeting(othValue)) {\n * return true;\n * }\n * }\n *\n * var array = ['hello', 'goodbye'];\n * var other = ['hi', 'goodbye'];\n *\n * _.isEqualWith(array, other, customizer);\n * // => true\n */\nfunction isEqualWith(value, other, customizer) {\n customizer = typeof customizer == 'function' ? customizer : undefined;\n var result = customizer ? customizer(value, other) : undefined;\n return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;\n}\n\nexport default isEqualWith;\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/observer/mutationobserver\n */\n\n/* globals window */\n\nimport Observer from './observer';\nimport ViewSelection from '../selection';\nimport { startsWithFiller, getDataWithoutFiller } from '../filler';\nimport { isEqualWith } from 'lodash-es';\n\n/**\n * Mutation observer class observes changes in the DOM, fires {@link module:engine/view/document~Document#event:mutations} event, mark view\n * elements as changed and call {@link module:engine/view/renderer~Renderer#render}.\n * Because all mutated nodes are marked as \"to be rendered\" and the\n * {@link module:engine/view/renderer~Renderer#render} is called, all changes will be reverted, unless the mutation will be handled by the\n * {@link module:engine/view/document~Document#event:mutations} event listener. It means user will see only handled changes, and the editor\n * will block all changes which are not handled.\n *\n * Mutation Observer also take care of reducing number of mutations which are fired. It removes duplicates and\n * mutations on elements which do not have corresponding view elements. Also\n * {@link module:engine/view/observer/mutationobserver~MutatedText text mutation} is fired only if parent element do not change child list.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class MutationObserver extends Observer {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\t/**\n\t\t * Native mutation observer config.\n\t\t *\n\t\t * @private\n\t\t * @member {Object}\n\t\t */\n\t\tthis._config = {\n\t\t\tchildList: true,\n\t\t\tcharacterData: true,\n\t\t\tcharacterDataOldValue: true,\n\t\t\tsubtree: true\n\t\t};\n\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/view~View#domConverter}.\n\t\t *\n\t\t * @member {module:engine/view/domconverter~DomConverter}\n\t\t */\n\t\tthis.domConverter = view.domConverter;\n\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/view~View#_renderer}.\n\t\t *\n\t\t * @member {module:engine/view/renderer~Renderer}\n\t\t */\n\t\tthis.renderer = view._renderer;\n\n\t\t/**\n\t\t * Observed DOM elements.\n\t\t *\n\t\t * @private\n\t\t * @member {Array.<HTMLElement>}\n\t\t */\n\t\tthis._domElements = [];\n\n\t\t/**\n\t\t * Native mutation observer.\n\t\t *\n\t\t * @private\n\t\t * @member {MutationObserver}\n\t\t */\n\t\tthis._mutationObserver = new window.MutationObserver( this._onMutations.bind( this ) );\n\t}\n\n\t/**\n\t * Synchronously fires {@link module:engine/view/document~Document#event:mutations} event with all mutations in record queue.\n\t * At the same time empties the queue so mutations will not be fired twice.\n\t */\n\tflush() {\n\t\tthis._onMutations( this._mutationObserver.takeRecords() );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve( domElement ) {\n\t\tthis._domElements.push( domElement );\n\n\t\tif ( this.isEnabled ) {\n\t\t\tthis._mutationObserver.observe( domElement, this._config );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tenable() {\n\t\tsuper.enable();\n\n\t\tfor ( const domElement of this._domElements ) {\n\t\t\tthis._mutationObserver.observe( domElement, this._config );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdisable() {\n\t\tsuper.disable();\n\n\t\tthis._mutationObserver.disconnect();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis._mutationObserver.disconnect();\n\t}\n\n\t/**\n\t * Handles mutations. Deduplicates, mark view elements to sync, fire event and call render.\n\t *\n\t * @private\n\t * @param {Array.<Object>} domMutations Array of native mutations.\n\t */\n\t_onMutations( domMutations ) {\n\t\t// As a result of this.flush() we can have an empty collection.\n\t\tif ( domMutations.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst domConverter = this.domConverter;\n\n\t\t// Use map and set for deduplication.\n\t\tconst mutatedTexts = new Map();\n\t\tconst mutatedElements = new Set();\n\n\t\t// Handle `childList` mutations first, so we will be able to check if the `characterData` mutation is in the\n\t\t// element with changed structure anyway.\n\t\tfor ( const mutation of domMutations ) {\n\t\t\tif ( mutation.type === 'childList' ) {\n\t\t\t\tconst element = domConverter.mapDomToView( mutation.target );\n\n\t\t\t\t// Do not collect mutations from UIElements.\n\t\t\t\tif ( element && element.is( 'uiElement' ) ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif ( element && !this._isBogusBrMutation( mutation ) ) {\n\t\t\t\t\tmutatedElements.add( element );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Handle `characterData` mutations later, when we have the full list of nodes which changed structure.\n\t\tfor ( const mutation of domMutations ) {\n\t\t\tconst element = domConverter.mapDomToView( mutation.target );\n\n\t\t\t// Do not collect mutations from UIElements.\n\t\t\tif ( element && element.is( 'uiElement' ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( mutation.type === 'characterData' ) {\n\t\t\t\tconst text = domConverter.findCorrespondingViewText( mutation.target );\n\n\t\t\t\tif ( text && !mutatedElements.has( text.parent ) ) {\n\t\t\t\t\t// Use text as a key, for deduplication. If there will be another mutation on the same text element\n\t\t\t\t\t// we will have only one in the map.\n\t\t\t\t\tmutatedTexts.set( text, {\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\toldText: text.data,\n\t\t\t\t\t\tnewText: getDataWithoutFiller( mutation.target ),\n\t\t\t\t\t\tnode: text\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\t// When we added first letter to the text node which had only inline filler, for the DOM it is mutation\n\t\t\t\t// on text, but for the view, where filler text node did not existed, new text node was created, so we\n\t\t\t\t// need to fire 'children' mutation instead of 'text'.\n\t\t\t\telse if ( !text && startsWithFiller( mutation.target ) ) {\n\t\t\t\t\tmutatedElements.add( domConverter.mapDomToView( mutation.target.parentNode ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Now we build the list of mutations to fire and mark elements. We did not do it earlier to avoid marking the\n\t\t// same node multiple times in case of duplication.\n\n\t\t// List of mutations we will fire.\n\t\tconst viewMutations = [];\n\n\t\tfor ( const mutatedText of mutatedTexts.values() ) {\n\t\t\tthis.renderer.markToSync( 'text', mutatedText.node );\n\t\t\tviewMutations.push( mutatedText );\n\t\t}\n\n\t\tfor ( const viewElement of mutatedElements ) {\n\t\t\tconst domElement = domConverter.mapViewToDom( viewElement );\n\t\t\tconst viewChildren = Array.from( viewElement.getChildren() );\n\t\t\tconst newViewChildren = Array.from( domConverter.domChildrenToView( domElement, { withChildren: false } ) );\n\n\t\t\t// It may happen that as a result of many changes (sth was inserted and then removed),\n\t\t\t// both elements haven't really changed. #1031\n\t\t\tif ( !isEqualWith( viewChildren, newViewChildren, sameNodes ) ) {\n\t\t\t\tthis.renderer.markToSync( 'children', viewElement );\n\n\t\t\t\tviewMutations.push( {\n\t\t\t\t\ttype: 'children',\n\t\t\t\t\toldChildren: viewChildren,\n\t\t\t\t\tnewChildren: newViewChildren,\n\t\t\t\t\tnode: viewElement\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\t// Retrieve `domSelection` using `ownerDocument` of one of mutated nodes.\n\t\t// There should not be simultaneous mutation in multiple documents, so it's fine.\n\t\tconst domSelection = domMutations[ 0 ].target.ownerDocument.getSelection();\n\n\t\tlet viewSelection = null;\n\n\t\tif ( domSelection && domSelection.anchorNode ) {\n\t\t\t// If `domSelection` is inside a dom node that is already bound to a view node from view tree, get\n\t\t\t// corresponding selection in the view and pass it together with `viewMutations`. The `viewSelection` may\n\t\t\t// be used by features handling mutations.\n\t\t\t// Only one range is supported.\n\n\t\t\tconst viewSelectionAnchor = domConverter.domPositionToView( domSelection.anchorNode, domSelection.anchorOffset );\n\t\t\tconst viewSelectionFocus = domConverter.domPositionToView( domSelection.focusNode, domSelection.focusOffset );\n\n\t\t\t// Anchor and focus has to be properly mapped to view.\n\t\t\tif ( viewSelectionAnchor && viewSelectionFocus ) {\n\t\t\t\tviewSelection = new ViewSelection( viewSelectionAnchor );\n\t\t\t\tviewSelection.setFocus( viewSelectionFocus );\n\t\t\t}\n\t\t}\n\n\t\t// In case only non-relevant mutations were recorded it skips the event and force render (#5600).\n\t\tif ( viewMutations.length ) {\n\t\t\tthis.document.fire( 'mutations', viewMutations, viewSelection );\n\n\t\t\t// If nothing changes on `mutations` event, at this point we have \"dirty DOM\" (changed) and de-synched\n\t\t\t// view (which has not been changed). In order to \"reset DOM\" we render the view again.\n\t\t\tthis.view.forceRender();\n\t\t}\n\n\t\tfunction sameNodes( child1, child2 ) {\n\t\t\t// First level of comparison (array of children vs array of children) – use the Lodash's default behavior.\n\t\t\tif ( Array.isArray( child1 ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Elements.\n\t\t\tif ( child1 === child2 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// Texts.\n\t\t\telse if ( child1.is( 'text' ) && child2.is( 'text' ) ) {\n\t\t\t\treturn child1.data === child2.data;\n\t\t\t}\n\n\t\t\t// Not matching types.\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Checks if mutation was generated by the browser inserting bogus br on the end of the block element.\n\t * Such mutations are generated while pressing space or performing native spellchecker correction\n\t * on the end of the block element in Firefox browser.\n\t *\n\t * @private\n\t * @param {Object} mutation Native mutation object.\n\t * @returns {Boolean}\n\t */\n\t_isBogusBrMutation( mutation ) {\n\t\tlet addedNode = null;\n\n\t\t// Check if mutation added only one node on the end of its parent.\n\t\tif ( mutation.nextSibling === null && mutation.removedNodes.length === 0 && mutation.addedNodes.length == 1 ) {\n\t\t\taddedNode = this.domConverter.domToView( mutation.addedNodes[ 0 ], {\n\t\t\t\twithChildren: false\n\t\t\t} );\n\t\t}\n\n\t\treturn addedNode && addedNode.is( 'element', 'br' );\n\t}\n}\n\n/**\n * Fired when mutation occurred. If tree view is not changed on this event, DOM will be reverted to the state before\n * mutation, so all changes which should be applied, should be handled on this event.\n *\n * Introduced by {@link module:engine/view/observer/mutationobserver~MutationObserver}.\n *\n * Note that because {@link module:engine/view/observer/mutationobserver~MutationObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/mutationobserver~MutationObserver\n * @event module:engine/view/document~Document#event:mutations\n * @param {Array.<module:engine/view/observer/mutationobserver~MutatedText|module:engine/view/observer/mutationobserver~MutatedChildren>}\n * viewMutations Array of mutations.\n * For mutated texts it will be {@link module:engine/view/observer/mutationobserver~MutatedText} and for mutated elements it will be\n * {@link module:engine/view/observer/mutationobserver~MutatedChildren}. You can recognize the type based on the `type` property.\n * @param {module:engine/view/selection~Selection|null} viewSelection View selection that is a result of converting DOM selection to view.\n * Keep in\n * mind that the DOM selection is already \"updated\", meaning that it already acknowledges changes done in mutation.\n */\n\n/**\n * Mutation item for text.\n *\n * @see module:engine/view/document~Document#event:mutations\n * @see module:engine/view/observer/mutationobserver~MutatedChildren\n *\n * @typedef {Object} module:engine/view/observer/mutationobserver~MutatedText\n *\n * @property {String} type For text mutations it is always 'text'.\n * @property {module:engine/view/text~Text} node Mutated text node.\n * @property {String} oldText Old text.\n * @property {String} newText New text.\n */\n\n/**\n * Mutation item for child nodes.\n *\n * @see module:engine/view/document~Document#event:mutations\n * @see module:engine/view/observer/mutationobserver~MutatedText\n *\n * @typedef {Object} module:engine/view/observer/mutationobserver~MutatedChildren\n *\n * @property {String} type For child nodes mutations it is always 'children'.\n * @property {module:engine/view/element~Element} node Parent of the mutated children.\n * @property {Array.<module:engine/view/node~Node>} oldChildren Old child nodes.\n * @property {Array.<module:engine/view/node~Node>} newChildren New child nodes.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/observer/domeventdata\n */\n\nimport { extend } from 'lodash-es';\n\n/**\n * Information about a DOM event in context of the {@link module:engine/view/document~Document}.\n * It wraps the native event, which usually should not be used as the wrapper contains\n * additional data (like key code for keyboard events).\n */\nexport default class DomEventData {\n\t/**\n\t * @param {module:engine/view/view~View} view The instance of the view controller.\n\t * @param {Event} domEvent The DOM event.\n\t * @param {Object} [additionalData] Additional properties that the instance should contain.\n\t */\n\tconstructor( view, domEvent, additionalData ) {\n\t\t/**\n\t\t * Instance of the view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/view~View} module:engine/view/observer/observer~Observer.DomEvent#view\n\t\t */\n\t\tthis.view = view;\n\n\t\t/**\n\t\t * The instance of the document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document} module:engine/view/observer/observer~Observer.DomEvent#document\n\t\t */\n\t\tthis.document = view.document;\n\n\t\t/**\n\t\t * The DOM event.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Event} module:engine/view/observer/observer~Observer.DomEvent#domEvent\n\t\t */\n\t\tthis.domEvent = domEvent;\n\n\t\t/**\n\t\t * The DOM target.\n\t\t *\n\t\t * @readonly\n\t\t * @member {HTMLElement} module:engine/view/observer/observer~Observer.DomEvent#target\n\t\t */\n\t\tthis.domTarget = domEvent.target;\n\n\t\textend( this, additionalData );\n\t}\n\n\t/**\n\t * The tree view element representing the target.\n\t *\n\t * @readonly\n\t * @type module:engine/view/element~Element\n\t */\n\tget target() {\n\t\treturn this.view.domConverter.mapDomToView( this.domTarget );\n\t}\n\n\t/**\n\t * Prevents the native's event default action.\n\t */\n\tpreventDefault() {\n\t\tthis.domEvent.preventDefault();\n\t}\n\n\t/**\n\t * Stops native event propagation.\n\t */\n\tstopPropagation() {\n\t\tthis.domEvent.stopPropagation();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/observer/domeventobserver\n */\n\nimport Observer from './observer';\nimport DomEventData from './domeventdata';\n\n/**\n * Base class for DOM event observers. This class handles\n * {@link module:engine/view/observer/observer~Observer#observe adding} listeners to DOM elements,\n * {@link module:engine/view/observer/observer~Observer#disable disabling} and\n * {@link module:engine/view/observer/observer~Observer#enable re-enabling} events.\n * Child class needs to define\n * {@link module:engine/view/observer/domeventobserver~DomEventObserver#domEventType DOM event type} and\n * {@link module:engine/view/observer/domeventobserver~DomEventObserver#onDomEvent callback}.\n *\n * For instance:\n *\n *\t\tclass ClickObserver extends DomEventObserver {\n *\t\t\t// It can also be defined as a normal property in the constructor.\n *\t\t\tget domEventType() {\n *\t\t\t\treturn 'click';\n *\t\t\t}\n *\n *\t\t\tonDomEvent( domEvent ) {\n *\t\t\t\tthis.fire( 'click', domEvent );\n *\t\t\t}\n *\t\t}\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class DomEventObserver extends Observer {\n\t/**\n\t * Type of the DOM event the observer should listen on. Array of types can be defined\n\t * if the obsever should listen to multiple DOM events.\n\t *\n\t * @readonly\n\t * @member {String|Array.<String>} #domEventType\n\t */\n\n\t/**\n\t * Callback which should be called when the DOM event occurred. Note that the callback will not be called if\n\t * observer {@link #isEnabled is not enabled}.\n\t *\n\t * @see #domEventType\n\t * @abstract\n\t * @method #onDomEvent\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\t/**\n\t\t * If set to `true` DOM events will be listened on the capturing phase.\n\t\t * Default value is `false`.\n\t\t *\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.useCapture = false;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve( domElement ) {\n\t\tconst types = typeof this.domEventType == 'string' ? [ this.domEventType ] : this.domEventType;\n\n\t\ttypes.forEach( type => {\n\t\t\tthis.listenTo( domElement, type, ( eventInfo, domEvent ) => {\n\t\t\t\tif ( this.isEnabled ) {\n\t\t\t\t\tthis.onDomEvent( domEvent );\n\t\t\t\t}\n\t\t\t}, { useCapture: this.useCapture } );\n\t\t} );\n\t}\n\n\t/**\n\t * Calls `Document#fire()` if observer {@link #isEnabled is enabled}.\n\t *\n\t * @see module:utils/emittermixin~EmitterMixin#fire\n\t * @param {String} eventType The event type (name).\n\t * @param {Event} domEvent The DOM event.\n\t * @param {Object} [additionalData] The additional data which should extend the\n\t * {@link module:engine/view/observer/domeventdata~DomEventData event data} object.\n\t */\n\tfire( eventType, domEvent, additionalData ) {\n\t\tif ( this.isEnabled ) {\n\t\t\tthis.document.fire( eventType, new DomEventData( this.view, domEvent, additionalData ) );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/observer/keyobserver\n */\n\nimport DomEventObserver from './domeventobserver';\nimport { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';\n\n/**\n * Observer for events connected with pressing keyboard keys.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class KeyObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'keydown', 'keyup' ];\n\t}\n\n\tonDomEvent( domEvt ) {\n\t\tthis.fire( domEvt.type, domEvt, {\n\t\t\tkeyCode: domEvt.keyCode,\n\n\t\t\taltKey: domEvt.altKey,\n\t\t\tctrlKey: domEvt.ctrlKey || domEvt.metaKey,\n\t\t\tshiftKey: domEvt.shiftKey,\n\n\t\t\tget keystroke() {\n\t\t\t\treturn getCode( this );\n\t\t\t}\n\t\t} );\n\t}\n}\n\n/**\n * Fired when a key has been pressed.\n *\n * Introduced by {@link module:engine/view/observer/keyobserver~KeyObserver}.\n *\n * Note that because {@link module:engine/view/observer/keyobserver~KeyObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/keyobserver~KeyObserver\n * @event module:engine/view/document~Document#event:keydown\n * @param {module:engine/view/observer/keyobserver~KeyEventData} keyEventData\n */\n\n/**\n * Fired when a key has been released.\n *\n * Introduced by {@link module:engine/view/observer/keyobserver~KeyObserver}.\n *\n * Note that because {@link module:engine/view/observer/keyobserver~KeyObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/keyobserver~KeyObserver\n * @event module:engine/view/document~Document#event:keyup\n * @param {module:engine/view/observer/keyobserver~KeyEventData} keyEventData\n */\n\n/**\n * The value of both events - {@link module:engine/view/document~Document#event:keydown} and\n * {@link module:engine/view/document~Document#event:keyup}.\n *\n * @class module:engine/view/observer/keyobserver~KeyEventData\n * @extends module:engine/view/observer/domeventdata~DomEventData\n * @implements module:utils/keyboard~KeystrokeInfo\n */\n\n/**\n * Code of the whole keystroke. See {@link module:utils/keyboard~getCode}.\n *\n * @readonly\n * @member {Number} module:engine/view/observer/keyobserver~KeyEventData#keystroke\n */\n","import root from './_root.js';\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n * console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n return root.Date.now();\n};\n\nexport default now;\n","import isObject from './isObject.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** Used to match leading and trailing whitespace. */\nvar reTrim = /^\\s+|\\s+$/g;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = value.replace(reTrim, '');\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nexport default toNumber;\n","import isObject from './isObject.js';\nimport now from './now.js';\nimport toNumber from './toNumber.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max,\n nativeMin = Math.min;\n\n/**\n * Creates a debounced function that delays invoking `func` until after `wait`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a `cancel` method to cancel\n * delayed `func` invocations and a `flush` method to immediately invoke them.\n * Provide `options` to indicate whether `func` should be invoked on the\n * leading and/or trailing edge of the `wait` timeout. The `func` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `func`\n * invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.debounce` and `_.throttle`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n * Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n * The maximum time `func` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `sendMail` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n * 'leading': true,\n * 'trailing': false\n * }));\n *\n * // Ensure `batchLog` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n wait = toNumber(wait) || 0;\n if (isObject(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc(time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any `maxWait` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n timeWaiting = wait - timeSinceLastCall;\n\n return maxing\n ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)\n : timeWaiting;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the `maxWait` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have `lastArgs` which means `func` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(now());\n }\n\n function debounced() {\n var time = now(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n clearTimeout(timerId);\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n}\n\nexport default debounce;\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/observer/fakeselectionobserver\n */\n\nimport Observer from './observer';\nimport ViewSelection from '../selection';\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport { debounce } from 'lodash-es';\n\n/**\n * Fake selection observer class. If view selection is fake it is placed in dummy DOM container. This observer listens\n * on {@link module:engine/view/document~Document#event:keydown keydown} events and handles moving fake view selection to the correct place\n * if arrow keys are pressed.\n * Fires {@link module:engine/view/document~Document#event:selectionChange selectionChange event} simulating natural behaviour of\n * {@link module:engine/view/observer/selectionobserver~SelectionObserver SelectionObserver}.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class FakeSelectionObserver extends Observer {\n\t/**\n\t * Creates new FakeSelectionObserver instance.\n\t *\n\t * @param {module:engine/view/view~View} view\n\t */\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\t/**\n\t\t * Fires debounced event `selectionChangeDone`. It uses `lodash#debounce` method to delay function call.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} data Selection change data.\n\t\t * @method #_fireSelectionChangeDoneDebounced\n\t\t */\n\t\tthis._fireSelectionChangeDoneDebounced = debounce( data => this.document.fire( 'selectionChangeDone', data ), 200 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve() {\n\t\tconst document = this.document;\n\n\t\tdocument.on( 'keydown', ( eventInfo, data ) => {\n\t\t\tconst selection = document.selection;\n\n\t\t\tif ( selection.isFake && _isArrowKeyCode( data.keyCode ) && this.isEnabled ) {\n\t\t\t\t// Prevents default key down handling - no selection change will occur.\n\t\t\t\tdata.preventDefault();\n\n\t\t\t\tthis._handleSelectionMove( data.keyCode );\n\t\t\t}\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis._fireSelectionChangeDoneDebounced.cancel();\n\t}\n\n\t/**\n\t * Handles collapsing view selection according to given key code. If left or up key is provided - new selection will be\n\t * collapsed to left. If right or down key is pressed - new selection will be collapsed to right.\n\t *\n\t * This method fires {@link module:engine/view/document~Document#event:selectionChange} and\n\t * {@link module:engine/view/document~Document#event:selectionChangeDone} events imitating behaviour of\n\t * {@link module:engine/view/observer/selectionobserver~SelectionObserver}.\n\t *\n\t * @private\n\t * @param {Number} keyCode\n\t * @fires module:engine/view/document~Document#event:selectionChange\n\t * @fires module:engine/view/document~Document#event:selectionChangeDone\n\t */\n\t_handleSelectionMove( keyCode ) {\n\t\tconst selection = this.document.selection;\n\t\tconst newSelection = new ViewSelection( selection.getRanges(), { backward: selection.isBackward, fake: false } );\n\n\t\t// Left or up arrow pressed - move selection to start.\n\t\tif ( keyCode == keyCodes.arrowleft || keyCode == keyCodes.arrowup ) {\n\t\t\tnewSelection.setTo( newSelection.getFirstPosition() );\n\t\t}\n\n\t\t// Right or down arrow pressed - move selection to end.\n\t\tif ( keyCode == keyCodes.arrowright || keyCode == keyCodes.arrowdown ) {\n\t\t\tnewSelection.setTo( newSelection.getLastPosition() );\n\t\t}\n\n\t\tconst data = {\n\t\t\toldSelection: selection,\n\t\t\tnewSelection,\n\t\t\tdomSelection: null\n\t\t};\n\n\t\t// Fire dummy selection change event.\n\t\tthis.document.fire( 'selectionChange', data );\n\n\t\t// Call` #_fireSelectionChangeDoneDebounced` every time when `selectionChange` event is fired.\n\t\t// This function is debounced what means that `selectionChangeDone` event will be fired only when\n\t\t// defined int the function time will elapse since the last time the function was called.\n\t\t// So `selectionChangeDone` will be fired when selection will stop changing.\n\t\tthis._fireSelectionChangeDoneDebounced( data );\n\t}\n}\n\n// Checks if one of the arrow keys is pressed.\n//\n// @private\n// @param {Number} keyCode\n// @returns {Boolean}\nfunction _isArrowKeyCode( keyCode ) {\n\treturn keyCode == keyCodes.arrowright ||\n\t\tkeyCode == keyCodes.arrowleft ||\n\t\tkeyCode == keyCodes.arrowup ||\n\t\tkeyCode == keyCodes.arrowdown;\n}\n\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/observer/selectionobserver\n */\n\n/* global setInterval, clearInterval */\n\nimport Observer from './observer';\nimport MutationObserver from './mutationobserver';\nimport { debounce } from 'lodash-es';\n\n/**\n * Selection observer class observes selection changes in the document. If selection changes on the document this\n * observer checks if there are any mutations and if DOM selection is different than the\n * {@link module:engine/view/document~Document#selection view selection}. Selection observer fires\n * {@link module:engine/view/document~Document#event:selectionChange} event only if selection change was the only change in the document\n * and DOM selection is different then the view selection.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @see module:engine/view/observer/mutationobserver~MutationObserver\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class SelectionObserver extends Observer {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\t/**\n\t\t * Instance of the mutation observer. Selection observer calls\n\t\t * {@link module:engine/view/observer/mutationobserver~MutationObserver#flush} to ensure that the mutations will be handled\n\t\t * before the {@link module:engine/view/document~Document#event:selectionChange} event is fired.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/observer/mutationobserver~MutationObserver}\n\t\t * module:engine/view/observer/selectionobserver~SelectionObserver#mutationObserver\n\t\t */\n\t\tthis.mutationObserver = view.getObserver( MutationObserver );\n\n\t\t/**\n\t\t * Reference to the view {@link module:engine/view/documentselection~DocumentSelection} object used to compare\n\t\t * new selection with it.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/documentselection~DocumentSelection}\n\t\t * module:engine/view/observer/selectionobserver~SelectionObserver#selection\n\t\t */\n\t\tthis.selection = this.document.selection;\n\n\t\t/* eslint-disable max-len */\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/view~View#domConverter}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/domconverter~DomConverter} module:engine/view/observer/selectionobserver~SelectionObserver#domConverter\n\t\t */\n\t\t/* eslint-enable max-len */\n\t\tthis.domConverter = view.domConverter;\n\n\t\t/**\n\t\t * Set of documents which have added \"selectionchange\" listener to avoid adding listener twice to the same\n\t\t * document.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakSet.<Document>} module:engine/view/observer/selectionobserver~SelectionObserver#_documents\n\t\t */\n\t\tthis._documents = new WeakSet();\n\n\t\t/**\n\t\t * Fires debounced event `selectionChangeDone`. It uses `lodash#debounce` method to delay function call.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} data Selection change data.\n\t\t * @method #_fireSelectionChangeDoneDebounced\n\t\t */\n\t\tthis._fireSelectionChangeDoneDebounced = debounce( data => this.document.fire( 'selectionChangeDone', data ), 200 );\n\n\t\tthis._clearInfiniteLoopInterval = setInterval( () => this._clearInfiniteLoop(), 1000 );\n\n\t\t/**\n\t\t * Private property to check if the code does not enter infinite loop.\n\t\t *\n\t\t * @private\n\t\t * @member {Number} module:engine/view/observer/selectionobserver~SelectionObserver#_loopbackCounter\n\t\t */\n\t\tthis._loopbackCounter = 0;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve( domElement ) {\n\t\tconst domDocument = domElement.ownerDocument;\n\n\t\t// Add listener once per each document.\n\t\tif ( this._documents.has( domDocument ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.listenTo( domDocument, 'selectionchange', () => {\n\t\t\tthis._handleSelectionChange( domDocument );\n\t\t} );\n\n\t\tthis._documents.add( domDocument );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tclearInterval( this._clearInfiniteLoopInterval );\n\t\tthis._fireSelectionChangeDoneDebounced.cancel();\n\t}\n\n\t/**\n\t * Selection change listener. {@link module:engine/view/observer/mutationobserver~MutationObserver#flush Flush} mutations, check if\n\t * selection changes and fires {@link module:engine/view/document~Document#event:selectionChange} event on every change\n\t * and {@link module:engine/view/document~Document#event:selectionChangeDone} when selection stop changing.\n\t *\n\t * @private\n\t * @param {Document} domDocument DOM document.\n\t */\n\t_handleSelectionChange( domDocument ) {\n\t\tif ( !this.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Ensure the mutation event will be before selection event on all browsers.\n\t\tthis.mutationObserver.flush();\n\n\t\t// If there were mutations then the view will be re-rendered by the mutation observer and selection\n\t\t// will be updated, so selections will equal and event will not be fired, as expected.\n\t\tconst domSelection = domDocument.defaultView.getSelection();\n\t\tconst newViewSelection = this.domConverter.domSelectionToView( domSelection );\n\n\t\t// Do not convert selection change if the new view selection has no ranges in it.\n\t\t//\n\t\t// It means that the DOM selection is in some way incorrect. Ranges that were in the DOM selection could not be\n\t\t// converted to the view. This happens when the DOM selection was moved outside of the editable element.\n\t\tif ( newViewSelection.rangeCount == 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this.selection.isEqual( newViewSelection ) && this.domConverter.isDomSelectionCorrect( domSelection ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Ensure we are not in the infinite loop (#400).\n\t\t// This counter is reset each second. 60 selection changes in 1 second is enough high number\n\t\t// to be very difficult (impossible) to achieve using just keyboard keys (during normal editor use).\n\t\tif ( ++this._loopbackCounter > 60 ) {\n\t\t\t// Selection change observer detected an infinite rendering loop.\n\t\t\t// Most probably you try to put the selection in the position which is not allowed\n\t\t\t// by the browser and browser fixes it automatically what causes `selectionchange` event on\n\t\t\t// which a loopback through a model tries to re-render the wrong selection and again.\n\t\t\t//\n\t\t\t// @if CK_DEBUG // console.warn( 'Selection change observer detected an infinite rendering loop.' );\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this.selection.isSimilar( newViewSelection ) ) {\n\t\t\t// If selection was equal and we are at this point of algorithm, it means that it was incorrect.\n\t\t\t// Just re-render it, no need to fire any events, etc.\n\t\t\tthis.view.forceRender();\n\t\t} else {\n\t\t\tconst data = {\n\t\t\t\toldSelection: this.selection,\n\t\t\t\tnewSelection: newViewSelection,\n\t\t\t\tdomSelection\n\t\t\t};\n\n\t\t\t// Prepare data for new selection and fire appropriate events.\n\t\t\tthis.document.fire( 'selectionChange', data );\n\n\t\t\t// Call` #_fireSelectionChangeDoneDebounced` every time when `selectionChange` event is fired.\n\t\t\t// This function is debounced what means that `selectionChangeDone` event will be fired only when\n\t\t\t// defined int the function time will elapse since the last time the function was called.\n\t\t\t// So `selectionChangeDone` will be fired when selection will stop changing.\n\t\t\tthis._fireSelectionChangeDoneDebounced( data );\n\t\t}\n\t}\n\n\t/**\n\t * Clears `SelectionObserver` internal properties connected with preventing infinite loop.\n\t *\n\t * @protected\n\t */\n\t_clearInfiniteLoop() {\n\t\tthis._loopbackCounter = 0;\n\t}\n}\n\n/**\n * Fired when selection has changed. This event is fired only when the selection change was the only change that happened\n * in the document, and old selection is different then the new selection.\n *\n * Introduced by {@link module:engine/view/observer/selectionobserver~SelectionObserver}.\n *\n * Note that because {@link module:engine/view/observer/selectionobserver~SelectionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/selectionobserver~SelectionObserver\n * @event module:engine/view/document~Document#event:selectionChange\n * @param {Object} data\n * @param {module:engine/view/documentselection~DocumentSelection} data.oldSelection Old View selection which is\n * {@link module:engine/view/document~Document#selection}.\n * @param {module:engine/view/selection~Selection} data.newSelection New View selection which is converted DOM selection.\n * @param {Selection} data.domSelection Native DOM selection.\n */\n\n/**\n * Fired when selection stops changing.\n *\n * Introduced by {@link module:engine/view/observer/selectionobserver~SelectionObserver}.\n *\n * Note that because {@link module:engine/view/observer/selectionobserver~SelectionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/selectionobserver~SelectionObserver\n * @event module:engine/view/document~Document#event:selectionChangeDone\n * @param {Object} data\n * @param {module:engine/view/documentselection~DocumentSelection} data.oldSelection Old View selection which is\n * {@link module:engine/view/document~Document#selection}.\n * @param {module:engine/view/selection~Selection} data.newSelection New View selection which is converted DOM selection.\n * @param {Selection} data.domSelection Native DOM selection.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/observer/focusobserver\n */\n\n/* globals setTimeout, clearTimeout */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * {@link module:engine/view/document~Document#event:focus Focus}\n * and {@link module:engine/view/document~Document#event:blur blur} events observer.\n * Focus observer handle also {@link module:engine/view/rooteditableelement~RootEditableElement#isFocused isFocused} property of the\n * {@link module:engine/view/rooteditableelement~RootEditableElement root elements}.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class FocusObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'focus', 'blur' ];\n\t\tthis.useCapture = true;\n\t\tconst document = this.document;\n\n\t\tdocument.on( 'focus', () => {\n\t\t\tdocument.isFocused = true;\n\n\t\t\t// Unfortunately native `selectionchange` event is fired asynchronously.\n\t\t\t// We need to wait until `SelectionObserver` handle the event and then render. Otherwise rendering will\n\t\t\t// overwrite new DOM selection with selection from the view.\n\t\t\t// See https://github.com/ckeditor/ckeditor5-engine/issues/795 for more details.\n\t\t\t// Long timeout is needed to solve #676 and https://github.com/ckeditor/ckeditor5-engine/issues/1157 issues.\n\t\t\tthis._renderTimeoutId = setTimeout( () => view.forceRender(), 50 );\n\t\t} );\n\n\t\tdocument.on( 'blur', ( evt, data ) => {\n\t\t\tconst selectedEditable = document.selection.editableElement;\n\n\t\t\tif ( selectedEditable === null || selectedEditable === data.target ) {\n\t\t\t\tdocument.isFocused = false;\n\n\t\t\t\t// Re-render the document to update view elements.\n\t\t\t\tview.forceRender();\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * Identifier of the timeout currently used by focus listener to delay rendering execution.\n\t\t *\n\t\t * @private\n\t\t * @member {Number} #_renderTimeoutId\n\t\t */\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tif ( this._renderTimeoutId ) {\n\t\t\tclearTimeout( this._renderTimeoutId );\n\t\t}\n\n\t\tsuper.destroy();\n\t}\n}\n\n/**\n * Fired when one of the editables gets focus.\n *\n * Introduced by {@link module:engine/view/observer/focusobserver~FocusObserver}.\n *\n * Note that because {@link module:engine/view/observer/focusobserver~FocusObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/focusobserver~FocusObserver\n * @event module:engine/view/document~Document#event:focus\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when one of the editables loses focus.\n *\n * Introduced by {@link module:engine/view/observer/focusobserver~FocusObserver}.\n *\n * Note that because {@link module:engine/view/observer/focusobserver~FocusObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/focusobserver~FocusObserver\n * @event module:engine/view/document~Document#event:blur\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/observer/compositionobserver\n */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * {@link module:engine/view/document~Document#event:compositionstart Compositionstart},\n * {@link module:engine/view/document~Document#event:compositionupdate compositionupdate} and\n * {@link module:engine/view/document~Document#event:compositionend compositionend} events observer.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class CompositionObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'compositionstart', 'compositionupdate', 'compositionend' ];\n\t\tconst document = this.document;\n\n\t\tdocument.on( 'compositionstart', () => {\n\t\t\tdocument.isComposing = true;\n\t\t} );\n\n\t\tdocument.on( 'compositionend', () => {\n\t\t\tdocument.isComposing = false;\n\t\t} );\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired when composition starts inside one of the editables.\n *\n * Introduced by {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n *\n * Note that because {@link module:engine/view/observer/compositionobserver~CompositionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/compositionobserver~CompositionObserver\n * @event module:engine/view/document~Document#event:compositionstart\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when composition is updated inside one of the editables.\n *\n * Introduced by {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n *\n * Note that because {@link module:engine/view/observer/compositionobserver~CompositionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/compositionobserver~CompositionObserver\n * @event module:engine/view/document~Document#event:compositionupdate\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when composition ends inside one of the editables.\n *\n * Introduced by {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n *\n * Note that because {@link module:engine/view/observer/compositionobserver~CompositionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/compositionobserver~CompositionObserver\n * @event module:engine/view/document~Document#event:compositionend\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module engine/view/observer/inputobserver\n */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * Observer for events connected with data input.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class InputObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'beforeinput' ];\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired before browser inputs (or deletes) some data.\n *\n * This event is available only on browsers which support DOM `beforeinput` event.\n *\n * Introduced by {@link module:engine/view/observer/inputobserver~InputObserver}.\n *\n * Note that because {@link module:engine/view/observer/inputobserver~InputObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/inputobserver~InputObserver\n * @event module:engine/view/document~Document#event:beforeinput\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/isrange\n */\n\n/**\n * Checks if the object is a native DOM Range.\n *\n * @param {*} obj\n * @returns {Boolean}\n */\nexport default function isRange( obj ) {\n\treturn Object.prototype.toString.apply( obj ) == '[object Range]';\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/getborderwidths\n */\n\n/**\n * Returns an object containing CSS border widths of a specified HTML element.\n *\n * @param {HTMLElement} element An element which has CSS borders.\n * @returns {Object} An object containing `top`, `left`, `right` and `bottom` properties\n * with numerical values of the `border-[top,left,right,bottom]-width` CSS styles.\n */\nexport default function getBorderWidths( element ) {\n\t// Call getComputedStyle on the window the element document belongs to.\n\tconst style = element.ownerDocument.defaultView.getComputedStyle( element );\n\n\treturn {\n\t\ttop: parseInt( style.borderTopWidth, 10 ),\n\t\tright: parseInt( style.borderRightWidth, 10 ),\n\t\tbottom: parseInt( style.borderBottomWidth, 10 ),\n\t\tleft: parseInt( style.borderLeftWidth, 10 )\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/rect\n */\n\nimport isRange from './isrange';\nimport isWindow from './iswindow';\nimport getBorderWidths from './getborderwidths';\nimport isText from './istext';\nimport { isElement } from 'lodash-es';\n\nconst rectProperties = [ 'top', 'right', 'bottom', 'left', 'width', 'height' ];\n\n/**\n * A helper class representing a `ClientRect` object, e.g. value returned by\n * the native `object.getBoundingClientRect()` method. Provides a set of methods\n * to manipulate the rect and compare it against other rect instances.\n */\nexport default class Rect {\n\t/**\n\t * Creates an instance of rect.\n\t *\n\t *\t\t// Rect of an HTMLElement.\n\t *\t\tconst rectA = new Rect( document.body );\n\t *\n\t *\t\t// Rect of a DOM Range.\n\t *\t\tconst rectB = new Rect( document.getSelection().getRangeAt( 0 ) );\n\t *\n\t *\t\t// Rect of a window (web browser viewport).\n\t *\t\tconst rectC = new Rect( window );\n\t *\n\t *\t\t// Rect out of an object.\n\t *\t\tconst rectD = new Rect( { top: 0, right: 10, bottom: 10, left: 0, width: 10, height: 10 } );\n\t *\n\t *\t\t// Rect out of another Rect instance.\n\t *\t\tconst rectE = new Rect( rectD );\n\t *\n\t *\t\t// Rect out of a ClientRect.\n\t *\t\tconst rectF = new Rect( document.body.getClientRects().item( 0 ) );\n\t *\n\t * **Note**: By default a rect of an HTML element includes its CSS borders and scrollbars (if any)\n\t * ant the rect of a `window` includes scrollbars too. Use {@link #excludeScrollbarsAndBorders}\n\t * to get the inner part of the rect.\n\t *\n\t * @param {HTMLElement|Range|Window|ClientRect|module:utils/dom/rect~Rect|Object} source A source object to create the rect.\n\t */\n\tconstructor( source ) {\n\t\tconst isSourceRange = isRange( source );\n\n\t\t/**\n\t\t * The object this rect is for.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @member {HTMLElement|Range|ClientRect|module:utils/dom/rect~Rect|Object} #_source\n\t\t */\n\t\tObject.defineProperty( this, '_source', {\n\t\t\t// If the source is a Rect instance, copy it's #_source.\n\t\t\tvalue: source._source || source,\n\t\t\twritable: true,\n\t\t\tenumerable: false\n\t\t} );\n\n\t\tif ( isElement( source ) || isSourceRange ) {\n\t\t\t// The `Rect` class depends on `getBoundingClientRect` and `getClientRects` DOM methods. If the source\n\t\t\t// of a rect in an HTML element or a DOM range but it does not belong to any rendered DOM tree, these methods\n\t\t\t// will fail to obtain the geometry and the rect instance makes little sense to the features using it.\n\t\t\t// To get rid of this warning make sure the source passed to the constructor is a descendant of `window.document.body`.\n\t\t\t// @if CK_DEBUG // const sourceNode = isSourceRange ? source.startContainer : source;\n\t\t\t// @if CK_DEBUG // if ( !sourceNode.ownerDocument || !sourceNode.ownerDocument.body.contains( sourceNode ) ) {\n\t\t\t// @if CK_DEBUG // \tconsole.warn(\n\t\t\t// @if CK_DEBUG // \t\t'rect-source-not-in-dom: The source of this rect does not belong to any rendered DOM tree.',\n\t\t\t// @if CK_DEBUG // \t\t{ source } );\n\t\t\t// @if CK_DEBUG // }\n\n\t\t\tif ( isSourceRange ) {\n\t\t\t\tcopyRectProperties( this, Rect.getDomRangeRects( source )[ 0 ] );\n\t\t\t} else {\n\t\t\t\tcopyRectProperties( this, source.getBoundingClientRect() );\n\t\t\t}\n\t\t} else if ( isWindow( source ) ) {\n\t\t\tconst { innerWidth, innerHeight } = source;\n\n\t\t\tcopyRectProperties( this, {\n\t\t\t\ttop: 0,\n\t\t\t\tright: innerWidth,\n\t\t\t\tbottom: innerHeight,\n\t\t\t\tleft: 0,\n\t\t\t\twidth: innerWidth,\n\t\t\t\theight: innerHeight\n\t\t\t} );\n\t\t} else {\n\t\t\tcopyRectProperties( this, source );\n\t\t}\n\n\t\t/**\n\t\t * The \"top\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #top\n\t\t */\n\n\t\t/**\n\t\t * The \"right\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #right\n\t\t */\n\n\t\t/**\n\t\t * The \"bottom\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #bottom\n\t\t */\n\n\t\t/**\n\t\t * The \"left\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #left\n\t\t */\n\n\t\t/**\n\t\t * The \"width\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #width\n\t\t */\n\n\t\t/**\n\t\t * The \"height\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #height\n\t\t */\n\t}\n\n\t/**\n\t * Returns a clone of the rect.\n\t *\n\t * @returns {module:utils/dom/rect~Rect} A cloned rect.\n\t */\n\tclone() {\n\t\treturn new Rect( this );\n\t}\n\n\t/**\n\t * Moves the rect so that its upper–left corner lands in desired `[ x, y ]` location.\n\t *\n\t * @param {Number} x Desired horizontal location.\n\t * @param {Number} y Desired vertical location.\n\t * @returns {module:utils/dom/rect~Rect} A rect which has been moved.\n\t */\n\tmoveTo( x, y ) {\n\t\tthis.top = y;\n\t\tthis.right = x + this.width;\n\t\tthis.bottom = y + this.height;\n\t\tthis.left = x;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Moves the rect in–place by a dedicated offset.\n\t *\n\t * @param {Number} x A horizontal offset.\n\t * @param {Number} y A vertical offset\n\t * @returns {module:utils/dom/rect~Rect} A rect which has been moved.\n\t */\n\tmoveBy( x, y ) {\n\t\tthis.top += y;\n\t\tthis.right += x;\n\t\tthis.left += x;\n\t\tthis.bottom += y;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns a new rect a a result of intersection with another rect.\n\t *\n\t * @param {module:utils/dom/rect~Rect} anotherRect\n\t * @returns {module:utils/dom/rect~Rect}\n\t */\n\tgetIntersection( anotherRect ) {\n\t\tconst rect = {\n\t\t\ttop: Math.max( this.top, anotherRect.top ),\n\t\t\tright: Math.min( this.right, anotherRect.right ),\n\t\t\tbottom: Math.min( this.bottom, anotherRect.bottom ),\n\t\t\tleft: Math.max( this.left, anotherRect.left )\n\t\t};\n\n\t\trect.width = rect.right - rect.left;\n\t\trect.height = rect.bottom - rect.top;\n\n\t\tif ( rect.width < 0 || rect.height < 0 ) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\treturn new Rect( rect );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the area of intersection with another rect.\n\t *\n\t * @param {module:utils/dom/rect~Rect} anotherRect [description]\n\t * @returns {Number} Area of intersection.\n\t */\n\tgetIntersectionArea( anotherRect ) {\n\t\tconst rect = this.getIntersection( anotherRect );\n\n\t\tif ( rect ) {\n\t\t\treturn rect.getArea();\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the area of the rect.\n\t *\n\t * @returns {Number}\n\t */\n\tgetArea() {\n\t\treturn this.width * this.height;\n\t}\n\n\t/**\n\t * Returns a new rect, a part of the original rect, which is actually visible to the user,\n\t * e.g. an original rect cropped by parent element rects which have `overflow` set in CSS\n\t * other than `\"visible\"`.\n\t *\n\t * If there's no such visible rect, which is when the rect is limited by one or many of\n\t * the ancestors, `null` is returned.\n\t *\n\t * @returns {module:utils/dom/rect~Rect|null} A visible rect instance or `null`, if there's none.\n\t */\n\tgetVisible() {\n\t\tconst source = this._source;\n\t\tlet visibleRect = this.clone();\n\n\t\t// There's no ancestor to crop <body> with the overflow.\n\t\tif ( !isBody( source ) ) {\n\t\t\tlet parent = source.parentNode || source.commonAncestorContainer;\n\n\t\t\t// Check the ancestors all the way up to the <body>.\n\t\t\twhile ( parent && !isBody( parent ) ) {\n\t\t\t\tconst parentRect = new Rect( parent );\n\t\t\t\tconst intersectionRect = visibleRect.getIntersection( parentRect );\n\n\t\t\t\tif ( intersectionRect ) {\n\t\t\t\t\tif ( intersectionRect.getArea() < visibleRect.getArea() ) {\n\t\t\t\t\t\t// Reduce the visible rect to the intersection.\n\t\t\t\t\t\tvisibleRect = intersectionRect;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// There's no intersection, the rect is completely invisible.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tparent = parent.parentNode;\n\t\t\t}\n\t\t}\n\n\t\treturn visibleRect;\n\t}\n\n\t/**\n\t * Checks if all property values ({@link #top}, {@link #left}, {@link #right},\n\t * {@link #bottom}, {@link #width} and {@link #height}) are the equal in both rect\n\t * instances.\n\t *\n\t * @param {module:utils/dom/rect~Rect} rect A rect instance to compare with.\n\t * @returns {Boolean} `true` when Rects are equal. `false` otherwise.\n\t */\n\tisEqual( anotherRect ) {\n\t\tfor ( const prop of rectProperties ) {\n\t\t\tif ( this[ prop ] !== anotherRect[ prop ] ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks whether a rect fully contains another rect instance.\n\t *\n\t * @param {module:utils/dom/rect~Rect} anotherRect\n\t * @returns {Boolean} `true` if contains, `false` otherwise.\n\t */\n\tcontains( anotherRect ) {\n\t\tconst intersectRect = this.getIntersection( anotherRect );\n\n\t\treturn !!( intersectRect && intersectRect.isEqual( anotherRect ) );\n\t}\n\n\t/**\n\t * Excludes scrollbars and CSS borders from the rect.\n\t *\n\t * * Borders are removed when {@link #_source} is an HTML element.\n\t * * Scrollbars are excluded from HTML elements and the `window`.\n\t *\n\t * @returns {module:utils/dom/rect~Rect} A rect which has been updated.\n\t */\n\texcludeScrollbarsAndBorders() {\n\t\tconst source = this._source;\n\t\tlet scrollBarWidth, scrollBarHeight, direction;\n\n\t\tif ( isWindow( source ) ) {\n\t\t\tscrollBarWidth = source.innerWidth - source.document.documentElement.clientWidth;\n\t\t\tscrollBarHeight = source.innerHeight - source.document.documentElement.clientHeight;\n\t\t\tdirection = source.getComputedStyle( source.document.documentElement ).direction;\n\t\t} else {\n\t\t\tconst borderWidths = getBorderWidths( this._source );\n\n\t\t\tscrollBarWidth = source.offsetWidth - source.clientWidth - borderWidths.left - borderWidths.right;\n\t\t\tscrollBarHeight = source.offsetHeight - source.clientHeight - borderWidths.top - borderWidths.bottom;\n\t\t\tdirection = source.ownerDocument.defaultView.getComputedStyle( source ).direction;\n\n\t\t\tthis.left += borderWidths.left;\n\t\t\tthis.top += borderWidths.top;\n\t\t\tthis.right -= borderWidths.right;\n\t\t\tthis.bottom -= borderWidths.bottom;\n\t\t\tthis.width = this.right - this.left;\n\t\t\tthis.height = this.bottom - this.top;\n\t\t}\n\n\t\tthis.width -= scrollBarWidth;\n\n\t\tif ( direction === 'ltr' ) {\n\t\t\tthis.right -= scrollBarWidth;\n\t\t} else {\n\t\t\tthis.left += scrollBarWidth;\n\t\t}\n\n\t\tthis.height -= scrollBarHeight;\n\t\tthis.bottom -= scrollBarHeight;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns an array of rects of the given native DOM Range.\n\t *\n\t * @param {Range} range A native DOM range.\n\t * @returns {Array.<module:utils/dom/rect~Rect>} DOM Range rects.\n\t */\n\tstatic getDomRangeRects( range ) {\n\t\tconst rects = [];\n\t\t// Safari does not iterate over ClientRectList using for...of loop.\n\t\tconst clientRects = Array.from( range.getClientRects() );\n\n\t\tif ( clientRects.length ) {\n\t\t\tfor ( const rect of clientRects ) {\n\t\t\t\trects.push( new Rect( rect ) );\n\t\t\t}\n\t\t}\n\t\t// If there's no client rects for the Range, use parent container's bounding rect\n\t\t// instead and adjust rect's width to simulate the actual geometry of such range.\n\t\t// https://github.com/ckeditor/ckeditor5-utils/issues/153\n\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/317\n\t\telse {\n\t\t\tlet startContainer = range.startContainer;\n\n\t\t\tif ( isText( startContainer ) ) {\n\t\t\t\tstartContainer = startContainer.parentNode;\n\t\t\t}\n\n\t\t\tconst rect = new Rect( startContainer.getBoundingClientRect() );\n\t\t\trect.right = rect.left;\n\t\t\trect.width = 0;\n\n\t\t\trects.push( rect );\n\t\t}\n\n\t\treturn rects;\n\t}\n}\n\n// Acquires all the rect properties from the passed source.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} rect\n// @param {ClientRect|module:utils/dom/rect~Rect|Object} source\nfunction copyRectProperties( rect, source ) {\n\tfor ( const p of rectProperties ) {\n\t\trect[ p ] = source[ p ];\n\t}\n}\n\n// Checks if provided object is a <body> HTML element.\n//\n// @private\n// @param {HTMLElement|Range} elementOrRange\n// @returns {Boolean}\nfunction isBody( elementOrRange ) {\n\tif ( !isElement( elementOrRange ) ) {\n\t\treturn false;\n\t}\n\n\treturn elementOrRange === elementOrRange.ownerDocument.body;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/scroll\n */\n\nimport isRange from './isrange';\nimport Rect from './rect';\nimport isText from './istext';\n\nconst utils = {};\n\n/**\n * Makes any page `HTMLElement` or `Range` (`target`) visible inside the browser viewport.\n * This helper will scroll all `target` ancestors and the web browser viewport to reveal the target to\n * the user. If the `target` is already visible, nothing will happen.\n *\n * @param {HTMLElement|Range} options.target A target, which supposed to become visible to the user.\n * @param {Number} [options.viewportOffset] An offset from the edge of the viewport (in pixels)\n * the `target` will be moved by when the viewport is scrolled. It enhances the user experience\n * by keeping the `target` some distance from the edge of the viewport and thus making it easier to\n * read or edit by the user.\n */\nexport function scrollViewportToShowTarget( { target, viewportOffset = 0 } ) {\n\tconst targetWindow = getWindow( target );\n\tlet currentWindow = targetWindow;\n\tlet currentFrame = null;\n\n\t// Iterate over all windows, starting from target's parent window up to window#top.\n\twhile ( currentWindow ) {\n\t\tlet firstAncestorToScroll;\n\n\t\t// Let's scroll target's ancestors first to reveal it. Then, once the ancestor scrolls\n\t\t// settled down, the algorithm can eventually scroll the viewport of the current window.\n\t\t//\n\t\t// Note: If the current window is target's **original** window (e.g. the first one),\n\t\t// start scrolling the closest parent of the target. If not, scroll the closest parent\n\t\t// of an iframe that resides in the current window.\n\t\tif ( currentWindow == targetWindow ) {\n\t\t\tfirstAncestorToScroll = getParentElement( target );\n\t\t} else {\n\t\t\tfirstAncestorToScroll = getParentElement( currentFrame );\n\t\t}\n\n\t\t// Scroll the target's ancestors first. Once done, scrolling the viewport is easy.\n\t\tscrollAncestorsToShowRect( firstAncestorToScroll, () => {\n\t\t\t// Note: If the target does not belong to the current window **directly**,\n\t\t\t// i.e. it resides in an iframe belonging to the window, obtain the target's rect\n\t\t\t// in the coordinates of the current window. By default, a Rect returns geometry\n\t\t\t// relative to the current window's viewport. To make it work in a parent window,\n\t\t\t// it must be shifted.\n\t\t\treturn getRectRelativeToWindow( target, currentWindow );\n\t\t} );\n\n\t\t// Obtain the rect of the target after it has been scrolled within its ancestors.\n\t\t// It's time to scroll the viewport.\n\t\tconst targetRect = getRectRelativeToWindow( target, currentWindow );\n\n\t\tscrollWindowToShowRect( currentWindow, targetRect, viewportOffset );\n\n\t\tif ( currentWindow.parent != currentWindow ) {\n\t\t\t// Keep the reference to the <iframe> element the \"previous current window\" was\n\t\t\t// rendered within. It will be useful to re–calculate the rect of the target\n\t\t\t// in the parent window's relative geometry. The target's rect must be shifted\n\t\t\t// by it's iframe's position.\n\t\t\tcurrentFrame = currentWindow.frameElement;\n\t\t\tcurrentWindow = currentWindow.parent;\n\n\t\t\t// If the current window has some parent but frameElement is inaccessible, then they have\n\t\t\t// different domains/ports and, due to security reasons, accessing and scrolling\n\t\t\t// the parent window won't be possible.\n\t\t\t// See https://github.com/ckeditor/ckeditor5/issues/930.\n\t\t\tif ( !currentFrame ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else {\n\t\t\tcurrentWindow = null;\n\t\t}\n\t}\n}\n\n/**\n * Makes any page `HTMLElement` or `Range` (target) visible within its scrollable ancestors,\n * e.g. if they have `overflow: scroll` CSS style.\n *\n * @param {HTMLElement|Range} target A target, which supposed to become visible to the user.\n */\nexport function scrollAncestorsToShowTarget( target ) {\n\tconst targetParent = getParentElement( target );\n\n\tscrollAncestorsToShowRect( targetParent, () => {\n\t\treturn new Rect( target );\n\t} );\n}\n\n// TODO: Using a property value shorthand in the top of the file\n// causes JSDoc to throw errors. See https://github.com/cksource/docs-builder/issues/75.\nObject.assign( utils, {\n\tscrollViewportToShowTarget,\n\tscrollAncestorsToShowTarget\n} );\n\n// Makes a given rect visible within its parent window.\n//\n// Note: Avoid the situation where the caret is still in the viewport, but totally\n// at the edge of it. In such situation, if it moved beyond the viewport in the next\n// action e.g. after paste, the scrolling would move it to the viewportOffset level\n// and it all would look like the caret visually moved up/down:\n//\n// 1.\n//\t\t| foo[]\n//\t\t| <--- N px of space below the caret\n//\t\t+---------------------------------...\n//\n// 2. *paste*\n// 3.\n//\t\t|\n//\t\t|\n//\t\t+-foo-----------------------------...\n//\t\t bar[] <--- caret below viewport, scrolling...\n//\n// 4. *scrolling*\n// 5.\n//\t\t|\n//\t\t| foo\n//\t\t| bar[] <--- caret precisely at the edge\n//\t\t+---------------------------------...\n//\n// To prevent this, this method checks the rects moved by the viewportOffset to cover\n// the upper/lower edge of the viewport. It makes sure if the action repeats, there's\n// no twitching – it's a purely visual improvement:\n//\n// 5. (after fix)\n//\t\t|\n//\t\t| foo\n//\t\t| bar[]\n//\t\t| <--- N px of space below the caret\n//\t\t+---------------------------------...\n//\n// @private\n// @param {Window} window A window which is scrolled to reveal the rect.\n// @param {module:utils/dom/rect~Rect} rect A rect which is to be revealed.\n// @param {Number} viewportOffset See scrollViewportToShowTarget.\nfunction scrollWindowToShowRect( window, rect, viewportOffset ) {\n\tconst targetShiftedDownRect = rect.clone().moveBy( 0, viewportOffset );\n\tconst targetShiftedUpRect = rect.clone().moveBy( 0, -viewportOffset );\n\tconst viewportRect = new Rect( window ).excludeScrollbarsAndBorders();\n\n\tconst rects = [ targetShiftedUpRect, targetShiftedDownRect ];\n\n\tif ( !rects.every( rect => viewportRect.contains( rect ) ) ) {\n\t\tlet { scrollX, scrollY } = window;\n\n\t\tif ( isAbove( targetShiftedUpRect, viewportRect ) ) {\n\t\t\tscrollY -= viewportRect.top - rect.top + viewportOffset;\n\t\t} else if ( isBelow( targetShiftedDownRect, viewportRect ) ) {\n\t\t\tscrollY += rect.bottom - viewportRect.bottom + viewportOffset;\n\t\t}\n\n\t\t// TODO: Web browsers scroll natively to place the target in the middle\n\t\t// of the viewport. It's not a very popular case, though.\n\t\tif ( isLeftOf( rect, viewportRect ) ) {\n\t\t\tscrollX -= viewportRect.left - rect.left + viewportOffset;\n\t\t} else if ( isRightOf( rect, viewportRect ) ) {\n\t\t\tscrollX += rect.right - viewportRect.right + viewportOffset;\n\t\t}\n\n\t\twindow.scrollTo( scrollX, scrollY );\n\t}\n}\n\n// Recursively scrolls element ancestors to visually reveal a rect.\n//\n// @private\n// @param {HTMLElement} A parent The first ancestors to start scrolling.\n// @param {Function} getRect A function which returns the Rect, which is to be revealed.\nfunction scrollAncestorsToShowRect( parent, getRect ) {\n\tconst parentWindow = getWindow( parent );\n\tlet parentRect, targetRect;\n\n\twhile ( parent != parentWindow.document.body ) {\n\t\ttargetRect = getRect();\n\t\tparentRect = new Rect( parent ).excludeScrollbarsAndBorders();\n\n\t\tif ( !parentRect.contains( targetRect ) ) {\n\t\t\tif ( isAbove( targetRect, parentRect ) ) {\n\t\t\t\tparent.scrollTop -= parentRect.top - targetRect.top;\n\t\t\t} else if ( isBelow( targetRect, parentRect ) ) {\n\t\t\t\tparent.scrollTop += targetRect.bottom - parentRect.bottom;\n\t\t\t}\n\n\t\t\tif ( isLeftOf( targetRect, parentRect ) ) {\n\t\t\t\tparent.scrollLeft -= parentRect.left - targetRect.left;\n\t\t\t} else if ( isRightOf( targetRect, parentRect ) ) {\n\t\t\t\tparent.scrollLeft += targetRect.right - parentRect.right;\n\t\t\t}\n\t\t}\n\n\t\tparent = parent.parentNode;\n\t}\n}\n\n// Determines if a given `Rect` extends beyond the bottom edge of the second `Rect`.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} firstRect\n// @param {module:utils/dom/rect~Rect} secondRect\nfunction isBelow( firstRect, secondRect ) {\n\treturn firstRect.bottom > secondRect.bottom;\n}\n\n// Determines if a given `Rect` extends beyond the top edge of the second `Rect`.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} firstRect\n// @param {module:utils/dom/rect~Rect} secondRect\nfunction isAbove( firstRect, secondRect ) {\n\treturn firstRect.top < secondRect.top;\n}\n\n// Determines if a given `Rect` extends beyond the left edge of the second `Rect`.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} firstRect\n// @param {module:utils/dom/rect~Rect} secondRect\nfunction isLeftOf( firstRect, secondRect ) {\n\treturn firstRect.left < secondRect.left;\n}\n\n// Determines if a given `Rect` extends beyond the right edge of the second `Rect`.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} firstRect\n// @param {module:utils/dom/rect~Rect} secondRect\nfunction isRightOf( firstRect, secondRect ) {\n\treturn firstRect.right > secondRect.right;\n}\n\n// Returns the closest window of an element or range.\n//\n// @private\n// @param {HTMLElement|Range} firstRect\n// @returns {Window}\nfunction getWindow( elementOrRange ) {\n\tif ( isRange( elementOrRange ) ) {\n\t\treturn elementOrRange.startContainer.ownerDocument.defaultView;\n\t} else {\n\t\treturn elementOrRange.ownerDocument.defaultView;\n\t}\n}\n\n// Returns the closest parent of an element or DOM range.\n//\n// @private\n// @param {HTMLElement|Range} firstRect\n// @returns {HTMLelement}\nfunction getParentElement( elementOrRange ) {\n\tif ( isRange( elementOrRange ) ) {\n\t\tlet parent = elementOrRange.commonAncestorContainer;\n\n\t\t// If a Range is attached to the Text, use the closest element ancestor.\n\t\tif ( isText( parent ) ) {\n\t\t\tparent = parent.parentNode;\n\t\t}\n\n\t\treturn parent;\n\t} else {\n\t\treturn elementOrRange.parentNode;\n\t}\n}\n\n// Returns the rect of an element or range residing in an iframe.\n// The result rect is relative to the geometry of the passed window instance.\n//\n// @private\n// @param {HTMLElement|Range} target Element or range which rect should be returned.\n// @param {Window} relativeWindow A window the rect should be relative to.\n// @returns {module:utils/dom/rect~Rect}\nfunction getRectRelativeToWindow( target, relativeWindow ) {\n\tconst targetWindow = getWindow( target );\n\tconst rect = new Rect( target );\n\n\tif ( targetWindow === relativeWindow ) {\n\t\treturn rect;\n\t} else {\n\t\tlet currentWindow = targetWindow;\n\n\t\twhile ( currentWindow != relativeWindow ) {\n\t\t\tconst frame = currentWindow.frameElement;\n\t\t\tconst frameRect = new Rect( frame ).excludeScrollbarsAndBorders();\n\n\t\t\trect.moveBy( frameRect.left, frameRect.top );\n\n\t\t\tcurrentWindow = currentWindow.parent;\n\t\t}\n\t}\n\n\treturn rect;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/view\n */\n\nimport Document from './document';\nimport DowncastWriter from './downcastwriter';\nimport Renderer from './renderer';\nimport DomConverter from './domconverter';\nimport Position from './position';\nimport Range from './range';\nimport Selection from './selection';\n\nimport MutationObserver from './observer/mutationobserver';\nimport KeyObserver from './observer/keyobserver';\nimport FakeSelectionObserver from './observer/fakeselectionobserver';\nimport SelectionObserver from './observer/selectionobserver';\nimport FocusObserver from './observer/focusobserver';\nimport CompositionObserver from './observer/compositionobserver';\nimport InputObserver from './observer/inputobserver';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { scrollViewportToShowTarget } from '@ckeditor/ckeditor5-utils/src/dom/scroll';\nimport { injectUiElementHandling } from './uielement';\nimport { injectQuirksHandling } from './filler';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * Editor's view controller class. Its main responsibility is DOM - View management for editing purposes, to provide\n * abstraction over the DOM structure and events and hide all browsers quirks.\n *\n * View controller renders view document to DOM whenever view structure changes. To determine when view can be rendered,\n * all changes need to be done using the {@link module:engine/view/view~View#change} method, using\n * {@link module:engine/view/downcastwriter~DowncastWriter}:\n *\n *\t\tview.change( writer => {\n *\t\t\twriter.insert( position, writer.createText( 'foo' ) );\n *\t\t} );\n *\n * View controller also register {@link module:engine/view/observer/observer~Observer observers} which observes changes\n * on DOM and fire events on the {@link module:engine/view/document~Document Document}.\n * Note that the following observers are added by the class constructor and are always available:\n *\n * * {@link module:engine/view/observer/mutationobserver~MutationObserver},\n * * {@link module:engine/view/observer/selectionobserver~SelectionObserver},\n * * {@link module:engine/view/observer/focusobserver~FocusObserver},\n * * {@link module:engine/view/observer/keyobserver~KeyObserver},\n * * {@link module:engine/view/observer/fakeselectionobserver~FakeSelectionObserver}.\n * * {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n *\n * This class also {@link module:engine/view/view~View#attachDomRoot binds the DOM and the view elements}.\n *\n * If you do not need full a DOM - view management, and only want to transform a tree of view elements to a tree of DOM\n * elements you do not need this controller. You can use the {@link module:engine/view/domconverter~DomConverter DomConverter} instead.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class View {\n\tconstructor() {\n\t\t/**\n\t\t * Instance of the {@link module:engine/view/document~Document} associated with this view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = new Document();\n\n\t\t/**\n\t\t * Instance of the {@link module:engine/view/domconverter~DomConverter domConverter} used by\n\t\t * {@link module:engine/view/view~View#_renderer renderer}\n\t\t * and {@link module:engine/view/observer/observer~Observer observers}.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/view/domconverter~DomConverter}\n\t\t */\n\t\tthis.domConverter = new DomConverter();\n\n\t\t/**\n\t\t * Roots of the DOM tree. Map on the `HTMLElement`s with roots names as keys.\n\t\t *\n\t\t * @readonly\n\t\t * @type {Map.<String, HTMLElement>}\n\t\t */\n\t\tthis.domRoots = new Map();\n\n\t\t/**\n\t\t * Used to prevent calling {@link #forceRender} and {@link #change} during rendering view to the DOM.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isRenderingInProgress\n\t\t */\n\t\tthis.set( 'isRenderingInProgress', false );\n\n\t\t/**\n\t\t * Instance of the {@link module:engine/view/renderer~Renderer renderer}.\n\t\t *\n\t\t * @protected\n\t\t * @type {module:engine/view/renderer~Renderer}\n\t\t */\n\t\tthis._renderer = new Renderer( this.domConverter, this.document.selection );\n\t\tthis._renderer.bind( 'isFocused' ).to( this.document );\n\n\t\t/**\n\t\t * A DOM root attributes cache. It saves the initial values of DOM root attributes before the DOM element\n\t\t * is {@link module:engine/view/view~View#attachDomRoot attached} to the view so later on, when\n\t\t * the view is destroyed ({@link module:engine/view/view~View#detachDomRoot}), they can be easily restored.\n\t\t * This way, the DOM element can go back to the (clean) state as if the editing view never used it.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap.<HTMLElement,Object>}\n\t\t */\n\t\tthis._initialDomRootAttributes = new WeakMap();\n\n\t\t/**\n\t\t * Map of registered {@link module:engine/view/observer/observer~Observer observers}.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<Function, module:engine/view/observer/observer~Observer>}\n\t\t */\n\t\tthis._observers = new Map();\n\n\t\t/**\n\t\t * Is set to `true` when {@link #change view changes} are currently in progress.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._ongoingChange = false;\n\n\t\t/**\n\t\t * Used to prevent calling {@link #forceRender} and {@link #change} during rendering view to the DOM.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._postFixersInProgress = false;\n\n\t\t/**\n\t\t * Internal flag to temporary disable rendering. See the usage in the {@link #_disableRendering}.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._renderingDisabled = false;\n\n\t\t/**\n\t\t * Internal flag that disables rendering when there are no changes since the last rendering.\n\t\t * It stores information about changed selection and changed elements from attached document roots.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._hasChangedSinceTheLastRendering = false;\n\n\t\t/**\n\t\t * DowncastWriter instance used in {@link #change change method} callbacks.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/view/downcastwriter~DowncastWriter}\n\t\t */\n\t\tthis._writer = new DowncastWriter( this.document );\n\n\t\t// Add default observers.\n\t\tthis.addObserver( MutationObserver );\n\t\tthis.addObserver( SelectionObserver );\n\t\tthis.addObserver( FocusObserver );\n\t\tthis.addObserver( KeyObserver );\n\t\tthis.addObserver( FakeSelectionObserver );\n\t\tthis.addObserver( CompositionObserver );\n\n\t\tif ( env.isAndroid ) {\n\t\t\tthis.addObserver( InputObserver );\n\t\t}\n\n\t\t// Inject quirks handlers.\n\t\tinjectQuirksHandling( this );\n\t\tinjectUiElementHandling( this );\n\n\t\t// Use 'normal' priority so that rendering is performed as first when using that priority.\n\t\tthis.on( 'render', () => {\n\t\t\tthis._render();\n\n\t\t\t// Informs that layout has changed after render.\n\t\t\tthis.document.fire( 'layoutChanged' );\n\n\t\t\t// Reset the `_hasChangedSinceTheLastRendering` flag after rendering.\n\t\t\tthis._hasChangedSinceTheLastRendering = false;\n\t\t} );\n\n\t\t// Listen to the document selection changes directly.\n\t\tthis.listenTo( this.document.selection, 'change', () => {\n\t\t\tthis._hasChangedSinceTheLastRendering = true;\n\t\t} );\n\t}\n\n\t/**\n\t * Attaches a DOM root element to the view element and enable all observers on that element.\n\t * Also {@link module:engine/view/renderer~Renderer#markToSync mark element} to be synchronized\n\t * with the view what means that all child nodes will be removed and replaced with content of the view root.\n\t *\n\t * This method also will change view element name as the same as tag name of given dom root.\n\t * Name is always transformed to lower case.\n\t *\n\t * **Note:** Use {@link #detachDomRoot `detachDomRoot()`} to revert this action.\n\t *\n\t * @param {Element} domRoot DOM root element.\n\t * @param {String} [name='main'] Name of the root.\n\t */\n\tattachDomRoot( domRoot, name = 'main' ) {\n\t\tconst viewRoot = this.document.getRoot( name );\n\n\t\t// Set view root name the same as DOM root tag name.\n\t\tviewRoot._name = domRoot.tagName.toLowerCase();\n\n\t\tconst initialDomRootAttributes = {};\n\n\t\t// 1. Copy and cache the attributes to remember the state of the element before attaching.\n\t\t// The cached attributes will be restored in detachDomRoot() so the element goes to the\n\t\t// clean state as if the editing view never used it.\n\t\t// 2. Apply the attributes using the view writer, so they all go under the control of the engine.\n\t\t// The editing view takes over the attribute management completely because various\n\t\t// features (e.g. addPlaceholder()) require dynamic changes of those attributes and they\n\t\t// cannot be managed by the engine and the UI library at the same time.\n\t\tfor ( const { name, value } of Array.from( domRoot.attributes ) ) {\n\t\t\tinitialDomRootAttributes[ name ] = value;\n\n\t\t\t// Do not use writer.setAttribute() for the class attribute. The EditableUIView class\n\t\t\t// and its descendants could have already set some using the writer.addClass() on the view\n\t\t\t// document root. They haven't been rendered yet so they are not present in the DOM root.\n\t\t\t// Using writer.setAttribute( 'class', ... ) would override them completely.\n\t\t\tif ( name === 'class' ) {\n\t\t\t\tthis._writer.addClass( value.split( ' ' ), viewRoot );\n\t\t\t} else {\n\t\t\t\tthis._writer.setAttribute( name, value, viewRoot );\n\t\t\t}\n\t\t}\n\n\t\tthis._initialDomRootAttributes.set( domRoot, initialDomRootAttributes );\n\n\t\tconst updateContenteditableAttribute = () => {\n\t\t\tthis._writer.setAttribute( 'contenteditable', !viewRoot.isReadOnly, viewRoot );\n\n\t\t\tif ( viewRoot.isReadOnly ) {\n\t\t\t\tthis._writer.addClass( 'ck-read-only', viewRoot );\n\t\t\t} else {\n\t\t\t\tthis._writer.removeClass( 'ck-read-only', viewRoot );\n\t\t\t}\n\t\t};\n\n\t\t// Set initial value.\n\t\tupdateContenteditableAttribute();\n\n\t\tthis.domRoots.set( name, domRoot );\n\t\tthis.domConverter.bindElements( domRoot, viewRoot );\n\t\tthis._renderer.markToSync( 'children', viewRoot );\n\t\tthis._renderer.markToSync( 'attributes', viewRoot );\n\t\tthis._renderer.domDocuments.add( domRoot.ownerDocument );\n\n\t\tviewRoot.on( 'change:children', ( evt, node ) => this._renderer.markToSync( 'children', node ) );\n\t\tviewRoot.on( 'change:attributes', ( evt, node ) => this._renderer.markToSync( 'attributes', node ) );\n\t\tviewRoot.on( 'change:text', ( evt, node ) => this._renderer.markToSync( 'text', node ) );\n\t\tviewRoot.on( 'change:isReadOnly', () => this.change( updateContenteditableAttribute ) );\n\n\t\tviewRoot.on( 'change', () => {\n\t\t\tthis._hasChangedSinceTheLastRendering = true;\n\t\t} );\n\n\t\tfor ( const observer of this._observers.values() ) {\n\t\t\tobserver.observe( domRoot, name );\n\t\t}\n\t}\n\n\t/**\n\t * Detaches a DOM root element from the view element and restores its attributes to the state before\n\t * {@link #attachDomRoot `attachDomRoot()`}.\n\t *\n\t * @param {String} name Name of the root to detach.\n\t */\n\tdetachDomRoot( name ) {\n\t\tconst domRoot = this.domRoots.get( name );\n\n\t\t// Remove all root attributes so the DOM element is \"bare\".\n\t\tArray.from( domRoot.attributes ).forEach( ( { name } ) => domRoot.removeAttribute( name ) );\n\n\t\tconst initialDomRootAttributes = this._initialDomRootAttributes.get( domRoot );\n\n\t\t// Revert all view root attributes back to the state before attachDomRoot was called.\n\t\tfor ( const attribute in initialDomRootAttributes ) {\n\t\t\tdomRoot.setAttribute( attribute, initialDomRootAttributes[ attribute ] );\n\t\t}\n\n\t\tthis.domRoots.delete( name );\n\t\tthis.domConverter.unbindDomElement( domRoot );\n\t}\n\n\t/**\n\t * Gets DOM root element.\n\t *\n\t * @param {String} [name='main'] Name of the root.\n\t * @returns {Element} DOM root element instance.\n\t */\n\tgetDomRoot( name = 'main' ) {\n\t\treturn this.domRoots.get( name );\n\t}\n\n\t/**\n\t * Creates observer of the given type if not yet created, {@link module:engine/view/observer/observer~Observer#enable enables} it\n\t * and {@link module:engine/view/observer/observer~Observer#observe attaches} to all existing and future\n\t * {@link #domRoots DOM roots}.\n\t *\n\t * Note: Observers are recognized by their constructor (classes). A single observer will be instantiated and used only\n\t * when registered for the first time. This means that features and other components can register a single observer\n\t * multiple times without caring whether it has been already added or not.\n\t *\n\t * @param {Function} Observer The constructor of an observer to add.\n\t * Should create an instance inheriting from {@link module:engine/view/observer/observer~Observer}.\n\t * @returns {module:engine/view/observer/observer~Observer} Added observer instance.\n\t */\n\taddObserver( Observer ) {\n\t\tlet observer = this._observers.get( Observer );\n\n\t\tif ( observer ) {\n\t\t\treturn observer;\n\t\t}\n\n\t\tobserver = new Observer( this );\n\n\t\tthis._observers.set( Observer, observer );\n\n\t\tfor ( const [ name, domElement ] of this.domRoots ) {\n\t\t\tobserver.observe( domElement, name );\n\t\t}\n\n\t\tobserver.enable();\n\n\t\treturn observer;\n\t}\n\n\t/**\n\t * Returns observer of the given type or `undefined` if such observer has not been added yet.\n\t *\n\t * @param {Function} Observer The constructor of an observer to get.\n\t * @returns {module:engine/view/observer/observer~Observer|undefined} Observer instance or undefined.\n\t */\n\tgetObserver( Observer ) {\n\t\treturn this._observers.get( Observer );\n\t}\n\n\t/**\n\t * Disables all added observers.\n\t */\n\tdisableObservers() {\n\t\tfor ( const observer of this._observers.values() ) {\n\t\t\tobserver.disable();\n\t\t}\n\t}\n\n\t/**\n\t * Enables all added observers.\n\t */\n\tenableObservers() {\n\t\tfor ( const observer of this._observers.values() ) {\n\t\t\tobserver.enable();\n\t\t}\n\t}\n\n\t/**\n\t * Scrolls the page viewport and {@link #domRoots} with their ancestors to reveal the\n\t * caret, if not already visible to the user.\n\t */\n\tscrollToTheSelection() {\n\t\tconst range = this.document.selection.getFirstRange();\n\n\t\tif ( range ) {\n\t\t\tscrollViewportToShowTarget( {\n\t\t\t\ttarget: this.domConverter.viewRangeToDom( range ),\n\t\t\t\tviewportOffset: 20\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * It will focus DOM element representing {@link module:engine/view/editableelement~EditableElement EditableElement}\n\t * that is currently having selection inside.\n\t */\n\tfocus() {\n\t\tif ( !this.document.isFocused ) {\n\t\t\tconst editable = this.document.selection.editableElement;\n\n\t\t\tif ( editable ) {\n\t\t\t\tthis.domConverter.focus( editable );\n\t\t\t\tthis.forceRender();\n\t\t\t} else {\n\t\t\t\t// Before focusing view document, selection should be placed inside one of the view's editables.\n\t\t\t\t// Normally its selection will be converted from model document (which have default selection), but\n\t\t\t\t// when using view document on its own, we need to manually place selection before focusing it.\n\t\t\t\t//\n\t\t\t\t// @if CK_DEBUG // console.warn( 'There is no selection in any editable to focus.' );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The `change()` method is the primary way of changing the view. You should use it to modify any node in the view tree.\n\t * It makes sure that after all changes are made the view is rendered to the DOM (assuming that the view will be changed\n\t * inside the callback). It prevents situations when the DOM is updated when the view state is not yet correct. It allows\n\t * to nest calls one inside another and still performs a single rendering after all those changes are made.\n\t * It also returns the return value of its callback.\n\t *\n\t *\t\tconst text = view.change( writer => {\n\t *\t\t\tconst newText = writer.createText( 'foo' );\n\t *\t\t\twriter.insert( position1, newText );\n\t *\n\t *\t\t\tview.change( writer => {\n\t *\t\t\t\twriter.insert( position2, writer.createText( 'bar' ) );\n\t *\t\t\t} );\n\t *\n\t * \t\t\twriter.remove( range );\n\t *\n\t * \t\t\treturn newText;\n\t *\t\t} );\n\t *\n\t * When the outermost change block is done and rendering to the DOM is over the\n\t * {@link module:engine/view/view~View#event:render `View#render`} event is fired.\n\t *\n\t * This method throws a `applying-view-changes-on-rendering` error when\n\t * the change block is used after rendering to the DOM has started.\n\t *\n\t * @param {Function} callback Callback function which may modify the view.\n\t * @returns {*} Value returned by the callback.\n\t */\n\tchange( callback ) {\n\t\tif ( this.isRenderingInProgress || this._postFixersInProgress ) {\n\t\t\t/**\n\t\t\t * Thrown when there is an attempt to make changes to the view tree when it is in incorrect state. This may\n\t\t\t * cause some unexpected behaviour and inconsistency between the DOM and the view.\n\t\t\t * This may be caused by:\n\t\t\t *\n\t\t\t * * calling {@link #change} or {@link #forceRender} during rendering process,\n\t\t\t * * calling {@link #change} or {@link #forceRender} inside of\n\t\t\t * {@link module:engine/view/document~Document#registerPostFixer post-fixer function}.\n\t\t\t *\n\t\t\t * @error cannot-change-view-tree\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'cannot-change-view-tree: ' +\n\t\t\t\t'Attempting to make changes to the view when it is in an incorrect state: rendering or post-fixers are in progress. ' +\n\t\t\t\t'This may cause some unexpected behavior and inconsistency between the DOM and the view.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\t// Recursive call to view.change() method - execute listener immediately.\n\t\t\tif ( this._ongoingChange ) {\n\t\t\t\treturn callback( this._writer );\n\t\t\t}\n\n\t\t\t// This lock will assure that all recursive calls to view.change() will end up in same block - one \"render\"\n\t\t\t// event for all nested calls.\n\t\t\tthis._ongoingChange = true;\n\t\t\tconst callbackResult = callback( this._writer );\n\t\t\tthis._ongoingChange = false;\n\n\t\t\t// This lock is used by editing controller to render changes from outer most model.change() once. As plugins might call\n\t\t\t// view.change() inside model.change() block - this will ensures that postfixers and rendering are called once after all\n\t\t\t// changes. Also, we don't need to render anything if there're no changes since last rendering.\n\t\t\tif ( !this._renderingDisabled && this._hasChangedSinceTheLastRendering ) {\n\t\t\t\tthis._postFixersInProgress = true;\n\t\t\t\tthis.document._callPostFixers( this._writer );\n\t\t\t\tthis._postFixersInProgress = false;\n\n\t\t\t\tthis.fire( 'render' );\n\t\t\t}\n\n\t\t\treturn callbackResult;\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t}\n\n\t/**\n\t * Forces rendering {@link module:engine/view/document~Document view document} to DOM. If any view changes are\n\t * currently in progress, rendering will start after all {@link #change change blocks} are processed.\n\t *\n\t * Note that this method is dedicated for special cases. All view changes should be wrapped in the {@link #change}\n\t * block and the view will automatically check whether it needs to render DOM or not.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `applying-view-changes-on-rendering` when\n\t * trying to re-render when rendering to DOM has already started.\n\t */\n\tforceRender() {\n\t\tthis._hasChangedSinceTheLastRendering = true;\n\t\tthis.change( () => {} );\n\t}\n\n\t/**\n\t * Destroys this instance. Makes sure that all observers are destroyed and listeners removed.\n\t */\n\tdestroy() {\n\t\tfor ( const observer of this._observers.values() ) {\n\t\t\tobserver.destroy();\n\t\t}\n\n\t\tthis.document.destroy();\n\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link #createPositionBefore},\n\t * * {@link #createPositionAfter},\n\t *\n\t * @param {module:engine/view/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn Position._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn Position._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn Position._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn Range._createOn( item );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn Range._createIn( element );\n\t}\n\n\t/**\n\t Creates new {@link module:engine/view/selection~Selection} instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = view.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = view.createRange( start, end );\n\t *\t\tconst selection = view.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ view.createRange( start1, end2 ), view.createRange( star2, end2 ) ];\n\t *\t\tconst selection = view.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = view.createSelection();\n\t *\t\tconst selection = view.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = view.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = view.createPositionFromPath( root, path );\n\t *\t\tconst selection = view.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = view.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = view.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = view.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = view.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s factory method allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = view.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = view.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t * @returns {module:engine/view/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn new Selection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Disables or enables rendering. If the flag is set to `true` then the rendering will be disabled.\n\t * If the flag is set to `false` and if there was some change in the meantime, then the rendering action will be performed.\n\t *\n\t * @protected\n\t * @param {Boolean} flag A flag indicates whether the rendering should be disabled.\n\t */\n\t_disableRendering( flag ) {\n\t\tthis._renderingDisabled = flag;\n\n\t\tif ( flag == false ) {\n\t\t\t// Render when you stop blocking rendering.\n\t\t\tthis.change( () => {} );\n\t\t}\n\t}\n\n\t/**\n\t * Renders all changes. In order to avoid triggering the observers (e.g. mutations) all observers are disabled\n\t * before rendering and re-enabled after that.\n\t *\n\t * @private\n\t */\n\t_render() {\n\t\tthis.isRenderingInProgress = true;\n\t\tthis.disableObservers();\n\t\tthis._renderer.render();\n\t\tthis.enableObservers();\n\t\tthis.isRenderingInProgress = false;\n\t}\n\n\t/**\n\t * Fired after a topmost {@link module:engine/view/view~View#change change block} and all\n\t * {@link module:engine/view/document~Document#registerPostFixer post-fixers} are executed.\n\t *\n\t * Actual rendering is performed as a first listener on 'normal' priority.\n\t *\n\t *\t\tview.on( 'render', () => {\n\t *\t\t\t// Rendering to the DOM is complete.\n\t *\t\t} );\n\t *\n\t * This event is useful when you want to update interface elements after the rendering, e.g. position of the\n\t * balloon panel. If you wants to change view structure use\n\t * {@link module:engine/view/document~Document#registerPostFixer post-fixers}.\n\t *\n\t * @event module:engine/view/view~View#event:render\n\t */\n}\n\nmix( View, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/node\n */\n\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Model node. Most basic structure of model tree.\n *\n * This is an abstract class that is a base for other classes representing different nodes in model.\n *\n * **Note:** If a node is detached from the model tree, you can manipulate it using it's API.\n * However, it is **very important** that nodes already attached to model tree should be only changed through\n * {@link module:engine/model/writer~Writer Writer API}.\n *\n * Changes done by `Node` methods, like {@link module:engine/model/element~Element#_insertChild _insertChild} or\n * {@link module:engine/model/node~Node#_setAttribute _setAttribute}\n * do not generate {@link module:engine/model/operation/operation~Operation operations}\n * which are essential for correct editor work if you modify nodes in {@link module:engine/model/document~Document document} root.\n *\n * The flow of working on `Node` (and classes that inherits from it) is as such:\n * 1. You can create a `Node` instance, modify it using it's API.\n * 2. Add `Node` to the model using `Batch` API.\n * 3. Change `Node` that was already added to the model using `Batch` API.\n *\n * Similarly, you cannot use `Batch` API on a node that has not been added to the model tree, with the exception\n * of {@link module:engine/model/writer~Writer#insert inserting} that node to the model tree.\n *\n * Be aware that using {@link module:engine/model/writer~Writer#remove remove from Batch API} does not allow to use `Node` API because\n * the information about `Node` is still kept in model document.\n *\n * In case of {@link module:engine/model/element~Element element node}, adding and removing children also counts as changing a node and\n * follows same rules.\n */\nexport default class Node {\n\t/**\n\t * Creates a model node.\n\t *\n\t * This is an abstract class, so this constructor should not be used directly.\n\t *\n\t * @abstract\n\t * @param {Object} [attrs] Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t */\n\tconstructor( attrs ) {\n\t\t/**\n\t\t * Parent of this node. It could be {@link module:engine/model/element~Element}\n\t\t * or {@link module:engine/model/documentfragment~DocumentFragment}.\n\t\t * Equals to `null` if the node has no parent.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t\t */\n\t\tthis.parent = null;\n\n\t\t/**\n\t\t * Attributes set on this node.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} module:engine/model/node~Node#_attrs\n\t\t */\n\t\tthis._attrs = toMap( attrs );\n\t}\n\n\t/**\n\t * Index of this node in it's parent or `null` if the node has no parent.\n\t *\n\t * Accessing this property throws an error if this node's parent element does not contain it.\n\t * This means that model tree got broken.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget index() {\n\t\tlet pos;\n\n\t\tif ( !this.parent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( ( pos = this.parent.getChildIndex( this ) ) === null ) {\n\t\t\tthrow new CKEditorError( 'model-node-not-found-in-parent: The node\\'s parent does not contain this node.', this );\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t/**\n\t * Offset at which this node starts in it's parent. It is equal to the sum of {@link #offsetSize offsetSize}\n\t * of all it's previous siblings. Equals to `null` if node has no parent.\n\t *\n\t * Accessing this property throws an error if this node's parent element does not contain it.\n\t * This means that model tree got broken.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget startOffset() {\n\t\tlet pos;\n\n\t\tif ( !this.parent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( ( pos = this.parent.getChildStartOffset( this ) ) === null ) {\n\t\t\tthrow new CKEditorError( 'model-node-not-found-in-parent: The node\\'s parent does not contain this node.', this );\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t/**\n\t * Offset size of this node. Represents how much \"offset space\" is occupied by the node in it's parent.\n\t * It is important for {@link module:engine/model/position~Position position}. When node has `offsetSize` greater than `1`, position\n\t * can be placed between that node start and end. `offsetSize` greater than `1` is for nodes that represents more\n\t * than one entity, i.e. {@link module:engine/model/text~Text text node}.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget offsetSize() {\n\t\treturn 1;\n\t}\n\n\t/**\n\t * Offset at which this node ends in it's parent. It is equal to the sum of this node's\n\t * {@link module:engine/model/node~Node#startOffset start offset} and {@link #offsetSize offset size}.\n\t * Equals to `null` if the node has no parent.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget endOffset() {\n\t\tif ( !this.parent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.startOffset + this.offsetSize;\n\t}\n\n\t/**\n\t * Node's next sibling or `null` if the node is a last child of it's parent or if the node has no parent.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|null}\n\t */\n\tget nextSibling() {\n\t\tconst index = this.index;\n\n\t\treturn ( index !== null && this.parent.getChild( index + 1 ) ) || null;\n\t}\n\n\t/**\n\t * Node's previous sibling or `null` if the node is a first child of it's parent or if the node has no parent.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|null}\n\t */\n\tget previousSibling() {\n\t\tconst index = this.index;\n\n\t\treturn ( index !== null && this.parent.getChild( index - 1 ) ) || null;\n\t}\n\n\t/**\n\t * The top-most ancestor of the node. If node has no parent it is the root itself. If the node is a part\n\t * of {@link module:engine/model/documentfragment~DocumentFragment}, it's `root` is equal to that `DocumentFragment`.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\tlet root = this; // eslint-disable-line consistent-this\n\n\t\twhile ( root.parent ) {\n\t\t\troot = root.parent;\n\t\t}\n\n\t\treturn root;\n\t}\n\n\t/**\n\t * {@link module:engine/model/document~Document Document} that owns this node or `null` if the node has no parent or is inside\n\t * a {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment}.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/document~Document|null}\n\t */\n\tget document() {\n\t\t// This is a top element of a sub-tree.\n\t\tif ( this.root == this ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Root may be `DocumentFragment` which does not have document property.\n\t\treturn this.root.document || null;\n\t}\n\n\t/**\n\t * Gets path to the node. The path is an array containing starting offsets of consecutive ancestors of this node,\n\t * beginning from {@link module:engine/model/node~Node#root root}, down to this node's starting offset. The path can be used to\n\t * create {@link module:engine/model/position~Position Position} instance.\n\t *\n\t *\t\tconst abc = new Text( 'abc' );\n\t *\t\tconst foo = new Text( 'foo' );\n\t *\t\tconst h1 = new Element( 'h1', null, new Text( 'header' ) );\n\t *\t\tconst p = new Element( 'p', null, [ abc, foo ] );\n\t *\t\tconst div = new Element( 'div', null, [ h1, p ] );\n\t *\t\tfoo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3.\n\t *\t\th1.getPath(); // Returns [ 0 ].\n\t *\t\tdiv.getPath(); // Returns [].\n\t *\n\t * @returns {Array.<Number>} The path.\n\t */\n\tgetPath() {\n\t\tconst path = [];\n\t\tlet node = this; // eslint-disable-line consistent-this\n\n\t\twhile ( node.parent ) {\n\t\t\tpath.unshift( node.startOffset );\n\t\t\tnode = node.parent;\n\t\t}\n\n\t\treturn path;\n\t}\n\n\t/**\n\t * Returns ancestors array of this node.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` this node will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from node's parent to root element,\n\t * otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this : this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both nodes.\n\t *\n\t * @param {module:engine/model/node~Node} node The second node.\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` both nodes will be considered \"ancestors\" too.\n\t * Which means that if e.g. node A is inside B, then their common ancestor will be B.\n\t * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( node, options = {} ) {\n\t\tconst ancestorsA = this.getAncestors( options );\n\t\tconst ancestorsB = node.getAncestors( options );\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Returns whether this node is before given node. `false` is returned if nodes are in different trees (for example,\n\t * in different {@link module:engine/model/documentfragment~DocumentFragment}s).\n\t *\n\t * @param {module:engine/model/node~Node} node Node to compare with.\n\t * @returns {Boolean}\n\t */\n\tisBefore( node ) {\n\t\t// Given node is not before this node if they are same.\n\t\tif ( this == node ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Return `false` if it is impossible to compare nodes.\n\t\tif ( this.root !== node.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst thisPath = this.getPath();\n\t\tconst nodePath = node.getPath();\n\n\t\tconst result = compareArrays( thisPath, nodePath );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'prefix':\n\t\t\t\treturn true;\n\n\t\t\tcase 'extension':\n\t\t\t\treturn false;\n\n\t\t\tdefault:\n\t\t\t\treturn thisPath[ result ] < nodePath[ result ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns whether this node is after given node. `false` is returned if nodes are in different trees (for example,\n\t * in different {@link module:engine/model/documentfragment~DocumentFragment}s).\n\t *\n\t * @param {module:engine/model/node~Node} node Node to compare with.\n\t * @returns {Boolean}\n\t */\n\tisAfter( node ) {\n\t\t// Given node is not before this node if they are same.\n\t\tif ( this == node ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Return `false` if it is impossible to compare nodes.\n\t\tif ( this.root !== node.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// In other cases, just check if the `node` is before, and return the opposite.\n\t\treturn !this.isBefore( node );\n\t}\n\n\t/**\n\t * Checks if the node has an attribute with given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on node, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this._attrs.has( key );\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on node.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this._attrs.get( key );\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this._attrs.entries();\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attribute keys.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this._attrs.keys();\n\t}\n\n\t/**\n\t * Converts `Node` to plain object and returns it.\n\t *\n\t * @returns {Object} `Node` converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = {};\n\n\t\t// Serializes attributes to the object.\n\t\t// attributes = { a: 'foo', b: 1, c: true }.\n\t\tif ( this._attrs.size ) {\n\t\t\tjson.attributes = Array.from( this._attrs ).reduce( ( result, attr ) => {\n\t\t\t\tresult[ attr[ 0 ] ] = attr[ 1 ];\n\n\t\t\t\treturn result;\n\t\t\t}, {} );\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t * This method is useful when processing model objects that are of unknown type. For example, a function\n\t * may return a {@link module:engine/model/documentfragment~DocumentFragment} or a {@link module:engine/model/node~Node}\n\t * that can be either a text node or an element. This method can be used to check what kind of object is returned.\n\t *\n\t *\t\tsomeObject.is( 'element' ); // -> true if this is an element\n\t *\t\tsomeObject.is( 'node' ); // -> true if this is a node (a text node or an element)\n\t *\t\tsomeObject.is( 'documentFragment' ); // -> true if this is a document fragment\n\t *\n\t * Since this method is also available on a range of view objects, you can prefix the type of the object with\n\t * `model:` or `view:` to check, for example, if this is the model's or view's element:\n\t *\n\t *\t\tmodelElement.is( 'model:element' ); // -> true\n\t *\t\tmodelElement.is( 'view:element' ); // -> false\n\t *\n\t * By using this method it is also possible to check a name of an element:\n\t *\n\t *\t\timageElement.is( 'image' ); // -> true\n\t *\t\timageElement.is( 'element', 'image' ); // -> same as above\n\t *\t\timageElement.is( 'model:element', 'image' ); // -> same as above, but more precise\n\t *\n\t * The list of model objects which implement the `is()` method:\n\t *\n\t * * {@link module:engine/model/node~Node#is `Node#is()`}\n\t * * {@link module:engine/model/text~Text#is `Text#is()`}\n\t * * {@link module:engine/model/element~Element#is `Element#is()`}\n\t * * {@link module:engine/model/rootelement~RootElement#is `RootElement#is()`}\n\t * * {@link module:engine/model/position~Position#is `Position#is()`}\n\t * * {@link module:engine/model/liveposition~LivePosition#is `LivePosition#is()`}\n\t * * {@link module:engine/model/range~Range#is `Range#is()`}\n\t * * {@link module:engine/model/liverange~LiveRange#is `LiveRange#is()`}\n\t * * {@link module:engine/model/documentfragment~DocumentFragment#is `DocumentFragment#is()`}\n\t * * {@link module:engine/model/selection~Selection#is `Selection#is()`}\n\t * * {@link module:engine/model/documentselection~DocumentSelection#is `DocumentSelection#is()`}\n\t * * {@link module:engine/model/markercollection~Marker#is `Marker#is()`}\n\t * * {@link module:engine/model/textproxy~TextProxy#is `TextProxy#is()`}\n\t *\n\t * @method #is\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'node' || type == 'model:node';\n\t}\n\n\t/**\n\t * Creates a copy of this node, that is a node with exactly same attributes, and returns it.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/node~Node} Node with same attributes as this node.\n\t */\n\t_clone() {\n\t\treturn new Node( this._attrs );\n\t}\n\n\t/**\n\t * Removes this node from it's parent.\n\t *\n\t * @see module:engine/model/writer~Writer#remove\n\t * @protected\n\t */\n\t_remove() {\n\t\tthis.parent._removeChildren( this.index );\n\t}\n\n\t/**\n\t * Sets attribute on the node. If attribute with the same key already is set, it's value is overwritten.\n\t *\n\t * @see module:engine/model/writer~Writer#setAttribute\n\t * @protected\n\t * @param {String} key Key of attribute to set.\n\t * @param {*} value Attribute value.\n\t */\n\t_setAttribute( key, value ) {\n\t\tthis._attrs.set( key, value );\n\t}\n\n\t/**\n\t * Removes all attributes from the node and sets given attributes.\n\t *\n\t * @see module:engine/model/writer~Writer#setAttributes\n\t * @protected\n\t * @param {Object} [attrs] Attributes to set. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t */\n\t_setAttributesTo( attrs ) {\n\t\tthis._attrs = toMap( attrs );\n\t}\n\n\t/**\n\t * Removes an attribute with given key from the node.\n\t *\n\t * @see module:engine/model/writer~Writer#removeAttribute\n\t * @protected\n\t * @param {String} key Key of attribute to remove.\n\t * @returns {Boolean} `true` if the attribute was set on the element, `false` otherwise.\n\t */\n\t_removeAttribute( key ) {\n\t\treturn this._attrs.delete( key );\n\t}\n\n\t/**\n\t * Removes all attributes from the node.\n\t *\n\t * @see module:engine/model/writer~Writer#clearAttributes\n\t * @protected\n\t */\n\t_clearAttributes() {\n\t\tthis._attrs.clear();\n\t}\n}\n\n/**\n * The node's parent does not contain this node.\n *\n * This error may be thrown from corrupted trees.\n *\n * @error model-node-not-found-in-parent\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/text\n */\n\nimport Node from './node';\n\n// @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' );\n\n/**\n * Model text node. Type of {@link module:engine/model/node~Node node} that contains {@link module:engine/model/text~Text#data text data}.\n *\n * **Important:** see {@link module:engine/model/node~Node} to read about restrictions using `Text` and `Node` API.\n *\n * **Note:** keep in mind that `Text` instances might indirectly got removed from model tree when model is changed.\n * This happens when {@link module:engine/model/writer~Writer model writer} is used to change model and the text node is merged with\n * another text node. Then, both text nodes are removed and a new text node is inserted into the model. Because of\n * this behavior, keeping references to `Text` is not recommended. Instead, consider creating\n * {@link module:engine/model/liveposition~LivePosition live position} placed before the text node.\n *\n * @extends module:engine/model/node~Node\n */\nexport default class Text extends Node {\n\t/**\n\t * Creates a text node.\n\t *\n\t * **Note:** Constructor of this class shouldn't be used directly in the code.\n\t * Use the {@link module:engine/model/writer~Writer#createText} method instead.\n\t *\n\t * @protected\n\t * @param {String} data Node's text.\n\t * @param {Object} [attrs] Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t */\n\tconstructor( data, attrs ) {\n\t\tsuper( attrs );\n\n\t\t/**\n\t\t * Text data contained in this text node.\n\t\t *\n\t\t * @protected\n\t\t * @type {String}\n\t\t */\n\t\tthis._data = data || '';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget offsetSize() {\n\t\treturn this.data.length;\n\t}\n\n\t/**\n\t * Returns a text data contained in the node.\n\t *\n\t * @readonly\n\t * @type {String}\n\t */\n\tget data() {\n\t\treturn this._data;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\ttext.is( 'text' ); // -> true\n\t *\t\ttext.is( 'node' ); // -> true\n\t *\t\ttext.is( 'model:text' ); // -> true\n\t *\t\ttext.is( 'model:node' ); // -> true\n\t *\n\t *\t\ttext.is( 'view:text' ); // -> false\n\t *\t\ttext.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check when `name` parameter is present.\n\t * Otherwise, it acts like the `name` parameter.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'text' || type == 'model:text' || super.is( type );\n\t}\n\n\t/**\n\t * Converts `Text` instance to plain object and returns it.\n\t *\n\t * @returns {Object} `Text` instance converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.data = this.data;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Creates a copy of this text node and returns it. Created text node has same text data and attributes as original text node.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/text~Text} `Text` instance created using given plain object.\n\t */\n\t_clone() {\n\t\treturn new Text( this.data, this.getAttributes() );\n\t}\n\n\t/**\n\t * Creates a `Text` instance from given plain object (i.e. parsed JSON string).\n\t *\n\t * @param {Object} json Plain object to be converted to `Text`.\n\t * @returns {module:engine/model/text~Text} `Text` instance created using given plain object.\n\t */\n\tstatic fromJSON( json ) {\n\t\treturn new Text( json.data, json.attributes );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( `ModelText: ${ this }, attrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelText: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/textproxy\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' );\n\n/**\n * `TextProxy` represents a part of {@link module:engine/model/text~Text text node}.\n *\n * Since {@link module:engine/model/position~Position positions} can be placed between characters of a text node,\n * {@link module:engine/model/range~Range ranges} may contain only parts of text nodes. When {@link module:engine/model/range~Range#getItems\n * getting items}\n * contained in such range, we need to represent a part of that text node, since returning the whole text node would be incorrect.\n * `TextProxy` solves this issue.\n *\n * `TextProxy` has an API similar to {@link module:engine/model/text~Text Text} and allows to do most of the common tasks performed\n * on model nodes.\n *\n * **Note:** Some `TextProxy` instances may represent whole text node, not just a part of it.\n * See {@link module:engine/model/textproxy~TextProxy#isPartial}.\n *\n * **Note:** `TextProxy` is not an instance of {@link module:engine/model/node~Node node}. Keep this in mind when using it as a\n * parameter of methods.\n *\n * **Note:** `TextProxy` is a readonly interface. If you want to perform changes on model data represented by a `TextProxy`\n * use {@link module:engine/model/writer~Writer model writer API}.\n *\n * **Note:** `TextProxy` instances are created on the fly, basing on the current state of model. Because of this, it is\n * highly unrecommended to store references to `TextProxy` instances. `TextProxy` instances are not refreshed when\n * model changes, so they might get invalidated. Instead, consider creating {@link module:engine/model/liveposition~LivePosition live\n * position}.\n *\n * `TextProxy` instances are created by {@link module:engine/model/treewalker~TreeWalker model tree walker}. You should not need to create\n * an instance of this class by your own.\n */\nexport default class TextProxy {\n\t/**\n\t * Creates a text proxy.\n\t *\n\t * @protected\n\t * @param {module:engine/model/text~Text} textNode Text node which part is represented by this text proxy.\n\t * @param {Number} offsetInText Offset in {@link module:engine/model/textproxy~TextProxy#textNode text node} from which the text proxy\n\t * starts.\n\t * @param {Number} length Text proxy length, that is how many text node's characters, starting from `offsetInText` it represents.\n\t * @constructor\n\t */\n\tconstructor( textNode, offsetInText, length ) {\n\t\t/**\n\t\t * Text node which part is represented by this text proxy.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/text~Text}\n\t\t */\n\t\tthis.textNode = textNode;\n\n\t\tif ( offsetInText < 0 || offsetInText > textNode.offsetSize ) {\n\t\t\t/**\n\t\t\t * Given `offsetInText` value is incorrect.\n\t\t\t *\n\t\t\t * @error model-textproxy-wrong-offsetintext\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-textproxy-wrong-offsetintext: Given offsetInText value is incorrect.', this );\n\t\t}\n\n\t\tif ( length < 0 || offsetInText + length > textNode.offsetSize ) {\n\t\t\t/**\n\t\t\t * Given `length` value is incorrect.\n\t\t\t *\n\t\t\t * @error model-textproxy-wrong-length\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-textproxy-wrong-length: Given length value is incorrect.', this );\n\t\t}\n\n\t\t/**\n\t\t * Text data represented by this text proxy.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.data = textNode.data.substring( offsetInText, offsetInText + length );\n\n\t\t/**\n\t\t * Offset in {@link module:engine/model/textproxy~TextProxy#textNode text node} from which the text proxy starts.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.offsetInText = offsetInText;\n\t}\n\n\t/**\n\t * Offset at which this text proxy starts in it's parent.\n\t *\n\t * @see module:engine/model/node~Node#startOffset\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget startOffset() {\n\t\treturn this.textNode.startOffset !== null ? this.textNode.startOffset + this.offsetInText : null;\n\t}\n\n\t/**\n\t * Offset size of this text proxy. Equal to the number of characters represented by the text proxy.\n\t *\n\t * @see module:engine/model/node~Node#offsetSize\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget offsetSize() {\n\t\treturn this.data.length;\n\t}\n\n\t/**\n\t * Offset at which this text proxy ends in it's parent.\n\t *\n\t * @see module:engine/model/node~Node#endOffset\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget endOffset() {\n\t\treturn this.startOffset !== null ? this.startOffset + this.offsetSize : null;\n\t}\n\n\t/**\n\t * Flag indicating whether `TextProxy` instance covers only part of the original {@link module:engine/model/text~Text text node}\n\t * (`true`) or the whole text node (`false`).\n\t *\n\t * This is `false` when text proxy starts at the very beginning of {@link module:engine/model/textproxy~TextProxy#textNode textNode}\n\t * ({@link module:engine/model/textproxy~TextProxy#offsetInText offsetInText} equals `0`) and text proxy sizes is equal to\n\t * text node size.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isPartial() {\n\t\treturn this.offsetSize !== this.textNode.offsetSize;\n\t}\n\n\t/**\n\t * Parent of this text proxy, which is same as parent of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tget parent() {\n\t\treturn this.textNode.parent;\n\t}\n\n\t/**\n\t * Root of this text proxy, which is same as root of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.textNode.root;\n\t}\n\n\t/**\n\t * {@link module:engine/model/document~Document Document} that owns text node represented by this text proxy or `null` if the text node\n\t * has no parent or is inside a {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment}.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/document~Document|null}\n\t */\n\tget document() {\n\t\treturn this.textNode.document;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\ttextProxy.is( 'textProxy' ); // -> true\n\t *\t\ttextProxy.is( 'model:textProxy' ); // -> true\n\t *\n\t *\t\ttextProxy.is( 'view:textProxy' ); // -> false\n\t *\t\ttextProxy.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'textProxy' || type == 'model:textProxy';\n\t}\n\n\t/**\n\t * Gets path to this text proxy.\n\t *\n\t * @see module:engine/model/node~Node#getPath\n\t * @returns {Array.<Number>}\n\t */\n\tgetPath() {\n\t\tconst path = this.textNode.getPath();\n\n\t\tif ( path.length > 0 ) {\n\t\t\tpath[ path.length - 1 ] += this.offsetInText;\n\t\t}\n\n\t\treturn path;\n\t}\n\n\t/**\n\t * Returns ancestors array of this text proxy.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` this text proxy will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from text proxy parent to root element,\n\t * otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this : this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t/**\n\t * Checks if this text proxy has an attribute for given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on text proxy, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this.textNode.hasAttribute( key );\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on text proxy.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this.textNode.getAttribute( key );\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attributes. Attributes are returned as arrays containing two\n\t * items. First one is attribute key and second is attribute value.\n\t *\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this.textNode.getAttributes();\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attribute keys.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this.textNode.getAttributeKeys();\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelTextProxy: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( `ModelTextProxy: ${ this }, ` +\n\t// @if CK_DEBUG_ENGINE // \t\t`attrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/nodelist\n */\n\nimport Node from './node';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Provides an interface to operate on a list of {@link module:engine/model/node~Node nodes}. `NodeList` is used internally\n * in classes like {@link module:engine/model/element~Element Element}\n * or {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment}.\n */\nexport default class NodeList {\n\t/**\n\t * Creates an empty node list.\n\t *\n\t * @protected\n\t * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes contained in this node list.\n\t */\n\tconstructor( nodes ) {\n\t\t/**\n\t\t * Nodes contained in this node list.\n\t\t *\n\t\t * @private\n\t\t * @member {Array.<module:engine/model/node~Node>}\n\t\t */\n\t\tthis._nodes = [];\n\n\t\tif ( nodes ) {\n\t\t\tthis._insertNodes( 0, nodes );\n\t\t}\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all nodes contained inside this node list.\n\t *\n\t * @returns {Iterable.<module:engine/model/node~Node>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._nodes[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Number of nodes contained inside this node list.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget length() {\n\t\treturn this._nodes.length;\n\t}\n\n\t/**\n\t * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all nodes contained inside this node list.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget maxOffset() {\n\t\treturn this._nodes.reduce( ( sum, node ) => sum + node.offsetSize, 0 );\n\t}\n\n\t/**\n\t * Gets the node at the given index. Returns `null` if incorrect index was passed.\n\t *\n\t * @param {Number} index Index of node.\n\t * @returns {module:engine/model/node~Node|null} Node at given index.\n\t */\n\tgetNode( index ) {\n\t\treturn this._nodes[ index ] || null;\n\t}\n\n\t/**\n\t * Returns an index of the given node. Returns `null` if given node is not inside this node list.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number|null} Child node's index.\n\t */\n\tgetNodeIndex( node ) {\n\t\tconst index = this._nodes.indexOf( node );\n\n\t\treturn index == -1 ? null : index;\n\t}\n\n\t/**\n\t * Returns the starting offset of given node. Starting offset is equal to the sum of\n\t * {@link module:engine/model/node~Node#offsetSize offset sizes} of all nodes that are before this node in this node list.\n\t *\n\t * @param {module:engine/model/node~Node} node Node to look for.\n\t * @returns {Number|null} Node's starting offset.\n\t */\n\tgetNodeStartOffset( node ) {\n\t\tconst index = this.getNodeIndex( node );\n\n\t\treturn index === null ? null : this._nodes.slice( 0, index ).reduce( ( sum, node ) => sum + node.offsetSize, 0 );\n\t}\n\n\t/**\n\t * Converts index to offset in node list.\n\t *\n\t * Returns starting offset of a node that is at given index. Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * `model-nodelist-index-out-of-bounds` if given index is less than `0` or more than {@link #length}.\n\t *\n\t * @param {Number} index Node's index.\n\t * @returns {Number} Node's starting offset.\n\t */\n\tindexToOffset( index ) {\n\t\tif ( index == this._nodes.length ) {\n\t\t\treturn this.maxOffset;\n\t\t}\n\n\t\tconst node = this._nodes[ index ];\n\n\t\tif ( !node ) {\n\t\t\t/**\n\t\t\t * Given index cannot be found in the node list.\n\t\t\t *\n\t\t\t * @error nodelist-index-out-of-bounds\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-nodelist-index-out-of-bounds: Given index cannot be found in the node list.', this );\n\t\t}\n\n\t\treturn this.getNodeStartOffset( node );\n\t}\n\n\t/**\n\t * Converts offset in node list to index.\n\t *\n\t * Returns index of a node that occupies given offset. Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * `model-nodelist-offset-out-of-bounds` if given offset is less than `0` or more than {@link #maxOffset}.\n\t *\n\t * @param {Number} offset Offset to look for.\n\t * @returns {Number} Index of a node that occupies given offset.\n\t */\n\toffsetToIndex( offset ) {\n\t\tlet totalOffset = 0;\n\n\t\tfor ( const node of this._nodes ) {\n\t\t\tif ( offset >= totalOffset && offset < totalOffset + node.offsetSize ) {\n\t\t\t\treturn this.getNodeIndex( node );\n\t\t\t}\n\n\t\t\ttotalOffset += node.offsetSize;\n\t\t}\n\n\t\tif ( totalOffset != offset ) {\n\t\t\t/**\n\t\t\t * Given offset cannot be found in the node list.\n\t\t\t *\n\t\t\t * @error model-nodelist-offset-out-of-bounds\n\t\t\t * @param {Number} offset\n\t\t\t * @param {module:engine/model/nodelist~NodeList} nodeList Stringified node list.\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-nodelist-offset-out-of-bounds: Given offset cannot be found in the node list.',\n\t\t\t\tthis,\n\t\t\t\t{\n\t\t\t\t\toffset,\n\t\t\t\t\tnodeList: this\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\treturn this.length;\n\t}\n\n\t/**\n\t * Inserts given nodes at given index.\n\t *\n\t * @protected\n\t * @param {Number} index Index at which nodes should be inserted.\n\t * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes to be inserted.\n\t */\n\t_insertNodes( index, nodes ) {\n\t\t// Validation.\n\t\tfor ( const node of nodes ) {\n\t\t\tif ( !( node instanceof Node ) ) {\n\t\t\t\t/**\n\t\t\t\t * Trying to insert an object which is not a Node instance.\n\t\t\t\t *\n\t\t\t\t * @error nodelist-insertNodes-not-node\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-nodelist-insertNodes-not-node: Trying to insert an object which is not a Node instance.',\n\t\t\t\t\tthis\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tthis._nodes.splice( index, 0, ...nodes );\n\t}\n\n\t/**\n\t * Removes one or more nodes starting at the given index.\n\t *\n\t * @protected\n\t * @param {Number} indexStart Index of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.\n\t */\n\t_removeNodes( indexStart, howMany = 1 ) {\n\t\treturn this._nodes.splice( indexStart, howMany );\n\t}\n\n\t/**\n\t * Converts `NodeList` instance to an array containing nodes that were inserted in the node list. Nodes\n\t * are also converted to their plain object representation.\n\t *\n\t * @returns {Array.<module:engine/model/node~Node>} `NodeList` instance converted to `Array`.\n\t */\n\ttoJSON() {\n\t\treturn this._nodes.map( node => node.toJSON() );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/element\n */\n\nimport Node from './node';\nimport NodeList from './nodelist';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\n// @if CK_DEBUG_ENGINE // const { stringifyMap, convertMapToStringifiedObject, convertMapToTags } = require( '../dev-utils/utils' );\n\n/**\n * Model element. Type of {@link module:engine/model/node~Node node} that has a {@link module:engine/model/element~Element#name name} and\n * {@link module:engine/model/element~Element#getChildren child nodes}.\n *\n * **Important**: see {@link module:engine/model/node~Node} to read about restrictions using `Element` and `Node` API.\n *\n * @extends module:engine/model/node~Node\n */\nexport default class Element extends Node {\n\t/**\n\t * Creates a model element.\n\t *\n\t * **Note:** Constructor of this class shouldn't be used directly in the code.\n\t * Use the {@link module:engine/model/writer~Writer#createElement} method instead.\n\t *\n\t * @protected\n\t * @param {String} name Element's name.\n\t * @param {Object} [attrs] Element's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t * @param {module:engine/model/node~Node|Iterable.<module:engine/model/node~Node>} [children]\n\t * One or more nodes to be inserted as children of created element.\n\t */\n\tconstructor( name, attrs, children ) {\n\t\tsuper( attrs );\n\n\t\t/**\n\t\t * Element name.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} module:engine/model/element~Element#name\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * List of children nodes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/nodelist~NodeList} module:engine/model/element~Element#_children\n\t\t */\n\t\tthis._children = new NodeList();\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\t}\n\n\t/**\n\t * Number of this element's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all of this element's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget maxOffset() {\n\t\treturn this._children.maxOffset;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this element, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this.childCount === 0;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\telement.is( 'element' ); // -> true\n\t *\t\telement.is( 'node' ); // -> true\n\t *\t\telement.is( 'model:element' ); // -> true\n\t *\t\telement.is( 'model:node' ); // -> true\n\t *\n\t *\t\telement.is( 'view:element' ); // -> false\n\t *\t\telement.is( 'documentSelection' ); // -> false\n\t *\n\t * Assuming that the object being checked is an element, you can also check its\n\t * {@link module:engine/model/element~Element#name name}:\n\t *\n\t *\t\telement.is( 'image' ); // -> true if this is an <image> element\n\t *\t\telement.is( 'element', 'image' ); // -> same as above\n\t *\t\ttext.is( 'image' ); -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check when `name` parameter is present.\n\t * Otherwise, it acts like the `name` parameter.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tconst cutType = type.replace( /^model:/, '' );\n\n\t\tif ( !name ) {\n\t\t\treturn cutType == 'element' || cutType == this.name || super.is( type );\n\t\t} else {\n\t\t\treturn cutType == 'element' && name == this.name;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the child at the given index.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/model/node~Node} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children.getNode( index );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all of this element's children.\n\t *\n\t * @returns {Iterable.<module:engine/model/node~Node>}\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns an index of the given child node. Returns `null` if given node is not a child of this element.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number} Child node's index in this element.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.getNodeIndex( node );\n\t}\n\n\t/**\n\t * Returns the starting offset of given child. Starting offset is equal to the sum of\n\t * {@link module:engine/model/node~Node#offsetSize offset sizes} of all node's siblings that are before it. Returns `null` if\n\t * given node is not a child of this element.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number} Child node's starting offset.\n\t */\n\tgetChildStartOffset( node ) {\n\t\treturn this._children.getNodeStartOffset( node );\n\t}\n\n\t/**\n\t * Returns index of a node that occupies given offset. If given offset is too low, returns `0`. If given offset is\n\t * too high, returns {@link module:engine/model/element~Element#getChildIndex index after last child}.\n\t *\n\t *\t\tconst textNode = new Text( 'foo' );\n\t *\t\tconst pElement = new Element( 'p' );\n\t *\t\tconst divElement = new Element( [ textNode, pElement ] );\n\t *\t\tdivElement.offsetToIndex( -1 ); // Returns 0, because offset is too low.\n\t *\t\tdivElement.offsetToIndex( 0 ); // Returns 0, because offset 0 is taken by `textNode` which is at index 0.\n\t *\t\tdivElement.offsetToIndex( 1 ); // Returns 0, because `textNode` has `offsetSize` equal to 3, so it occupies offset 1 too.\n\t *\t\tdivElement.offsetToIndex( 2 ); // Returns 0.\n\t *\t\tdivElement.offsetToIndex( 3 ); // Returns 1.\n\t *\t\tdivElement.offsetToIndex( 4 ); // Returns 2. There are no nodes at offset 4, so last available index is returned.\n\t *\n\t * @param {Number} offset Offset to look for.\n\t * @returns {Number}\n\t */\n\toffsetToIndex( offset ) {\n\t\treturn this._children.offsetToIndex( offset );\n\t}\n\n\t/**\n\t * Returns a descendant node by its path relative to this element.\n\t *\n\t *\t\t// <this>a<b>c</b></this>\n\t *\t\tthis.getNodeByPath( [ 0 ] ); // -> \"a\"\n\t *\t\tthis.getNodeByPath( [ 1 ] ); // -> <b>\n\t *\t\tthis.getNodeByPath( [ 1, 0 ] ); // -> \"c\"\n\t *\n\t * @param {Array.<Number>} relativePath Path of the node to find, relative to this element.\n\t * @returns {module:engine/model/node~Node}\n\t */\n\tgetNodeByPath( relativePath ) {\n\t\tlet node = this; // eslint-disable-line consistent-this\n\n\t\tfor ( const index of relativePath ) {\n\t\t\tnode = node.getChild( node.offsetToIndex( index ) );\n\t\t}\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Converts `Element` instance to plain object and returns it. Takes care of converting all of this element's children.\n\t *\n\t * @returns {Object} `Element` instance converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.name = this.name;\n\n\t\tif ( this._children.length > 0 ) {\n\t\t\tjson.children = [];\n\n\t\t\tfor ( const node of this._children ) {\n\t\t\t\tjson.children.push( node.toJSON() );\n\t\t\t}\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Creates a copy of this element and returns it. Created element has the same name and attributes as the original element.\n\t * If clone is deep, the original element's children are also cloned. If not, then empty element is removed.\n\t *\n\t * @protected\n\t * @param {Boolean} [deep=false] If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any child.\n\t */\n\t_clone( deep = false ) {\n\t\tconst children = deep ? Array.from( this._children ).map( node => node._clone( true ) ) : null;\n\n\t\treturn new Element( this.name, this.getAttributes(), children );\n\t}\n\n\t/**\n\t * {@link module:engine/model/element~Element#_insertChild Inserts} one or more nodes at the end of this element.\n\t *\n\t * @see module:engine/model/writer~Writer#append\n\t * @protected\n\t * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} nodes Nodes to be inserted.\n\t */\n\t_appendChild( nodes ) {\n\t\tthis._insertChild( this.childCount, nodes );\n\t}\n\n\t/**\n\t * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes\n\t * to this element.\n\t *\n\t * @see module:engine/model/writer~Writer#insert\n\t * @protected\n\t * @param {Number} index Index at which nodes should be inserted.\n\t * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.\n\t */\n\t_insertChild( index, items ) {\n\t\tconst nodes = normalize( items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\t\t}\n\n\t\tthis._children._insertNodes( index, nodes );\n\t}\n\n\t/**\n\t * Removes one or more nodes starting at the given index and sets\n\t * {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.\n\t *\n\t * @see module:engine/model/writer~Writer#remove\n\t * @protected\n\t * @param {Number} index Index of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tconst nodes = this._children._removeNodes( index, howMany );\n\n\t\tfor ( const node of nodes ) {\n\t\t\tnode.parent = null;\n\t\t}\n\n\t\treturn nodes;\n\t}\n\n\t/**\n\t * Creates an `Element` instance from given plain object (i.e. parsed JSON string).\n\t * Converts `Element` children to proper nodes.\n\t *\n\t * @param {Object} json Plain object to be converted to `Element`.\n\t * @returns {module:engine/model/element~Element} `Element` instance created using given plain object.\n\t */\n\tstatic fromJSON( json ) {\n\t\tlet children = null;\n\n\t\tif ( json.children ) {\n\t\t\tchildren = [];\n\n\t\t\tfor ( const child of json.children ) {\n\t\t\t\tif ( child.name ) {\n\t\t\t\t\t// If child has name property, it is an Element.\n\t\t\t\t\tchildren.push( Element.fromJSON( child ) );\n\t\t\t\t} else {\n\t\t\t\t\t// Otherwise, it is a Text node.\n\t\t\t\t\tchildren.push( Text.fromJSON( child ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn new Element( json.name, json.attributes, children );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `<${ this.rootName || this.name }>`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelElement: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( `ModelElement: ${ this }, ${ this.childCount } children,\n\t// @if CK_DEBUG_ENGINE //\t\tattrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logAll() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( '--------------------' );\n\t// @if CK_DEBUG_ENGINE //\n\t// @if CK_DEBUG_ENGINE // \tthis.logExtended();\n\t// @if CK_DEBUG_ENGINE //\tconsole.log( 'List of children:' );\n\t// @if CK_DEBUG_ENGINE //\n\t// @if CK_DEBUG_ENGINE // \tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE // \t\tchild.log();\n\t// @if CK_DEBUG_ENGINE // \t}\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // printTree( level = 0) {\n\t// @if CK_DEBUG_ENGINE // \tlet string = '';\n\n\t// @if CK_DEBUG_ENGINE // \tstring += '\\t'.repeat( level );\n\t// @if CK_DEBUG_ENGINE // \tstring += `<${ this.rootName || this.name }${ convertMapToTags( this.getAttributes() ) }>`;\n\n\t// @if CK_DEBUG_ENGINE // \tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE // \t\tstring += '\\n';\n\n\t// @if CK_DEBUG_ENGINE // \t\tif ( child.is( 'text' ) ) {\n\t// @if CK_DEBUG_ENGINE // \t\t\tconst textAttrs = convertMapToTags( child._attrs );\n\n\t// @if CK_DEBUG_ENGINE // \t\t\tstring += '\\t'.repeat( level + 1 );\n\n\t// @if CK_DEBUG_ENGINE // \t\t\tif ( textAttrs !== '' ) {\n\t// @if CK_DEBUG_ENGINE // \t\t\t\tstring += `<$text${ textAttrs }>` + child.data + '</$text>';\n\t// @if CK_DEBUG_ENGINE // \t\t\t} else {\n\t// @if CK_DEBUG_ENGINE // \t\t\t\tstring += child.data;\n\t// @if CK_DEBUG_ENGINE // \t\t\t}\n\t// @if CK_DEBUG_ENGINE // \t\t} else {\n\t// @if CK_DEBUG_ENGINE // \t\t\tstring += child.printTree( level + 1 );\n\t// @if CK_DEBUG_ENGINE // \t\t}\n\t// @if CK_DEBUG_ENGINE // \t}\n\n\t// @if CK_DEBUG_ENGINE // \tif ( this.childCount ) {\n\t// @if CK_DEBUG_ENGINE // \t\tstring += '\\n' + '\\t'.repeat( level );\n\t// @if CK_DEBUG_ENGINE // \t}\n\n\t// @if CK_DEBUG_ENGINE // \tstring += `</${ this.rootName || this.name }>`;\n\n\t// @if CK_DEBUG_ENGINE // \treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/model/item~Item|Iterable.<String|module:engine/model/item~Item>}\n// @returns {Iterable.<module:engine/model/node~Node>}\nfunction normalize( nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( node.data, node.getAttributes() );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/treewalker\n */\n\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport Element from './element';\nimport Position from './position';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Position iterator class. It allows to iterate forward and backward over the document.\n */\nexport default class TreeWalker {\n\t/**\n\t * Creates a range iterator. All parameters are optional, but you have to specify either `boundaries` or `startPosition`.\n\t *\n\t * @constructor\n\t * @param {Object} [options={}] Object with configuration.\n\t * @param {'forward'|'backward'} [options.direction='forward'] Walking direction.\n\t * @param {module:engine/model/range~Range} [options.boundaries=null] Range to define boundaries of the iterator.\n\t * @param {module:engine/model/position~Position} [options.startPosition] Starting position.\n\t * @param {Boolean} [options.singleCharacters=false] Flag indicating whether all consecutive characters with the same attributes\n\t * should be returned one by one as multiple {@link module:engine/model/textproxy~TextProxy} (`true`) objects or as one\n\t * {@link module:engine/model/textproxy~TextProxy} (`false`).\n\t * @param {Boolean} [options.shallow=false] Flag indicating whether iterator should enter elements or not. If the\n\t * iterator is shallow child nodes of any iterated node will not be returned along with `elementEnd` tag.\n\t * @param {Boolean} [options.ignoreElementEnd=false] Flag indicating whether iterator should ignore `elementEnd`\n\t * tags. If the option is true walker will not return a parent node of start position. If this option is `true`\n\t * each {@link module:engine/model/element~Element} will be returned once, while if the option is `false` they might be returned\n\t * twice: for `'elementStart'` and `'elementEnd'`.\n\t */\n\tconstructor( options = {} ) {\n\t\tif ( !options.boundaries && !options.startPosition ) {\n\t\t\t/**\n\t\t\t * Neither boundaries nor starting position of a `TreeWalker` have been defined.\n\t\t\t *\n\t\t\t * @error model-tree-walker-no-start-position\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-tree-walker-no-start-position: Neither boundaries nor starting position have been defined.',\n\t\t\t\tnull\n\t\t\t);\n\t\t}\n\n\t\tconst direction = options.direction || 'forward';\n\n\t\tif ( direction != 'forward' && direction != 'backward' ) {\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-tree-walker-unknown-direction: Only `backward` and `forward` direction allowed.',\n\t\t\t\toptions,\n\t\t\t\t{ direction }\n\t\t\t);\n\t\t}\n\n\t\t/**\n\t\t * Walking direction. Defaults `'forward'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'backward'|'forward'} module:engine/model/treewalker~TreeWalker#direction\n\t\t */\n\t\tthis.direction = direction;\n\n\t\t/**\n\t\t * Iterator boundaries.\n\t\t *\n\t\t * When the iterator is walking `'forward'` on the end of boundary or is walking `'backward'`\n\t\t * on the start of boundary, then `{ done: true }` is returned.\n\t\t *\n\t\t * If boundaries are not defined they are set before first and after last child of the root node.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range} module:engine/model/treewalker~TreeWalker#boundaries\n\t\t */\n\t\tthis.boundaries = options.boundaries || null;\n\n\t\t/**\n\t\t * Iterator position. This is always static position, even if the initial position was a\n\t\t * {@link module:engine/model/liveposition~LivePosition live position}. If start position is not defined then position depends\n\t\t * on {@link #direction}. If direction is `'forward'` position starts form the beginning, when direction\n\t\t * is `'backward'` position starts from the end.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position} module:engine/model/treewalker~TreeWalker#position\n\t\t */\n\t\tif ( options.startPosition ) {\n\t\t\tthis.position = options.startPosition.clone();\n\t\t} else {\n\t\t\tthis.position = Position._createAt( this.boundaries[ this.direction == 'backward' ? 'end' : 'start' ] );\n\t\t}\n\n\t\t// Reset position stickiness in case it was set to other value, as the stickiness is kept after cloning.\n\t\tthis.position.stickiness = 'toNone';\n\n\t\t/**\n\t\t * Flag indicating whether all consecutive characters with the same attributes should be\n\t\t * returned as one {@link module:engine/model/textproxy~TextProxy} (`true`) or one by one (`false`).\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/model/treewalker~TreeWalker#singleCharacters\n\t\t */\n\t\tthis.singleCharacters = !!options.singleCharacters;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should enter elements or not. If the iterator is shallow child nodes of any\n\t\t * iterated node will not be returned along with `elementEnd` tag.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/model/treewalker~TreeWalker#shallow\n\t\t */\n\t\tthis.shallow = !!options.shallow;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should ignore `elementEnd` tags. If the option is true walker will not\n\t\t * return a parent node of the start position. If this option is `true` each {@link module:engine/model/element~Element} will\n\t\t * be returned once, while if the option is `false` they might be returned twice:\n\t\t * for `'elementStart'` and `'elementEnd'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/model/treewalker~TreeWalker#ignoreElementEnd\n\t\t */\n\t\tthis.ignoreElementEnd = !!options.ignoreElementEnd;\n\n\t\t/**\n\t\t * Start boundary cached for optimization purposes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element} module:engine/model/treewalker~TreeWalker#_boundaryStartParent\n\t\t */\n\t\tthis._boundaryStartParent = this.boundaries ? this.boundaries.start.parent : null;\n\n\t\t/**\n\t\t * End boundary cached for optimization purposes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element} module:engine/model/treewalker~TreeWalker#_boundaryEndParent\n\t\t */\n\t\tthis._boundaryEndParent = this.boundaries ? this.boundaries.end.parent : null;\n\n\t\t/**\n\t\t * Parent of the most recently visited node. Cached for optimization purposes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t\t * module:engine/model/treewalker~TreeWalker#_visitedParent\n\t\t */\n\t\tthis._visitedParent = this.position.parent;\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<module:engine/model/treewalker~TreeWalkerValue>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Moves {@link #position} in the {@link #direction} skipping values as long as the callback function returns `true`.\n\t *\n\t * For example:\n\t *\n\t * \t\twalker.skip( value => value.type == 'text' ); // <paragraph>[]foo</paragraph> -> <paragraph>foo[]</paragraph>\n\t * \t\twalker.skip( () => true ); // Move the position to the end: <paragraph>[]foo</paragraph> -> <paragraph>foo</paragraph>[]\n\t * \t\twalker.skip( () => false ); // Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/model/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t */\n\tskip( skip ) {\n\t\tlet done, value, prevPosition, prevVisitedParent;\n\n\t\tdo {\n\t\t\tprevPosition = this.position;\n\t\t\tprevVisitedParent = this._visitedParent;\n\n\t\t\t( { done, value } = this.next() );\n\t\t} while ( !done && skip( value ) );\n\n\t\tif ( !done ) {\n\t\t\tthis.position = prevPosition;\n\t\t\tthis._visitedParent = prevVisitedParent;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the next tree walker's value.\n\t *\n\t * @returns {module:engine/model/treewalker~TreeWalkerValue} Next tree walker's value.\n\t */\n\tnext() {\n\t\tif ( this.direction == 'forward' ) {\n\t\t\treturn this._next();\n\t\t} else {\n\t\t\treturn this._previous();\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step forward in model. Moves the {@link #position} to the next position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done True if iterator is done.\n\t * @returns {module:engine/model/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_next() {\n\t\tconst previousPosition = this.position;\n\t\tconst position = this.position.clone();\n\t\tconst parent = this._visitedParent;\n\n\t\t// We are at the end of the root.\n\t\tif ( parent.parent === null && position.offset === parent.maxOffset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent === this._boundaryEndParent && position.offset == this.boundaries.end.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\tconst node = position.textNode ? position.textNode : position.nodeAfter;\n\n\t\tif ( node instanceof Element ) {\n\t\t\tif ( !this.shallow ) {\n\t\t\t\t// Manual operations on path internals for optimization purposes. Here and in the rest of the method.\n\t\t\t\tposition.path.push( 0 );\n\t\t\t\tthis._visitedParent = node;\n\t\t\t} else {\n\t\t\t\tposition.offset++;\n\t\t\t}\n\n\t\t\tthis.position = position;\n\n\t\t\treturn formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t} else if ( node instanceof Text ) {\n\t\t\tlet charactersCount;\n\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tcharactersCount = 1;\n\t\t\t} else {\n\t\t\t\tlet offset = node.endOffset;\n\n\t\t\t\tif ( this._boundaryEndParent == parent && this.boundaries.end.offset < offset ) {\n\t\t\t\t\toffset = this.boundaries.end.offset;\n\t\t\t\t}\n\n\t\t\t\tcharactersCount = offset - position.offset;\n\t\t\t}\n\n\t\t\tconst offsetInTextNode = position.offset - node.startOffset;\n\t\t\tconst item = new TextProxy( node, offsetInTextNode, charactersCount );\n\n\t\t\tposition.offset += charactersCount;\n\t\t\tthis.position = position;\n\n\t\t\treturn formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the end of current `parent`.\n\t\t\tposition.path.pop();\n\t\t\tposition.offset++;\n\t\t\tthis.position = position;\n\t\t\tthis._visitedParent = parent.parent;\n\n\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\treturn this._next();\n\t\t\t} else {\n\t\t\t\treturn formatReturnValue( 'elementEnd', parent, previousPosition, position );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step backward in model. Moves the {@link #position} to the previous position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done True if iterator is done.\n\t * @returns {module:engine/model/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_previous() {\n\t\tconst previousPosition = this.position;\n\t\tconst position = this.position.clone();\n\t\tconst parent = this._visitedParent;\n\n\t\t// We are at the beginning of the root.\n\t\tif ( parent.parent === null && position.offset === 0 ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent == this._boundaryStartParent && position.offset == this.boundaries.start.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just before current position\n\t\tconst node = position.textNode ? position.textNode : position.nodeBefore;\n\n\t\tif ( node instanceof Element ) {\n\t\t\tposition.offset--;\n\n\t\t\tif ( !this.shallow ) {\n\t\t\t\tposition.path.push( node.maxOffset );\n\t\t\t\tthis.position = position;\n\t\t\t\tthis._visitedParent = node;\n\n\t\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\t\treturn this._previous();\n\t\t\t\t} else {\n\t\t\t\t\treturn formatReturnValue( 'elementEnd', node, previousPosition, position );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t\t}\n\t\t} else if ( node instanceof Text ) {\n\t\t\tlet charactersCount;\n\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tcharactersCount = 1;\n\t\t\t} else {\n\t\t\t\tlet offset = node.startOffset;\n\n\t\t\t\tif ( this._boundaryStartParent == parent && this.boundaries.start.offset > offset ) {\n\t\t\t\t\toffset = this.boundaries.start.offset;\n\t\t\t\t}\n\n\t\t\t\tcharactersCount = position.offset - offset;\n\t\t\t}\n\n\t\t\tconst offsetInTextNode = position.offset - node.startOffset;\n\t\t\tconst item = new TextProxy( node, offsetInTextNode - charactersCount, charactersCount );\n\n\t\t\tposition.offset -= charactersCount;\n\t\t\tthis.position = position;\n\n\t\t\treturn formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the beginning of current `parent`.\n\t\t\tposition.path.pop();\n\t\t\tthis.position = position;\n\t\t\tthis._visitedParent = parent.parent;\n\n\t\t\treturn formatReturnValue( 'elementStart', parent, previousPosition, position, 1 );\n\t\t}\n\t}\n}\n\nfunction formatReturnValue( type, item, previousPosition, nextPosition, length ) {\n\treturn {\n\t\tdone: false,\n\t\tvalue: {\n\t\t\ttype,\n\t\t\titem,\n\t\t\tpreviousPosition,\n\t\t\tnextPosition,\n\t\t\tlength\n\t\t}\n\t};\n}\n\n/**\n * Type of the step made by {@link module:engine/model/treewalker~TreeWalker}.\n * Possible values: `'elementStart'` if walker is at the beginning of a node, `'elementEnd'` if walker is at the end of node,\n * `'character'` if walker traversed over a character, or `'text'` if walker traversed over multiple characters (available in\n * character merging mode, see {@link module:engine/model/treewalker~TreeWalker#constructor}).\n *\n * @typedef {'elementStart'|'elementEnd'|'character'|'text'} module:engine/model/treewalker~TreeWalkerValueType\n */\n\n/**\n * Object returned by {@link module:engine/model/treewalker~TreeWalker} when traversing tree model.\n *\n * @typedef {Object} module:engine/model/treewalker~TreeWalkerValue\n * @property {module:engine/model/treewalker~TreeWalkerValueType} type\n * @property {module:engine/model/item~Item} item Item between old and new positions of {@link module:engine/model/treewalker~TreeWalker}.\n * @property {module:engine/model/position~Position} previousPosition Previous position of the iterator.\n * * Forward iteration: For `'elementEnd'` it is the last position inside the element. For all other types it is the\n * position before the item.\n * * Backward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after item.\n * @property {module:engine/model/position~Position} nextPosition Next position of the iterator.\n * * Forward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after the item.\n * * Backward iteration: For `'elementEnd'` it is last position inside element. For all other types it is the position\n * before the item.\n * @property {Number} [length] Length of the item. For `'elementStart'` and `'character'` it is 1. For `'text'` it is\n * the length of the text. For `'elementEnd'` it is `undefined`.\n */\n\n/**\n * Tree walking directions.\n *\n * @typedef {'forward'|'backward'} module:engine/view/treewalker~TreeWalkerDirection\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/position\n */\n\nimport TreeWalker from './treewalker';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Text from './text';\nimport { last } from 'lodash-es';\n\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Represents a position in the model tree.\n *\n * A position is represented by its {@link module:engine/model/position~Position#root} and\n * a {@link module:engine/model/position~Position#path} in that root.\n *\n * You can create position instances via its constructor or the `createPosition*()` factory methods of\n * {@link module:engine/model/model~Model} and {@link module:engine/model/writer~Writer}.\n *\n * **Note:** Position is based on offsets, not indexes. This means that a position between two text nodes\n * `foo` and `bar` has offset `3`, not `1`. See {@link module:engine/model/position~Position#path} for more information.\n *\n * Since a position in the model is represented by a {@link module:engine/model/position~Position#root position root} and\n * {@link module:engine/model/position~Position#path position path} it is possible to create positions placed in non-existing places.\n * This requirement is important for operational transformation algorithms.\n *\n * Also, {@link module:engine/model/operation/operation~Operation operations}\n * kept in the {@link module:engine/model/document~Document#history document history}\n * are storing positions (and ranges) which were correct when those operations were applied, but may not be correct\n * after the document has changed.\n *\n * When changes are applied to the model, it may also happen that {@link module:engine/model/position~Position#parent position parent}\n * will change even if position path has not changed. Keep in mind, that if a position leads to non-existing element,\n * {@link module:engine/model/position~Position#parent} and some other properties and methods will throw errors.\n *\n * In most cases, position with wrong path is caused by an error in code, but it is sometimes needed, as described above.\n */\nexport default class Position {\n\t/**\n\t * Creates a position.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} root Root of the position.\n\t * @param {Array.<Number>} path Position path. See {@link module:engine/model/position~Position#path}.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * See {@link module:engine/model/position~PositionStickiness}.\n\t */\n\tconstructor( root, path, stickiness = 'toNone' ) {\n\t\tif ( !root.is( 'element' ) && !root.is( 'documentFragment' ) ) {\n\t\t\t/**\n\t\t\t * Position root is invalid.\n\t\t\t *\n\t\t\t * Positions can only be anchored in elements or document fragments.\n\t\t\t *\n\t\t\t * @error model-position-root-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-root-invalid: Position root invalid.',\n\t\t\t\troot\n\t\t\t);\n\t\t}\n\n\t\tif ( !( path instanceof Array ) || path.length === 0 ) {\n\t\t\t/**\n\t\t\t * Position path must be an array with at least one item.\n\t\t\t *\n\t\t\t * @error model-position-path-incorrect-format\n\t\t\t * @param path\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-path-incorrect-format: Position path must be an array with at least one item.',\n\t\t\t\troot,\n\t\t\t\t{ path }\n\t\t\t);\n\t\t}\n\n\t\t// Normalize the root and path (if element was passed).\n\t\tpath = root.getPath().concat( path );\n\t\troot = root.root;\n\n\t\t/**\n\t\t * Root of the position path.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t\t * module:engine/model/position~Position#root\n\t\t */\n\t\tthis.root = root;\n\n\t\t/**\n\t\t * Position of the node in the tree. **Path contains offsets, not indexes.**\n\t\t *\n\t\t * Position can be placed before, after or in a {@link module:engine/model/node~Node node} if that node has\n\t\t * {@link module:engine/model/node~Node#offsetSize} greater than `1`. Items in position path are\n\t\t * {@link module:engine/model/node~Node#startOffset starting offsets} of position ancestors, starting from direct root children,\n\t\t * down to the position offset in it's parent.\n\t\t *\n\t\t *\t\t ROOT\n\t\t *\t\t |- P before: [ 0 ] after: [ 1 ]\n\t\t *\t\t |- UL before: [ 1 ] after: [ 2 ]\n\t\t *\t\t |- LI before: [ 1, 0 ] after: [ 1, 1 ]\n\t\t *\t\t | |- foo before: [ 1, 0, 0 ] after: [ 1, 0, 3 ]\n\t\t *\t\t |- LI before: [ 1, 1 ] after: [ 1, 2 ]\n\t\t *\t\t |- bar before: [ 1, 1, 0 ] after: [ 1, 1, 3 ]\n\t\t *\n\t\t * `foo` and `bar` are representing {@link module:engine/model/text~Text text nodes}. Since text nodes has offset size\n\t\t * greater than `1` you can place position offset between their start and end:\n\t\t *\n\t\t *\t\t ROOT\n\t\t *\t\t |- P\n\t\t *\t\t |- UL\n\t\t *\t\t |- LI\n\t\t *\t\t | |- f^o|o ^ has path: [ 1, 0, 1 ] | has path: [ 1, 0, 2 ]\n\t\t *\t\t |- LI\n\t\t *\t\t |- b^a|r ^ has path: [ 1, 1, 1 ] | has path: [ 1, 1, 2 ]\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<Number>} module:engine/model/position~Position#path\n\t\t */\n\t\tthis.path = path;\n\n\t\t/**\n\t\t * Position stickiness. See {@link module:engine/model/position~PositionStickiness}.\n\t\t *\n\t\t * @member {module:engine/model/position~PositionStickiness} module:engine/model/position~Position#stickiness\n\t\t */\n\t\tthis.stickiness = stickiness;\n\t}\n\n\t/**\n\t * Offset at which this position is located in its {@link module:engine/model/position~Position#parent parent}. It is equal\n\t * to the last item in position {@link module:engine/model/position~Position#path path}.\n\t *\n\t * @type {Number}\n\t */\n\tget offset() {\n\t\treturn last( this.path );\n\t}\n\n\t/**\n\t * @param {Number} newOffset\n\t */\n\tset offset( newOffset ) {\n\t\tthis.path[ this.path.length - 1 ] = newOffset;\n\t}\n\n\t/**\n\t * Parent element of this position.\n\t *\n\t * Keep in mind that `parent` value is calculated when the property is accessed.\n\t * If {@link module:engine/model/position~Position#path position path}\n\t * leads to a non-existing element, `parent` property will throw error.\n\t *\n\t * Also it is a good idea to cache `parent` property if it is used frequently in an algorithm (i.e. in a long loop).\n\t *\n\t * @readonly\n\t * @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget parent() {\n\t\tlet parent = this.root;\n\n\t\tfor ( let i = 0; i < this.path.length - 1; i++ ) {\n\t\t\tparent = parent.getChild( parent.offsetToIndex( this.path[ i ] ) );\n\n\t\t\tif ( !parent ) {\n\t\t\t\tthrow new CKEditorError( 'model-position-path-incorrect: The position\\'s path is incorrect.', this, { position: this } );\n\t\t\t}\n\t\t}\n\n\t\tif ( parent.is( 'text' ) ) {\n\t\t\t/**\n\t\t\t * The position's path is incorrect. This means that a position does not point to\n\t\t\t * a correct place in the tree and hence, some of its methods and getters cannot work correctly.\n\t\t\t *\n\t\t\t * **Note**: Unlike DOM and view positions, in the model, the\n\t\t\t * {@link module:engine/model/position~Position#parent position's parent} is always an element or a document fragment.\n\t\t\t * The last offset in the {@link module:engine/model/position~Position#path position's path} is the point in this element where\n\t\t\t * this position points.\n\t\t\t *\n\t\t\t * Read more about model positions and offsets in\n\t\t\t * the {@glink framework/guides/architecture/editing-engine#indexes-and-offsets Editing engine architecture guide}.\n\t\t\t *\n\t\t\t * @error position-incorrect-path\n\t\t\t * @param {module:engine/model/position~Position} position The incorrect position.\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-position-path-incorrect: The position\\'s path is incorrect.', this, { position: this } );\n\t\t}\n\n\t\treturn parent;\n\t}\n\n\t/**\n\t * Position {@link module:engine/model/position~Position#offset offset} converted to an index in position's parent node. It is\n\t * equal to the {@link module:engine/model/node~Node#index index} of a node after this position. If position is placed\n\t * in text node, position index is equal to the index of that text node.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget index() {\n\t\treturn this.parent.offsetToIndex( this.offset );\n\t}\n\n\t/**\n\t * Returns {@link module:engine/model/text~Text text node} instance in which this position is placed or `null` if this\n\t * position is not in a text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/text~Text|null}\n\t */\n\tget textNode() {\n\t\tconst node = this.parent.getChild( this.index );\n\n\t\treturn ( node instanceof Text && node.startOffset < this.offset ) ? node : null;\n\t}\n\n\t/**\n\t * Node directly after this position or `null` if this position is in text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|null}\n\t */\n\tget nodeAfter() {\n\t\treturn this.textNode === null ? this.parent.getChild( this.index ) : null;\n\t}\n\n\t/**\n\t * Node directly before this position or `null` if this position is in text node.\n\t *\n\t * @readonly\n\t * @type {Node}\n\t */\n\tget nodeBefore() {\n\t\treturn this.textNode === null ? this.parent.getChild( this.index - 1 ) : null;\n\t}\n\n\t/**\n\t * Is `true` if position is at the beginning of its {@link module:engine/model/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtStart() {\n\t\treturn this.offset === 0;\n\t}\n\n\t/**\n\t * Is `true` if position is at the end of its {@link module:engine/model/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtEnd() {\n\t\treturn this.offset == this.parent.maxOffset;\n\t}\n\n\t/**\n\t * Checks whether this position is before or after given position.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {module:engine/model/position~PositionRelation}\n\t */\n\tcompareWith( otherPosition ) {\n\t\tif ( this.root != otherPosition.root ) {\n\t\t\treturn 'different';\n\t\t}\n\n\t\tconst result = compareArrays( this.path, otherPosition.path );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'same':\n\t\t\t\treturn 'same';\n\n\t\t\tcase 'prefix':\n\t\t\t\treturn 'before';\n\n\t\t\tcase 'extension':\n\t\t\t\treturn 'after';\n\n\t\t\tdefault:\n\t\t\t\treturn this.path[ result ] < otherPosition.path[ result ] ? 'before' : 'after';\n\t\t}\n\t}\n\n\t/**\n\t * Gets the farthest position which matches the callback using\n\t * {@link module:engine/model/treewalker~TreeWalker TreeWalker}.\n\t *\n\t * For example:\n\t *\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text' );\n\t * \t\t// <paragraph>[]foo</paragraph> -> <paragraph>foo[]</paragraph>\n\t *\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text', { direction: 'backward' } );\n\t * \t\t// <paragraph>foo[]</paragraph> -> <paragraph>[]foo</paragraph>\n\t *\n\t * \t\tgetLastMatchingPosition( value => false );\n\t * \t\t// Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/model/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t *\n\t * @returns {module:engine/model/position~Position} The position after the last item which matches the `skip` callback test.\n\t */\n\tgetLastMatchingPosition( skip, options = {} ) {\n\t\toptions.startPosition = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\t\ttreeWalker.skip( skip );\n\n\t\treturn treeWalker.position;\n\t}\n\n\t/**\n\t * Returns a path to this position's parent. Parent path is equal to position {@link module:engine/model/position~Position#path path}\n\t * but without the last item.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @returns {Array.<Number>} Path to the parent.\n\t */\n\tgetParentPath() {\n\t\treturn this.path.slice( 0, -1 );\n\t}\n\n\t/**\n\t * Returns ancestors array of this position, that is this position's parent and its ancestors.\n\t *\n\t * @returns {Array.<module:engine/model/item~Item>} Array with ancestors.\n\t */\n\tgetAncestors() {\n\t\tif ( this.parent.is( 'documentFragment' ) ) {\n\t\t\treturn [ this.parent ];\n\t\t} else {\n\t\t\treturn this.parent.getAncestors( { includeSelf: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the slice of two position {@link #path paths} which is identical. The {@link #root roots}\n\t * of these two paths must be identical.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} position The second position.\n\t * @returns {Array.<Number>} The common path.\n\t */\n\tgetCommonPath( position ) {\n\t\tif ( this.root != position.root ) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// We find on which tree-level start and end have the lowest common ancestor\n\t\tconst cmp = compareArrays( this.path, position.path );\n\t\t// If comparison returned string it means that arrays are same.\n\t\tconst diffAt = ( typeof cmp == 'string' ) ? Math.min( this.path.length, position.path.length ) : cmp;\n\n\t\treturn this.path.slice( 0, diffAt );\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both positions. The {@link #root roots} of these two positions must be identical.\n\t *\n\t * @param {module:engine/model/position~Position} position The second position.\n\t * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( position ) {\n\t\tconst ancestorsA = this.getAncestors();\n\t\tconst ancestorsB = position.getAncestors();\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Returns a new instance of `Position`, that has same {@link #parent parent} but it's offset\n\t * is shifted by `shift` value (can be a negative value).\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {Number} shift Offset shift. Can be a negative value.\n\t * @returns {module:engine/model/position~Position} Shifted position.\n\t */\n\tgetShiftedBy( shift ) {\n\t\tconst shifted = this.clone();\n\n\t\tconst offset = shifted.offset + shift;\n\t\tshifted.offset = offset < 0 ? 0 : offset;\n\n\t\treturn shifted;\n\t}\n\n\t/**\n\t * Checks whether this position is after given position.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @see module:engine/model/position~Position#isBefore\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if this position is after given position.\n\t */\n\tisAfter( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'after';\n\t}\n\n\t/**\n\t * Checks whether this position is before given position.\n\t *\n\t * **Note:** watch out when using negation of the value returned by this method, because the negation will also\n\t * be `true` if positions are in different roots and you might not expect this. You should probably use\n\t * `a.isAfter( b ) || a.isEqual( b )` or `!a.isBefore( p ) && a.root == b.root` in most scenarios. If your\n\t * condition uses multiple `isAfter` and `isBefore` checks, build them so they do not use negated values, i.e.:\n\t *\n\t *\t\tif ( a.isBefore( b ) && c.isAfter( d ) ) {\n\t *\t\t\t// do A.\n\t *\t\t} else {\n\t *\t\t\t// do B.\n\t *\t\t}\n\t *\n\t * or, if you have only one if-branch:\n\t *\n\t *\t\tif ( !( a.isBefore( b ) && c.isAfter( d ) ) {\n\t *\t\t\t// do B.\n\t *\t\t}\n\t *\n\t * rather than:\n\t *\n\t *\t\tif ( !a.isBefore( b ) || && !c.isAfter( d ) ) {\n\t *\t\t\t// do B.\n\t *\t\t} else {\n\t *\t\t\t// do A.\n\t *\t\t}\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if this position is before given position.\n\t */\n\tisBefore( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'before';\n\t}\n\n\t/**\n\t * Checks whether this position is equal to given position.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if positions are same.\n\t */\n\tisEqual( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'same';\n\t}\n\n\t/**\n\t * Checks whether this position is touching given position. Positions touch when there are no text nodes\n\t * or empty nodes in a range between them. Technically, those positions are not equal but in many cases\n\t * they are very similar or even indistinguishable.\n\t *\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if positions touch.\n\t */\n\tisTouching( otherPosition ) {\n\t\tlet left = null;\n\t\tlet right = null;\n\t\tconst compare = this.compareWith( otherPosition );\n\n\t\tswitch ( compare ) {\n\t\t\tcase 'same':\n\t\t\t\treturn true;\n\n\t\t\tcase 'before':\n\t\t\t\tleft = Position._createAt( this );\n\t\t\t\tright = Position._createAt( otherPosition );\n\t\t\t\tbreak;\n\n\t\t\tcase 'after':\n\t\t\t\tleft = Position._createAt( otherPosition );\n\t\t\t\tright = Position._createAt( this );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\n\t\t// Cached for optimization purposes.\n\t\tlet leftParent = left.parent;\n\n\t\twhile ( left.path.length + right.path.length ) {\n\t\t\tif ( left.isEqual( right ) ) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif ( left.path.length > right.path.length ) {\n\t\t\t\tif ( left.offset !== leftParent.maxOffset ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tleft.path = left.path.slice( 0, -1 );\n\t\t\t\tleftParent = leftParent.parent;\n\t\t\t\tleft.offset++;\n\t\t\t} else {\n\t\t\t\tif ( right.offset !== 0 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tright.path = right.path.slice( 0, -1 );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tposition.is( 'position' ); // -> true\n\t *\t\tposition.is( 'model:position' ); // -> true\n\t *\n\t *\t\tposition.is( 'view:position' ); // -> false\n\t *\t\tposition.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'position' || type == 'model:position';\n\t}\n\n\t/**\n\t * Checks if two positions are in the same parent.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} position Position to compare with.\n\t * @returns {Boolean} `true` if positions have the same parent, `false` otherwise.\n\t */\n\thasSameParentAs( position ) {\n\t\tif ( this.root !== position.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst thisParentPath = this.getParentPath();\n\t\tconst posParentPath = position.getParentPath();\n\n\t\treturn compareArrays( thisParentPath, posParentPath ) == 'same';\n\t}\n\n\t/**\n\t * Returns a copy of this position that is transformed by given `operation`.\n\t *\n\t * The new position's parameters are updated accordingly to the effect of the `operation`.\n\t *\n\t * For example, if `n` nodes are inserted before the position, the returned position {@link ~Position#offset} will be\n\t * increased by `n`. If the position was in a merged element, it will be accordingly moved to the new element, etc.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to transform by.\n\t * @returns {module:engine/model/position~Position} Transformed position.\n\t */\n\tgetTransformedByOperation( operation ) {\n\t\tlet result;\n\n\t\tswitch ( operation.type ) {\n\t\t\tcase 'insert':\n\t\t\t\tresult = this._getTransformedByInsertOperation( operation );\n\t\t\t\tbreak;\n\t\t\tcase 'move':\n\t\t\tcase 'remove':\n\t\t\tcase 'reinsert':\n\t\t\t\tresult = this._getTransformedByMoveOperation( operation );\n\t\t\t\tbreak;\n\t\t\tcase 'split':\n\t\t\t\tresult = this._getTransformedBySplitOperation( operation );\n\t\t\t\tbreak;\n\t\t\tcase 'merge':\n\t\t\t\tresult = this._getTransformedByMergeOperation( operation );\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tresult = Position._createAt( this );\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a copy of this position transformed by an insert operation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/insertoperation~InsertOperation} operation\n\t * @returns {module:engine/model/position~Position}\n\t */\n\t_getTransformedByInsertOperation( operation ) {\n\t\treturn this._getTransformedByInsertion( operation.position, operation.howMany );\n\t}\n\n\t/**\n\t * Returns a copy of this position transformed by a move operation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/moveoperation~MoveOperation} operation\n\t * @returns {module:engine/model/position~Position}\n\t */\n\t_getTransformedByMoveOperation( operation ) {\n\t\treturn this._getTransformedByMove( operation.sourcePosition, operation.targetPosition, operation.howMany );\n\t}\n\n\t/**\n\t * Returns a copy of this position transformed by a split operation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/splitoperation~SplitOperation} operation\n\t * @returns {module:engine/model/position~Position}\n\t */\n\t_getTransformedBySplitOperation( operation ) {\n\t\tconst movedRange = operation.movedRange;\n\n\t\tconst isContained = movedRange.containsPosition( this ) ||\n\t\t\t( movedRange.start.isEqual( this ) && this.stickiness == 'toNext' );\n\n\t\tif ( isContained ) {\n\t\t\treturn this._getCombined( operation.splitPosition, operation.moveTargetPosition );\n\t\t} else {\n\t\t\tif ( operation.graveyardPosition ) {\n\t\t\t\treturn this._getTransformedByMove( operation.graveyardPosition, operation.insertionPosition, 1 );\n\t\t\t} else {\n\t\t\t\treturn this._getTransformedByInsertion( operation.insertionPosition, 1 );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns a copy of this position transformed by merge operation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/mergeoperation~MergeOperation} operation\n\t * @returns {module:engine/model/position~Position}\n\t */\n\t_getTransformedByMergeOperation( operation ) {\n\t\tconst movedRange = operation.movedRange;\n\t\tconst isContained = movedRange.containsPosition( this ) || movedRange.start.isEqual( this );\n\n\t\tlet pos;\n\n\t\tif ( isContained ) {\n\t\t\tpos = this._getCombined( operation.sourcePosition, operation.targetPosition );\n\n\t\t\tif ( operation.sourcePosition.isBefore( operation.targetPosition ) ) {\n\t\t\t\t// Above happens during OT when the merged element is moved before the merged-to element.\n\t\t\t\tpos = pos._getTransformedByDeletion( operation.deletionPosition, 1 );\n\t\t\t}\n\t\t} else if ( this.isEqual( operation.deletionPosition ) ) {\n\t\t\tpos = Position._createAt( operation.deletionPosition );\n\t\t} else {\n\t\t\tpos = this._getTransformedByMove( operation.deletionPosition, operation.graveyardPosition, 1 );\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t/**\n\t * Returns a copy of this position that is updated by removing `howMany` nodes starting from `deletePosition`.\n\t * It may happen that this position is in a removed node. If that is the case, `null` is returned instead.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} deletePosition Position before the first removed node.\n\t * @param {Number} howMany How many nodes are removed.\n\t * @returns {module:engine/model/position~Position|null} Transformed position or `null`.\n\t */\n\t_getTransformedByDeletion( deletePosition, howMany ) {\n\t\tconst transformed = Position._createAt( this );\n\n\t\t// This position can't be affected if deletion was in a different root.\n\t\tif ( this.root != deletePosition.root ) {\n\t\t\treturn transformed;\n\t\t}\n\n\t\tif ( compareArrays( deletePosition.getParentPath(), this.getParentPath() ) == 'same' ) {\n\t\t\t// If nodes are removed from the node that is pointed by this position...\n\t\t\tif ( deletePosition.offset < this.offset ) {\n\t\t\t\t// And are removed from before an offset of that position...\n\t\t\t\tif ( deletePosition.offset + howMany > this.offset ) {\n\t\t\t\t\t// Position is in removed range, it's no longer in the tree.\n\t\t\t\t\treturn null;\n\t\t\t\t} else {\n\t\t\t\t\t// Decrement the offset accordingly.\n\t\t\t\t\ttransformed.offset -= howMany;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ( compareArrays( deletePosition.getParentPath(), this.getParentPath() ) == 'prefix' ) {\n\t\t\t// If nodes are removed from a node that is on a path to this position...\n\t\t\tconst i = deletePosition.path.length - 1;\n\n\t\t\tif ( deletePosition.offset <= this.path[ i ] ) {\n\t\t\t\t// And are removed from before next node of that path...\n\t\t\t\tif ( deletePosition.offset + howMany > this.path[ i ] ) {\n\t\t\t\t\t// If the next node of that path is removed return null\n\t\t\t\t\t// because the node containing this position got removed.\n\t\t\t\t\treturn null;\n\t\t\t\t} else {\n\t\t\t\t\t// Otherwise, decrement index on that path.\n\t\t\t\t\ttransformed.path[ i ] -= howMany;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn transformed;\n\t}\n\n\t/**\n\t * Returns a copy of this position that is updated by inserting `howMany` nodes at `insertPosition`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} insertPosition Position where nodes are inserted.\n\t * @param {Number} howMany How many nodes are inserted.\n\t * @returns {module:engine/model/position~Position} Transformed position.\n\t */\n\t_getTransformedByInsertion( insertPosition, howMany ) {\n\t\tconst transformed = Position._createAt( this );\n\n\t\t// This position can't be affected if insertion was in a different root.\n\t\tif ( this.root != insertPosition.root ) {\n\t\t\treturn transformed;\n\t\t}\n\n\t\tif ( compareArrays( insertPosition.getParentPath(), this.getParentPath() ) == 'same' ) {\n\t\t\t// If nodes are inserted in the node that is pointed by this position...\n\t\t\tif ( insertPosition.offset < this.offset || ( insertPosition.offset == this.offset && this.stickiness != 'toPrevious' ) ) {\n\t\t\t\t// And are inserted before an offset of that position...\n\t\t\t\t// \"Push\" this positions offset.\n\t\t\t\ttransformed.offset += howMany;\n\t\t\t}\n\t\t} else if ( compareArrays( insertPosition.getParentPath(), this.getParentPath() ) == 'prefix' ) {\n\t\t\t// If nodes are inserted in a node that is on a path to this position...\n\t\t\tconst i = insertPosition.path.length - 1;\n\n\t\t\tif ( insertPosition.offset <= this.path[ i ] ) {\n\t\t\t\t// And are inserted before next node of that path...\n\t\t\t\t// \"Push\" the index on that path.\n\t\t\t\ttransformed.path[ i ] += howMany;\n\t\t\t}\n\t\t}\n\n\t\treturn transformed;\n\t}\n\n\t/**\n\t * Returns a copy of this position that is updated by moving `howMany` nodes from `sourcePosition` to `targetPosition`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} sourcePosition Position before the first element to move.\n\t * @param {module:engine/model/position~Position} targetPosition Position where moved elements will be inserted.\n\t * @param {Number} howMany How many consecutive nodes to move, starting from `sourcePosition`.\n\t * @returns {module:engine/model/position~Position} Transformed position.\n\t */\n\t_getTransformedByMove( sourcePosition, targetPosition, howMany ) {\n\t\t// Update target position, as it could be affected by nodes removal.\n\t\ttargetPosition = targetPosition._getTransformedByDeletion( sourcePosition, howMany );\n\n\t\tif ( sourcePosition.isEqual( targetPosition ) ) {\n\t\t\t// If `targetPosition` is equal to `sourcePosition` this isn't really any move. Just return position as it is.\n\t\t\treturn Position._createAt( this );\n\t\t}\n\n\t\t// Moving a range removes nodes from their original position. We acknowledge this by proper transformation.\n\t\tconst transformed = this._getTransformedByDeletion( sourcePosition, howMany );\n\n\t\tconst isMoved = transformed === null ||\n\t\t\t( sourcePosition.isEqual( this ) && this.stickiness == 'toNext' ) ||\n\t\t\t( sourcePosition.getShiftedBy( howMany ).isEqual( this ) && this.stickiness == 'toPrevious' );\n\n\t\tif ( isMoved ) {\n\t\t\t// This position is inside moved range (or sticks to it).\n\t\t\t// In this case, we calculate a combination of this position, move source position and target position.\n\t\t\treturn this._getCombined( sourcePosition, targetPosition );\n\t\t} else {\n\t\t\t// This position is not inside a removed range.\n\t\t\t//\n\t\t\t// In next step, we simply reflect inserting `howMany` nodes, which might further affect the position.\n\t\t\treturn transformed._getTransformedByInsertion( targetPosition, howMany );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a new position that is a combination of this position and given positions.\n\t *\n\t * The combined position is a copy of this position transformed by moving a range starting at `source` position\n\t * to the `target` position. It is expected that this position is inside the moved range.\n\t *\n\t * Example:\n\t *\n\t *\t\tlet original = model.createPositionFromPath( root, [ 2, 3, 1 ] );\n\t *\t\tlet source = model.createPositionFromPath( root, [ 2, 2 ] );\n\t *\t\tlet target = model.createPositionFromPath( otherRoot, [ 1, 1, 3 ] );\n\t *\t\toriginal._getCombined( source, target ); // path is [ 1, 1, 4, 1 ], root is `otherRoot`\n\t *\n\t * Explanation:\n\t *\n\t * We have a position `[ 2, 3, 1 ]` and move some nodes from `[ 2, 2 ]` to `[ 1, 1, 3 ]`. The original position\n\t * was inside moved nodes and now should point to the new place. The moved nodes will be after\n\t * positions `[ 1, 1, 3 ]`, `[ 1, 1, 4 ]`, `[ 1, 1, 5 ]`. Since our position was in the second moved node,\n\t * the transformed position will be in a sub-tree of a node at `[ 1, 1, 4 ]`. Looking at original path, we\n\t * took care of `[ 2, 3 ]` part of it. Now we have to add the rest of the original path to the transformed path.\n\t * Finally, the transformed position will point to `[ 1, 1, 4, 1 ]`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} source Beginning of the moved range.\n\t * @param {module:engine/model/position~Position} target Position where the range is moved.\n\t * @returns {module:engine/model/position~Position} Combined position.\n\t */\n\t_getCombined( source, target ) {\n\t\tconst i = source.path.length - 1;\n\n\t\t// The first part of a path to combined position is a path to the place where nodes were moved.\n\t\tconst combined = Position._createAt( target );\n\t\tcombined.stickiness = this.stickiness;\n\n\t\t// Then we have to update the rest of the path.\n\n\t\t// Fix the offset because this position might be after `from` position and we have to reflect that.\n\t\tcombined.offset = combined.offset + this.path[ i ] - source.offset;\n\n\t\t// Then, add the rest of the path.\n\t\t// If this position is at the same level as `from` position nothing will get added.\n\t\tcombined.path = combined.path.concat( this.path.slice( i + 1 ) );\n\n\t\treturn combined;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\treturn {\n\t\t\troot: this.root.toJSON(),\n\t\t\tpath: Array.from( this.path ),\n\t\t\tstickiness: this.stickiness\n\t\t};\n\t}\n\n\t/**\n\t * Returns a new position that is equal to current position.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.root, this.path, this.stickiness );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/model/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/model/item~Item model item} and `'before'` or `'after'` (sets position before or after given model item).\n\t *\n\t * This method is a shortcut to other factory methods such as:\n\t *\n\t * * {@link module:engine/model/position~Position._createBefore},\n\t * * {@link module:engine/model/position~Position._createAfter}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when the\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness. Used only when the\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t * @protected\n\t */\n\tstatic _createAt( itemOrPosition, offset, stickiness = 'toNone' ) {\n\t\tif ( itemOrPosition instanceof Position ) {\n\t\t\treturn new Position( itemOrPosition.root, itemOrPosition.path, itemOrPosition.stickiness );\n\t\t} else {\n\t\t\tconst node = itemOrPosition;\n\n\t\t\tif ( offset == 'end' ) {\n\t\t\t\toffset = node.maxOffset;\n\t\t\t} else if ( offset == 'before' ) {\n\t\t\t\treturn this._createBefore( node, stickiness );\n\t\t\t} else if ( offset == 'after' ) {\n\t\t\t\treturn this._createAfter( node, stickiness );\n\t\t\t} else if ( offset !== 0 && !offset ) {\n\t\t\t\t/**\n\t\t\t\t * {@link module:engine/model/model~Model#createPositionAt `Model#createPositionAt()`}\n\t\t\t\t * requires the offset to be specified when the first parameter is a model item.\n\t\t\t\t *\n\t\t\t\t * @error model-createPositionAt-offset-required\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-createPositionAt-offset-required: ' +\n\t\t\t\t\t'Model#createPositionAt() requires the offset when the first parameter is a model item.',\n\t\t\t\t\t[ this, itemOrPosition ]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( !node.is( 'element' ) && !node.is( 'documentFragment' ) ) {\n\t\t\t\t/**\n\t\t\t\t * Position parent have to be a model element or model document fragment.\n\t\t\t\t *\n\t\t\t\t * @error model-position-parent-incorrect\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-position-parent-incorrect: Position parent have to be a element or document fragment.',\n\t\t\t\t\t[ this, itemOrPosition ]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst path = node.getPath();\n\n\t\t\tpath.push( offset );\n\n\t\t\treturn new this( node.root, path, stickiness );\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new position, after given {@link module:engine/model/item~Item model item}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item after which the position should be placed.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * @returns {module:engine/model/position~Position}\n\t * @protected\n\t */\n\tstatic _createAfter( item, stickiness ) {\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You can not make a position after a root element.\n\t\t\t *\n\t\t\t * @error model-position-after-root\n\t\t\t * @param {module:engine/model/item~Item} root\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-after-root: You cannot make a position after root.',\n\t\t\t\t[ this, item ],\n\t\t\t\t{ root: item }\n\t\t\t);\n\t\t}\n\n\t\treturn this._createAt( item.parent, item.endOffset, stickiness );\n\t}\n\n\t/**\n\t * Creates a new position, before the given {@link module:engine/model/item~Item model item}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item before which the position should be placed.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * @returns {module:engine/model/position~Position}\n\t * @protected\n\t */\n\tstatic _createBefore( item, stickiness ) {\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You can not make a position before a root element.\n\t\t\t *\n\t\t\t * @error model-position-before-root\n\t\t\t * @param {module:engine/model/item~Item} root\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-before-root: You cannot make a position before root.',\n\t\t\t\titem,\n\t\t\t\t{ root: item }\n\t\t\t);\n\t\t}\n\n\t\treturn this._createAt( item.parent, item.startOffset, stickiness );\n\t}\n\n\t/**\n\t * Creates a `Position` instance from given plain object (i.e. parsed JSON string).\n\t *\n\t * @param {Object} json Plain object to be converted to `Position`.\n\t * @param {module:engine/model/document~Document} doc Document object that will be position owner.\n\t * @returns {module:engine/model/position~Position} `Position` instance created using given plain object.\n\t */\n\tstatic fromJSON( json, doc ) {\n\t\tif ( json.root === '$graveyard' ) {\n\t\t\tconst pos = new Position( doc.graveyard, json.path );\n\t\t\tpos.stickiness = json.stickiness;\n\n\t\t\treturn pos;\n\t\t}\n\n\t\tif ( !doc.getRoot( json.root ) ) {\n\t\t\t/**\n\t\t\t * Cannot create position for document. Root with specified name does not exist.\n\t\t\t *\n\t\t\t * @error model-position-fromjson-no-root\n\t\t\t * @param {String} rootName\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-fromjson-no-root: Cannot create position for document. Root with specified name does not exist.',\n\t\t\t\tdoc,\n\t\t\t\t{ rootName: json.root }\n\t\t\t);\n\t\t}\n\n\t\treturn new Position( doc.getRoot( json.root ), json.path, json.stickiness );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `${ this.root } [ ${ this.path.join( ', ' ) } ]`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelPosition: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n/**\n * A flag indicating whether this position is `'before'` or `'after'` or `'same'` as given position.\n * If positions are in different roots `'different'` flag is returned.\n *\n * @typedef {String} module:engine/model/position~PositionRelation\n */\n\n/**\n * Represents how position is \"sticking\" with neighbour nodes. Used to define how position should be transformed (moved)\n * in edge cases. Possible values: `'toNone'`, `'toNext'`, `'toPrevious'`.\n *\n * Examples:\n *\n *\t\tInsert. Position is at | and nodes are inserted at the same position, marked as ^:\n *\n *\t\t- sticks to none: <p>f^|oo</p> -> <p>fbar|oo</p>\n *\t\t- sticks to next node: <p>f^|oo</p> -> <p>fbar|oo</p>\n *\t\t- sticks to previous node: <p>f|^oo</p> -> <p>f|baroo</p>\n *\n *\n *\t\tMove. Position is at | and range [oo] is moved to position ^:\n *\n *\t\t- sticks to none: <p>f|[oo]</p><p>b^ar</p> -> <p>f|</p><p>booar</p>\n *\t\t- sticks to none: <p>f[oo]|</p><p>b^ar</p> -> <p>f|</p><p>booar</p>\n *\n *\t\t- sticks to next node: <p>f|[oo]</p><p>b^ar</p> -> <p>f</p><p>b|ooar</p>\n *\t\t- sticks to next node: <p>f[oo]|</p><p>b^ar</p> -> <p>f|</p><p>booar</p>\n *\n *\t\t- sticks to previous node: <p>f|[oo]</p><p>b^ar</p> -> <p>f|</p><p>booar</p>\n *\t\t- sticks to previous node: <p>f[oo]|</p><p>b^ar</p> -> <p>f</p><p>boo|ar</p>\n *\n * @typedef {String} module:engine/model/position~PositionStickiness\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/range\n */\n\nimport Position from './position';\nimport TreeWalker from './treewalker';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n\n/**\n * Represents a range in the model tree.\n *\n * A range is defined by its {@link module:engine/model/range~Range#start} and {@link module:engine/model/range~Range#end}\n * positions.\n *\n * You can create range instances via its constructor or the `createRange*()` factory methods of\n * {@link module:engine/model/model~Model} and {@link module:engine/model/writer~Writer}.\n */\nexport default class Range {\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * @param {module:engine/model/position~Position} start Start position.\n\t * @param {module:engine/model/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t */\n\tconstructor( start, end = null ) {\n\t\t/**\n\t\t * Start position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position}\n\t\t */\n\t\tthis.start = Position._createAt( start );\n\n\t\t/**\n\t\t * End position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position}\n\t\t */\n\t\tthis.end = end ? Position._createAt( end ) : Position._createAt( start );\n\n\t\t// If the range is collapsed, treat in a similar way as a position and set its boundaries stickiness to 'toNone'.\n\t\t// In other case, make the boundaries stick to the \"inside\" of the range.\n\t\tthis.start.stickiness = this.isCollapsed ? 'toNone' : 'toNext';\n\t\tthis.end.stickiness = this.isCollapsed ? 'toNone' : 'toPrevious';\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all {@link module:engine/model/item~Item items} that are in this range and returns\n\t * them together with additional information like length or {@link module:engine/model/position~Position positions},\n\t * grouped as {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t * It iterates over all {@link module:engine/model/textproxy~TextProxy text contents} that are inside the range\n\t * and all the {@link module:engine/model/element~Element}s that are entered into when iterating over this range.\n\t *\n\t * This iterator uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range\n\t * and `ignoreElementEnd` option set to `true`.\n\t *\n\t * @returns {Iterable.<module:engine/model/treewalker~TreeWalkerValue>}\n\t */\n\t* [ Symbol.iterator ]() {\n\t\tyield* new TreeWalker( { boundaries: this, ignoreElementEnd: true } );\n\t}\n\n\t/**\n\t * Returns whether the range is collapsed, that is if {@link #start} and\n\t * {@link #end} positions are equal.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this.start.isEqual( this.end );\n\t}\n\n\t/**\n\t * Returns whether this range is flat, that is if {@link #start} position and\n\t * {@link #end} position are in the same {@link module:engine/model/position~Position#parent}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isFlat() {\n\t\tconst startParentPath = this.start.getParentPath();\n\t\tconst endParentPath = this.end.getParentPath();\n\n\t\treturn compareArrays( startParentPath, endParentPath ) == 'same';\n\t}\n\n\t/**\n\t * Range root element.\n\t *\n\t * @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.start.root;\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link module:engine/model/position~Position position}.\n\t *\n\t * @param {module:engine/model/position~Position} position Position to check.\n\t * @returns {Boolean} `true` if given {@link module:engine/model/position~Position position} is contained\n\t * in this range,`false` otherwise.\n\t */\n\tcontainsPosition( position ) {\n\t\treturn position.isAfter( this.start ) && position.isBefore( this.end );\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link ~Range range}.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to check.\n\t * @param {Boolean} [loose=false] Whether the check is loose or strict. If the check is strict (`false`), compared range cannot\n\t * start or end at the same position as this range boundaries. If the check is loose (`true`), compared range can start, end or\n\t * even be equal to this range. Note that collapsed ranges are always compared in strict mode.\n\t * @returns {Boolean} `true` if given {@link ~Range range} boundaries are contained by this range, `false` otherwise.\n\t */\n\tcontainsRange( otherRange, loose = false ) {\n\t\tif ( otherRange.isCollapsed ) {\n\t\t\tloose = false;\n\t\t}\n\n\t\tconst containsStart = this.containsPosition( otherRange.start ) || ( loose && this.start.isEqual( otherRange.start ) );\n\t\tconst containsEnd = this.containsPosition( otherRange.end ) || ( loose && this.end.isEqual( otherRange.end ) );\n\n\t\treturn containsStart && containsEnd;\n\t}\n\n\t/**\n\t * Checks whether given {@link module:engine/model/item~Item} is inside this range.\n\t *\n\t * @param {module:engine/model/item~Item} item Model item to check.\n\t */\n\tcontainsItem( item ) {\n\t\tconst pos = Position._createBefore( item );\n\n\t\treturn this.containsPosition( pos ) || this.start.isEqual( pos );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\trange.is( 'range' ); // -> true\n\t *\t\trange.is( 'model:range' ); // -> true\n\t *\n\t *\t\trange.is( 'view:range' ); // -> false\n\t *\t\trange.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'range' || type == 'model:range';\n\t}\n\n\t/**\n\t * Two ranges are equal if their {@link #start} and {@link #end} positions are equal.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges are equal, `false` otherwise.\n\t */\n\tisEqual( otherRange ) {\n\t\treturn this.start.isEqual( otherRange.start ) && this.end.isEqual( otherRange.end );\n\t}\n\n\t/**\n\t * Checks and returns whether this range intersects with given range.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges intersect, `false` otherwise.\n\t */\n\tisIntersecting( otherRange ) {\n\t\treturn this.start.isBefore( otherRange.end ) && this.end.isAfter( otherRange.start );\n\t}\n\n\t/**\n\t * Computes which part(s) of this {@link ~Range range} is not a part of given {@link ~Range range}.\n\t * Returned array contains zero, one or two {@link ~Range ranges}.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 5 ] ) );\n\t *\t\tlet transformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has no ranges because `otherRange` contains `range`\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 3 ] ) );\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has one range: from [ 3 ] to [ 4, 0, 1 ]\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 4 ] ) );\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has two ranges: from [ 2, 7 ] to [ 3 ] and from [ 4 ] to [ 4, 0, 1 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to differentiate against.\n\t * @returns {Array.<module:engine/model/range~Range>} The difference between ranges.\n\t */\n\tgetDifference( otherRange ) {\n\t\tconst ranges = [];\n\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect.\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the start to the middle of this range.\n\t\t\t\tranges.push( new Range( this.start, otherRange.start ) );\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the middle of this range to the end.\n\t\t\t\tranges.push( new Range( otherRange.end, this.end ) );\n\t\t\t}\n\t\t} else {\n\t\t\t// Ranges do not intersect, return the original range.\n\t\t\tranges.push( new Range( this.start, this.end ) );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an intersection of this {@link ~Range range} and given {@link ~Range range}.\n\t * Intersection is a common part of both of those ranges. If ranges has no common part, returns `null`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 2 ] ) );\n\t *\t\tlet transformed = range.getIntersection( otherRange ); // null - ranges have no common part\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 5 ] ) );\n\t *\t\ttransformed = range.getIntersection( otherRange ); // range from [ 3 ] to [ 4, 0, 1 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to check for intersection.\n\t * @returns {module:engine/model/range~Range|null} A common part of given ranges or `null` if ranges have no common part.\n\t */\n\tgetIntersection( otherRange ) {\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect, so a common range will be returned.\n\t\t\t// At most, it will be same as this range.\n\t\t\tlet commonRangeStart = this.start;\n\t\t\tlet commonRangeEnd = this.end;\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means thaNt we have to\n\t\t\t\t// shrink common range to the given range start.\n\t\t\t\tcommonRangeStart = otherRange.start;\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// shrink common range to the given range end.\n\t\t\t\tcommonRangeEnd = otherRange.end;\n\t\t\t}\n\n\t\t\treturn new Range( commonRangeStart, commonRangeEnd );\n\t\t}\n\n\t\t// Ranges do not intersect, so they do not have common part.\n\t\treturn null;\n\t}\n\n\t/**\n\t * Computes and returns the smallest set of {@link #isFlat flat} ranges, that covers this range in whole.\n\t *\n\t * See an example of a model structure (`[` and `]` are range boundaries):\n\t *\n\t *\t\troot root\n\t *\t\t |- element DIV DIV P2 P3 DIV\n\t *\t\t | |- element H H P1 f o o b a r H P4\n\t *\t\t | | |- \"fir[st\" fir[st lorem se]cond ipsum\n\t *\t\t | |- element P1\n\t *\t\t | | |- \"lorem\" ||\n\t *\t\t |- element P2 ||\n\t *\t\t | |- \"foo\" VV\n\t *\t\t |- element P3\n\t *\t\t | |- \"bar\" root\n\t *\t\t |- element DIV DIV [P2 P3] DIV\n\t *\t\t | |- element H H [P1] f o o b a r H P4\n\t *\t\t | | |- \"se]cond\" fir[st] lorem [se]cond ipsum\n\t *\t\t | |- element P4\n\t *\t\t | | |- \"ipsum\"\n\t *\n\t * As it can be seen, letters contained in the range are: `stloremfoobarse`, spread across different parents.\n\t * We are looking for minimal set of flat ranges that contains the same nodes.\n\t *\n\t * Minimal flat ranges for above range `( [ 0, 0, 3 ], [ 3, 0, 2 ] )` will be:\n\t *\n\t *\t\t( [ 0, 0, 3 ], [ 0, 0, 5 ] ) = \"st\"\n\t *\t\t( [ 0, 1 ], [ 0, 2 ] ) = element P1 (\"lorem\")\n\t *\t\t( [ 1 ], [ 3 ] ) = element P2, element P3 (\"foobar\")\n\t *\t\t( [ 3, 0, 0 ], [ 3, 0, 2 ] ) = \"se\"\n\t *\n\t * **Note:** if an {@link module:engine/model/element~Element element} is not wholly contained in this range, it won't be returned\n\t * in any of the returned flat ranges. See in the example how `H` elements at the beginning and at the end of the range\n\t * were omitted. Only their parts that were wholly in the range were returned.\n\t *\n\t * **Note:** this method is not returning flat ranges that contain no nodes.\n\t *\n\t * @returns {Array.<module:engine/model/range~Range>} Array of flat ranges covering this range.\n\t */\n\tgetMinimalFlatRanges() {\n\t\tconst ranges = [];\n\t\tconst diffAt = this.start.getCommonPath( this.end ).length;\n\n\t\tconst pos = Position._createAt( this.start );\n\t\tlet posParent = pos.parent;\n\n\t\t// Go up.\n\t\twhile ( pos.path.length > diffAt + 1 ) {\n\t\t\tconst howMany = posParent.maxOffset - pos.offset;\n\n\t\t\tif ( howMany !== 0 ) {\n\t\t\t\tranges.push( new Range( pos, pos.getShiftedBy( howMany ) ) );\n\t\t\t}\n\n\t\t\tpos.path = pos.path.slice( 0, -1 );\n\t\t\tpos.offset++;\n\t\t\tposParent = posParent.parent;\n\t\t}\n\n\t\t// Go down.\n\t\twhile ( pos.path.length <= this.end.path.length ) {\n\t\t\tconst offset = this.end.path[ pos.path.length - 1 ];\n\t\t\tconst howMany = offset - pos.offset;\n\n\t\t\tif ( howMany !== 0 ) {\n\t\t\t\tranges.push( new Range( pos, pos.getShiftedBy( howMany ) ) );\n\t\t\t}\n\n\t\t\tpos.offset = offset;\n\t\t\tpos.path.push( 0 );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/treewalker~TreeWalker TreeWalker} instance with this range as a boundary.\n\t *\n\t * For example, to iterate over all items in the entire document root:\n\t *\n\t *\t\t// Create a range spanning over the entire root content:\n\t *\t\tconst range = editor.model.createRangeIn( editor.model.document.getRoot() );\n\t *\n\t *\t\t// Iterate over all items in this range:\n\t *\t\tfor ( const value of range.getWalker() ) {\n\t *\t\t\tconsole.log( value.item );\n\t *\t\t}\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @param {module:engine/model/position~Position} [options.startPosition]\n\t * @param {Boolean} [options.singleCharacters=false]\n\t * @param {Boolean} [options.shallow=false]\n\t * @param {Boolean} [options.ignoreElementEnd=false]\n\t */\n\tgetWalker( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\treturn new TreeWalker( options );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/model/item~Item items} that are in this range and returns\n\t * them.\n\t *\n\t * This method uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range and `ignoreElementEnd` option\n\t * set to `true`. However it returns only {@link module:engine/model/item~Item model items},\n\t * not {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/model/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @returns {Iterable.<module:engine/model/item~Item>}\n\t */\n\t* getItems( options = {} ) {\n\t\toptions.boundaries = this;\n\t\toptions.ignoreElementEnd = true;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.item;\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/model/position~Position positions} that are boundaries or\n\t * contained in this range.\n\t *\n\t * This method uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range. However it returns only\n\t * {@link module:engine/model/position~Position positions}, not {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/model/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @returns {Iterable.<module:engine/model/position~Position>}\n\t */\n\t* getPositions( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tyield treeWalker.position;\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.nextPosition;\n\t\t}\n\t}\n\n\t/**\n\t * Returns a range that is a result of transforming this range by given `operation`.\n\t *\n\t * **Note:** transformation may break one range into multiple ranges (for example, when a part of the range is\n\t * moved to a different part of document tree). For this reason, an array is returned by this method and it\n\t * may contain one or more `Range` instances.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to transform range by.\n\t * @returns {Array.<module:engine/model/range~Range>} Range which is the result of transformation.\n\t */\n\tgetTransformedByOperation( operation ) {\n\t\tswitch ( operation.type ) {\n\t\t\tcase 'insert':\n\t\t\t\treturn this._getTransformedByInsertOperation( operation );\n\t\t\tcase 'move':\n\t\t\tcase 'remove':\n\t\t\tcase 'reinsert':\n\t\t\t\treturn this._getTransformedByMoveOperation( operation );\n\t\t\tcase 'split':\n\t\t\t\treturn [ this._getTransformedBySplitOperation( operation ) ];\n\t\t\tcase 'merge':\n\t\t\t\treturn [ this._getTransformedByMergeOperation( operation ) ];\n\t\t}\n\n\t\treturn [ new Range( this.start, this.end ) ];\n\t}\n\n\t/**\n\t * Returns a range that is a result of transforming this range by multiple `operations`.\n\t *\n\t * @see ~Range#getTransformedByOperation\n\t * @param {Iterable.<module:engine/model/operation/operation~Operation>} operations Operations to transform the range by.\n\t * @returns {Array.<module:engine/model/range~Range>} Range which is the result of transformation.\n\t */\n\tgetTransformedByOperations( operations ) {\n\t\tconst ranges = [ new Range( this.start, this.end ) ];\n\n\t\tfor ( const operation of operations ) {\n\t\t\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t\t\tconst result = ranges[ i ].getTransformedByOperation( operation );\n\n\t\t\t\tranges.splice( i, 1, ...result );\n\t\t\t\ti += result.length - 1;\n\t\t\t}\n\t\t}\n\n\t\t// It may happen that a range is split into two, and then the part of second \"piece\" is moved into first\n\t\t// \"piece\". In this case we will have incorrect third range, which should not be included in the result --\n\t\t// because it is already included in the first \"piece\". In this loop we are looking for all such ranges that\n\t\t// are inside other ranges and we simply remove them.\n\t\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t\tconst range = ranges[ i ];\n\n\t\t\tfor ( let j = i + 1; j < ranges.length; j++ ) {\n\t\t\t\tconst next = ranges[ j ];\n\n\t\t\t\tif ( range.containsRange( next ) || next.containsRange( range ) || range.isEqual( next ) ) {\n\t\t\t\t\tranges.splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}\n\t * which is a common ancestor of the range's both ends (in which the entire range is contained).\n\t *\n\t * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor() {\n\t\treturn this.start.getCommonAncestor( this.end );\n\t}\n\n\t/**\n\t * Converts `Range` to plain object and returns it.\n\t *\n\t * @returns {Object} `Node` converted to plain object.\n\t */\n\ttoJSON() {\n\t\treturn {\n\t\t\tstart: this.start.toJSON(),\n\t\t\tend: this.end.toJSON()\n\t\t};\n\t}\n\n\t/**\n\t * Returns a new range that is equal to current range.\n\t *\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.start, this.end );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by insert operation.\n\t *\n\t * One or more ranges may be returned as a result of this transformation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/insertoperation~InsertOperation} operation\n\t * @returns {Array.<module:engine/model/range~Range>}\n\t */\n\t_getTransformedByInsertOperation( operation, spread = false ) {\n\t\treturn this._getTransformedByInsertion( operation.position, operation.howMany, spread );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by move operation.\n\t *\n\t * One or more ranges may be returned as a result of this transformation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/moveoperation~MoveOperation} operation\n\t * @returns {Array.<module:engine/model/range~Range>}\n\t */\n\t_getTransformedByMoveOperation( operation, spread = false ) {\n\t\tconst sourcePosition = operation.sourcePosition;\n\t\tconst howMany = operation.howMany;\n\t\tconst targetPosition = operation.targetPosition;\n\n\t\treturn this._getTransformedByMove( sourcePosition, targetPosition, howMany, spread );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by split operation.\n\t *\n\t * Always one range is returned. The transformation is done in a way to not break the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/splitoperation~SplitOperation} operation\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getTransformedBySplitOperation( operation ) {\n\t\tconst start = this.start._getTransformedBySplitOperation( operation );\n\t\tlet end = this.end._getTransformedBySplitOperation( operation );\n\n\t\tif ( this.end.isEqual( operation.insertionPosition ) ) {\n\t\t\tend = this.end.getShiftedBy( 1 );\n\t\t}\n\n\t\t// Below may happen when range contains graveyard element used by split operation.\n\t\tif ( start.root != end.root ) {\n\t\t\t// End position was next to the moved graveyard element and was moved with it.\n\t\t\t// Fix it by using old `end` which has proper `root`.\n\t\t\tend = this.end.getShiftedBy( -1 );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by merge operation.\n\t *\n\t * Always one range is returned. The transformation is done in a way to not break the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/mergeoperation~MergeOperation} operation\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getTransformedByMergeOperation( operation ) {\n\t\t// Special case when the marker is set on \"the closing tag\" of an element. Marker can be set like that during\n\t\t// transformations, especially when a content of a few block elements were removed. For example:\n\t\t//\n\t\t// {} is the transformed range, [] is the removed range.\n\t\t// <p>F[o{o</p><p>B}ar</p><p>Xy]z</p>\n\t\t//\n\t\t// <p>Fo{o</p><p>B}ar</p><p>z</p>\n\t\t// <p>F{</p><p>B}ar</p><p>z</p>\n\t\t// <p>F{</p>}<p>z</p>\n\t\t// <p>F{}z</p>\n\t\t//\n\t\tif ( this.start.isEqual( operation.targetPosition ) && this.end.isEqual( operation.deletionPosition ) ) {\n\t\t\treturn new Range( this.start );\n\t\t}\n\n\t\tlet start = this.start._getTransformedByMergeOperation( operation );\n\t\tlet end = this.end._getTransformedByMergeOperation( operation );\n\n\t\tif ( start.root != end.root ) {\n\t\t\t// This happens when the end position was next to the merged (deleted) element.\n\t\t\t// Then, the end position was moved to the graveyard root. In this case we need to fix\n\t\t\t// the range cause its boundaries would be in different roots.\n\t\t\tend = this.end.getShiftedBy( -1 );\n\t\t}\n\n\t\tif ( start.isAfter( end ) ) {\n\t\t\t// This happens in three following cases:\n\t\t\t//\n\t\t\t// Case 1: Merge operation source position is before the target position (due to some transformations, OT, etc.)\n\t\t\t// This means that start can be moved before the end of the range.\n\t\t\t//\n\t\t\t// Before: <p>a{a</p><p>b}b</p><p>cc</p>\n\t\t\t// Merge: <p>b}b</p><p>cca{a</p>\n\t\t\t// Fix: <p>{b}b</p><p>ccaa</p>\n\t\t\t//\n\t\t\t// Case 2: Range start is before merged node but not directly.\n\t\t\t// Result should include all nodes that were in the original range.\n\t\t\t//\n\t\t\t// Before: <p>aa</p>{<p>cc</p><p>b}b</p>\n\t\t\t// Merge: <p>aab}b</p>{<p>cc</p>\n\t\t\t// Fix: <p>aa{bb</p><p>cc</p>}\n\t\t\t//\n\t\t\t// The range is expanded by an additional `b` letter but it is better than dropping the whole `cc` paragraph.\n\t\t\t//\n\t\t\t// Case 3: Range start is directly before merged node.\n\t\t\t// Resulting range should include only nodes from the merged element:\n\t\t\t//\n\t\t\t// Before: <p>aa</p>{<p>b}b</p><p>cc</p>\n\t\t\t// Merge: <p>aab}b</p>{<p>cc</p>\n\t\t\t// Fix: <p>aa{b}b</p><p>cc</p>\n\t\t\t//\n\n\t\t\tif ( operation.sourcePosition.isBefore( operation.targetPosition ) ) {\n\t\t\t\t// Case 1.\n\t\t\t\tstart = Position._createAt( end );\n\t\t\t\tstart.offset = 0;\n\t\t\t} else {\n\t\t\t\tif ( !operation.deletionPosition.isEqual( start ) ) {\n\t\t\t\t\t// Case 2.\n\t\t\t\t\tend = operation.deletionPosition;\n\t\t\t\t}\n\n\t\t\t\t// In both case 2 and 3 start is at the end of the merge-to element.\n\t\t\t\tstart = operation.targetPosition;\n\t\t\t}\n\n\t\t\treturn new Range( start, end );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Returns an array containing one or two {@link ~Range ranges} that are a result of transforming this\n\t * {@link ~Range range} by inserting `howMany` nodes at `insertPosition`. Two {@link ~Range ranges} are\n\t * returned if the insertion was inside this {@link ~Range range} and `spread` is set to `true`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 1 ] ), 2 );\n\t *\t\t// transformed array has one range from [ 4, 7 ] to [ 6, 0, 1 ]\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 4, 0, 0 ] ), 4 );\n\t *\t\t// transformed array has one range from [ 2, 7 ] to [ 4, 0, 5 ]\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4 );\n\t *\t\t// transformed array has one range, which is equal to original range\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4, true );\n\t *\t\t// transformed array has two ranges: from [ 2, 7 ] to [ 3, 2 ] and from [ 3, 6 ] to [ 4, 0, 1 ]\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} insertPosition Position where nodes are inserted.\n\t * @param {Number} howMany How many nodes are inserted.\n\t * @param {Boolean} [spread] Flag indicating whether this {~Range range} should be spread if insertion\n\t * was inside the range. Defaults to `false`.\n\t * @returns {Array.<module:engine/model/range~Range>} Result of the transformation.\n\t */\n\t_getTransformedByInsertion( insertPosition, howMany, spread = false ) {\n\t\tif ( spread && this.containsPosition( insertPosition ) ) {\n\t\t\t// Range has to be spread. The first part is from original start to the spread point.\n\t\t\t// The other part is from spread point to the original end, but transformed by\n\t\t\t// insertion to reflect insertion changes.\n\n\t\t\treturn [\n\t\t\t\tnew Range( this.start, insertPosition ),\n\t\t\t\tnew Range(\n\t\t\t\t\tinsertPosition.getShiftedBy( howMany ),\n\t\t\t\t\tthis.end._getTransformedByInsertion( insertPosition, howMany )\n\t\t\t\t)\n\t\t\t];\n\t\t} else {\n\t\t\tconst range = new Range( this.start, this.end );\n\n\t\t\trange.start = range.start._getTransformedByInsertion( insertPosition, howMany );\n\t\t\trange.end = range.end._getTransformedByInsertion( insertPosition, howMany );\n\n\t\t\treturn [ range ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns an array containing {@link ~Range ranges} that are a result of transforming this\n\t * {@link ~Range range} by moving `howMany` nodes from `sourcePosition` to `targetPosition`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} sourcePosition Position from which nodes are moved.\n\t * @param {module:engine/model/position~Position} targetPosition Position to where nodes are moved.\n\t * @param {Number} howMany How many nodes are moved.\n\t * @param {Boolean} [spread=false] Whether the range should be spread if the move points inside the range.\n\t * @returns {Array.<module:engine/model/range~Range>} Result of the transformation.\n\t */\n\t_getTransformedByMove( sourcePosition, targetPosition, howMany, spread = false ) {\n\t\t// Special case for transforming a collapsed range. Just transform it like a position.\n\t\tif ( this.isCollapsed ) {\n\t\t\tconst newPos = this.start._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\n\t\t\treturn [ new Range( newPos ) ];\n\t\t}\n\n\t\t// Special case for transformation when a part of the range is moved towards the range.\n\t\t//\n\t\t// Examples:\n\t\t//\n\t\t// <div><p>ab</p><p>c[d</p></div><p>e]f</p> --> <div><p>ab</p></div><p>c[d</p><p>e]f</p>\n\t\t// <p>e[f</p><div><p>a]b</p><p>cd</p></div> --> <p>e[f</p><p>a]b</p><div><p>cd</p></div>\n\t\t//\n\t\t// Without this special condition, the default algorithm leaves an \"artifact\" range from one of `differenceSet` parts:\n\t\t//\n\t\t// <div><p>ab</p><p>c[d</p></div><p>e]f</p> --> <div><p>ab</p>{</div>}<p>c[d</p><p>e]f</p>\n\t\t//\n\t\t// This special case is applied only if the range is to be kept together (not spread).\n\t\tconst moveRange = Range._createFromPositionAndShift( sourcePosition, howMany );\n\t\tconst insertPosition = targetPosition._getTransformedByDeletion( sourcePosition, howMany );\n\n\t\tif ( this.containsPosition( targetPosition ) && !spread ) {\n\t\t\tif ( moveRange.containsPosition( this.start ) || moveRange.containsPosition( this.end ) ) {\n\t\t\t\tconst start = this.start._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\t\t\t\tconst end = this.end._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\n\t\t\t\treturn [ new Range( start, end ) ];\n\t\t\t}\n\t\t}\n\n\t\t// Default algorithm.\n\t\tlet result;\n\n\t\tconst differenceSet = this.getDifference( moveRange );\n\t\tlet difference = null;\n\n\t\tconst common = this.getIntersection( moveRange );\n\n\t\tif ( differenceSet.length == 1 ) {\n\t\t\t// `moveRange` and this range may intersect but may be separate.\n\t\t\tdifference = new Range(\n\t\t\t\tdifferenceSet[ 0 ].start._getTransformedByDeletion( sourcePosition, howMany ),\n\t\t\t\tdifferenceSet[ 0 ].end._getTransformedByDeletion( sourcePosition, howMany )\n\t\t\t);\n\t\t} else if ( differenceSet.length == 2 ) {\n\t\t\t// `moveRange` is inside this range.\n\t\t\tdifference = new Range(\n\t\t\t\tthis.start,\n\t\t\t\tthis.end._getTransformedByDeletion( sourcePosition, howMany )\n\t\t\t);\n\t\t} // else, `moveRange` contains this range.\n\n\t\tif ( difference ) {\n\t\t\tresult = difference._getTransformedByInsertion( insertPosition, howMany, common !== null || spread );\n\t\t} else {\n\t\t\tresult = [];\n\t\t}\n\n\t\tif ( common ) {\n\t\t\tconst transformedCommon = new Range(\n\t\t\t\tcommon.start._getCombined( moveRange.start, insertPosition ),\n\t\t\t\tcommon.end._getCombined( moveRange.start, insertPosition )\n\t\t\t);\n\n\t\t\tif ( result.length == 2 ) {\n\t\t\t\tresult.splice( 1, 0, transformedCommon );\n\t\t\t} else {\n\t\t\t\tresult.push( transformedCommon );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a copy of this range that is transformed by deletion of `howMany` nodes from `deletePosition`.\n\t *\n\t * If the deleted range is intersecting with the transformed range, the transformed range will be shrank.\n\t *\n\t * If the deleted range contains transformed range, `null` will be returned.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} deletionPosition Position from which nodes are removed.\n\t * @param {Number} howMany How many nodes are removed.\n\t * @returns {module:engine/model/range~Range|null} Result of the transformation.\n\t */\n\t_getTransformedByDeletion( deletePosition, howMany ) {\n\t\tlet newStart = this.start._getTransformedByDeletion( deletePosition, howMany );\n\t\tlet newEnd = this.end._getTransformedByDeletion( deletePosition, howMany );\n\n\t\tif ( newStart == null && newEnd == null ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( newStart == null ) {\n\t\t\tnewStart = deletePosition;\n\t\t}\n\n\t\tif ( newEnd == null ) {\n\t\t\tnewEnd = deletePosition;\n\t\t}\n\n\t\treturn new Range( newStart, newEnd );\n\t}\n\n\t/**\n\t * Creates a new range, spreading from specified {@link module:engine/model/position~Position position} to a position moved by\n\t * given `shift`. If `shift` is a negative value, shifted position is treated as the beginning of the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} position Beginning of the range.\n\t * @param {Number} shift How long the range should be.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createFromPositionAndShift( position, shift ) {\n\t\tconst start = position;\n\t\tconst end = position.getShiftedBy( shift );\n\n\t\treturn shift > 0 ? new this( start, end ) : new this( end, start );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @protected\n\t * @param {module:engine/model/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createIn( element ) {\n\t\treturn new this( Position._createAt( element, 0 ), Position._createAt( element, element.maxOffset ) );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/model/item~Item model item} and ends after it.\n\t *\n\t * @protected\n\t * @param {module:engine/model/item~Item} item\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createOn( item ) {\n\t\treturn this._createFromPositionAndShift( Position._createBefore( item ), item.offsetSize );\n\t}\n\n\t/**\n\t * Combines all ranges from the passed array into a one range. At least one range has to be passed.\n\t * Passed ranges must not have common parts.\n\t *\n\t * The first range from the array is a reference range. If other ranges start or end on the exactly same position where\n\t * the reference range, they get combined into one range.\n\t *\n\t *\t\t[ ][] [ ][ ][ ][ ][] [ ] // Passed ranges, shown sorted\n\t *\t\t[ ] // The result of the function if the first range was a reference range.\n\t *\t [ ] // The result of the function if the third-to-seventh range was a reference range.\n\t *\t [ ] // The result of the function if the last range was a reference range.\n\t *\n\t * @param {Array.<module:engine/model/range~Range>} ranges Ranges to combine.\n\t * @returns {module:engine/model/range~Range} Combined range.\n\t */\n\tstatic _createFromRanges( ranges ) {\n\t\tif ( ranges.length === 0 ) {\n\t\t\t/**\n\t\t\t * At least one range has to be passed to\n\t\t\t * {@link module:engine/model/range~Range._createFromRanges `Range._createFromRanges()`}.\n\t\t\t *\n\t\t\t * @error range-create-from-ranges-empty-array\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'range-create-from-ranges-empty-array: At least one range has to be passed.',\n\t\t\t\tnull\n\t\t\t);\n\t\t} else if ( ranges.length == 1 ) {\n\t\t\treturn ranges[ 0 ].clone();\n\t\t}\n\n\t\t// 1. Set the first range in `ranges` array as a reference range.\n\t\t// If we are going to return just a one range, one of the ranges need to be the reference one.\n\t\t// Other ranges will be stuck to that range, if possible.\n\t\tconst ref = ranges[ 0 ];\n\n\t\t// 2. Sort all the ranges so it's easier to process them.\n\t\tranges.sort( ( a, b ) => {\n\t\t\treturn a.start.isAfter( b.start ) ? 1 : -1;\n\t\t} );\n\n\t\t// 3. Check at which index the reference range is now.\n\t\tconst refIndex = ranges.indexOf( ref );\n\n\t\t// 4. At this moment we don't need the original range.\n\t\t// We are going to modify the result and we need to return a new instance of Range.\n\t\t// We have to create a copy of the reference range.\n\t\tconst result = new this( ref.start, ref.end );\n\n\t\t// 5. Ranges should be checked and glued starting from the range that is closest to the reference range.\n\t\t// Since ranges are sorted, start with the range with index that is closest to reference range index.\n\t\tif ( refIndex > 0 ) {\n\t\t\tfor ( let i = refIndex - 1; true; i++ ) {\n\t\t\t\tif ( ranges[ i ].end.isEqual( result.start ) ) {\n\t\t\t\t\tresult.start = Position._createAt( ranges[ i ].start );\n\t\t\t\t} else {\n\t\t\t\t\t// If ranges are not starting/ending at the same position there is no point in looking further.\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 6. Ranges should be checked and glued starting from the range that is closest to the reference range.\n\t\t// Since ranges are sorted, start with the range with index that is closest to reference range index.\n\t\tfor ( let i = refIndex + 1; i < ranges.length; i++ ) {\n\t\t\tif ( ranges[ i ].start.isEqual( result.end ) ) {\n\t\t\t\tresult.end = Position._createAt( ranges[ i ].end );\n\t\t\t} else {\n\t\t\t\t// If ranges are not starting/ending at the same position there is no point in looking further.\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Creates a `Range` instance from given plain object (i.e. parsed JSON string).\n\t *\n\t * @param {Object} json Plain object to be converted to `Range`.\n\t * @param {module:engine/model/document~Document} doc Document object that will be range owner.\n\t * @returns {module:engine/model/element~Element} `Range` instance created using given plain object.\n\t */\n\tstatic fromJSON( json, doc ) {\n\t\treturn new this( Position.fromJSON( json.start, doc ), Position.fromJSON( json.end, doc ) );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `${ this.root } [ ${ this.start.path.join( ', ' ) } ] - [ ${ this.end.path.join( ', ' ) } ]`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelPosition: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/conversion/mapper\n */\n\nimport ModelPosition from '../model/position';\nimport ModelRange from '../model/range';\n\nimport ViewPosition from '../view/position';\nimport ViewRange from '../view/range';\nimport ViewText from '../view/text';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Maps elements, positions and markers between {@link module:engine/view/document~Document the view} and\n * {@link module:engine/model/model the model}.\n *\n * The instance of the Mapper used for the editing pipeline is available in\n * {@link module:engine/controller/editingcontroller~EditingController#mapper `editor.editing.mapper`}.\n *\n * Mapper uses bound elements to find corresponding elements and positions, so, to get proper results,\n * all model elements should be {@link module:engine/conversion/mapper~Mapper#bindElements bound}.\n *\n * To map complex model to/from view relations, you may provide custom callbacks for\n * {@link module:engine/conversion/mapper~Mapper#event:modelToViewPosition modelToViewPosition event} and\n * {@link module:engine/conversion/mapper~Mapper#event:viewToModelPosition viewToModelPosition event} that are fired whenever\n * a position mapping request occurs.\n * Those events are fired by {@link module:engine/conversion/mapper~Mapper#toViewPosition toViewPosition}\n * and {@link module:engine/conversion/mapper~Mapper#toModelPosition toModelPosition} methods. `Mapper` adds it's own default callbacks\n * with `'lowest'` priority. To override default `Mapper` mapping, add custom callback with higher priority and\n * stop the event.\n */\nexport default class Mapper {\n\t/**\n\t * Creates an instance of the mapper.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Model element to view element mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap}\n\t\t */\n\t\tthis._modelToViewMapping = new WeakMap();\n\n\t\t/**\n\t\t * View element to model element mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap}\n\t\t */\n\t\tthis._viewToModelMapping = new WeakMap();\n\n\t\t/**\n\t\t * A map containing callbacks between view element names and functions evaluating length of view elements\n\t\t * in model.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._viewToModelLengthCallbacks = new Map();\n\n\t\t/**\n\t\t * Model marker name to view elements mapping.\n\t\t *\n\t\t * Keys are `String`s while values are `Set`s with {@link module:engine/view/element~Element view elements}.\n\t\t * One marker (name) can be mapped to multiple elements.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._markerNameToElements = new Map();\n\n\t\t/**\n\t\t * View element to model marker names mapping.\n\t\t *\n\t\t * This is reverse to {@link ~Mapper#_markerNameToElements} map.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._elementToMarkerNames = new Map();\n\n\t\t/**\n\t\t * Stores marker names of markers which has changed due to unbinding a view element (so it is assumed that the view element\n\t\t * has been removed, moved or renamed).\n\t\t *\n\t\t * @private\n\t\t * @member {Set.<module:engine/model/markercollection~Marker>}\n\t\t */\n\t\tthis._unboundMarkerNames = new Set();\n\n\t\t// Default mapper algorithm for mapping model position to view position.\n\t\tthis.on( 'modelToViewPosition', ( evt, data ) => {\n\t\t\tif ( data.viewPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst viewContainer = this._modelToViewMapping.get( data.modelPosition.parent );\n\n\t\t\tdata.viewPosition = this._findPositionIn( viewContainer, data.modelPosition.offset );\n\t\t}, { priority: 'low' } );\n\n\t\t// Default mapper algorithm for mapping view position to model position.\n\t\tthis.on( 'viewToModelPosition', ( evt, data ) => {\n\t\t\tif ( data.modelPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst viewBlock = this.findMappedViewAncestor( data.viewPosition );\n\t\t\tconst modelParent = this._viewToModelMapping.get( viewBlock );\n\t\t\tconst modelOffset = this._toModelOffset( data.viewPosition.parent, data.viewPosition.offset, viewBlock );\n\n\t\t\tdata.modelPosition = ModelPosition._createAt( modelParent, modelOffset );\n\t\t}, { priority: 'low' } );\n\t}\n\n\t/**\n\t * Marks model and view elements as corresponding. Corresponding elements can be retrieved by using\n\t * the {@link module:engine/conversion/mapper~Mapper#toModelElement toModelElement} and\n\t * {@link module:engine/conversion/mapper~Mapper#toViewElement toViewElement} methods.\n\t * The information that elements are bound is also used to translate positions.\n\t *\n\t * @param {module:engine/model/element~Element} modelElement Model element.\n\t * @param {module:engine/view/element~Element} viewElement View element.\n\t */\n\tbindElements( modelElement, viewElement ) {\n\t\tthis._modelToViewMapping.set( modelElement, viewElement );\n\t\tthis._viewToModelMapping.set( viewElement, modelElement );\n\t}\n\n\t/**\n\t * Unbinds given {@link module:engine/view/element~Element view element} from the map.\n\t *\n\t * **Note:** view-to-model binding will be removed, if it existed. However, corresponding model-to-view binding\n\t * will be removed only if model element is still bound to passed `viewElement`.\n\t *\n\t * This behavior lets for re-binding model element to another view element without fear of losing the new binding\n\t * when the previously bound view element is unbound.\n\t *\n\t * @param {module:engine/view/element~Element} viewElement View element to unbind.\n\t */\n\tunbindViewElement( viewElement ) {\n\t\tconst modelElement = this.toModelElement( viewElement );\n\n\t\tthis._viewToModelMapping.delete( viewElement );\n\n\t\tif ( this._elementToMarkerNames.has( viewElement ) ) {\n\t\t\tfor ( const markerName of this._elementToMarkerNames.get( viewElement ) ) {\n\t\t\t\tthis._unboundMarkerNames.add( markerName );\n\t\t\t}\n\t\t}\n\n\t\tif ( this._modelToViewMapping.get( modelElement ) == viewElement ) {\n\t\t\tthis._modelToViewMapping.delete( modelElement );\n\t\t}\n\t}\n\n\t/**\n\t * Unbinds given {@link module:engine/model/element~Element model element} from the map.\n\t *\n\t * **Note:** model-to-view binding will be removed, if it existed. However, corresponding view-to-model binding\n\t * will be removed only if view element is still bound to passed `modelElement`.\n\t *\n\t * This behavior lets for re-binding view element to another model element without fear of losing the new binding\n\t * when the previously bound model element is unbound.\n\t *\n\t * @param {module:engine/model/element~Element} modelElement Model element to unbind.\n\t */\n\tunbindModelElement( modelElement ) {\n\t\tconst viewElement = this.toViewElement( modelElement );\n\n\t\tthis._modelToViewMapping.delete( modelElement );\n\n\t\tif ( this._viewToModelMapping.get( viewElement ) == modelElement ) {\n\t\t\tthis._viewToModelMapping.delete( viewElement );\n\t\t}\n\t}\n\n\t/**\n\t * Binds given marker name with given {@link module:engine/view/element~Element view element}. The element\n\t * will be added to the current set of elements bound with given marker name.\n\t *\n\t * @param {module:engine/view/element~Element} element Element to bind.\n\t * @param {String} name Marker name.\n\t */\n\tbindElementToMarker( element, name ) {\n\t\tconst elements = this._markerNameToElements.get( name ) || new Set();\n\t\telements.add( element );\n\n\t\tconst names = this._elementToMarkerNames.get( element ) || new Set();\n\t\tnames.add( name );\n\n\t\tthis._markerNameToElements.set( name, elements );\n\t\tthis._elementToMarkerNames.set( element, names );\n\t}\n\n\t/**\n\t * Unbinds an element from given marker name.\n\t *\n\t * @param {module:engine/view/element~Element} element Element to unbind.\n\t * @param {String} name Marker name.\n\t */\n\tunbindElementFromMarkerName( element, name ) {\n\t\tconst nameToElements = this._markerNameToElements.get( name );\n\n\t\tif ( nameToElements ) {\n\t\t\tnameToElements.delete( element );\n\n\t\t\tif ( nameToElements.size == 0 ) {\n\t\t\t\tthis._markerNameToElements.delete( name );\n\t\t\t}\n\t\t}\n\n\t\tconst elementToNames = this._elementToMarkerNames.get( element );\n\n\t\tif ( elementToNames ) {\n\t\t\telementToNames.delete( name );\n\n\t\t\tif ( elementToNames.size == 0 ) {\n\t\t\t\tthis._elementToMarkerNames.delete( element );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns all marker names of markers which has changed due to unbinding a view element (so it is assumed that the view element\n\t * has been removed, moved or renamed) since the last flush. After returning, the marker names list is cleared.\n\t *\n\t * @returns {Array.<String>}\n\t */\n\tflushUnboundMarkerNames() {\n\t\tconst markerNames = Array.from( this._unboundMarkerNames );\n\n\t\tthis._unboundMarkerNames.clear();\n\n\t\treturn markerNames;\n\t}\n\n\t/**\n\t * Removes all model to view and view to model bindings.\n\t */\n\tclearBindings() {\n\t\tthis._modelToViewMapping = new WeakMap();\n\t\tthis._viewToModelMapping = new WeakMap();\n\t\tthis._markerNameToElements = new Map();\n\t\tthis._elementToMarkerNames = new Map();\n\t\tthis._unboundMarkerNames = new Set();\n\t}\n\n\t/**\n\t * Gets the corresponding model element.\n\t *\n\t * **Note:** {@link module:engine/view/uielement~UIElement} does not have corresponding element in model.\n\t *\n\t * @param {module:engine/view/element~Element} viewElement View element.\n\t * @returns {module:engine/model/element~Element|undefined} Corresponding model element or `undefined` if not found.\n\t */\n\ttoModelElement( viewElement ) {\n\t\treturn this._viewToModelMapping.get( viewElement );\n\t}\n\n\t/**\n\t * Gets the corresponding view element.\n\t *\n\t * @param {module:engine/model/element~Element} modelElement Model element.\n\t * @returns {module:engine/view/element~Element|undefined} Corresponding view element or `undefined` if not found.\n\t */\n\ttoViewElement( modelElement ) {\n\t\treturn this._modelToViewMapping.get( modelElement );\n\t}\n\n\t/**\n\t * Gets the corresponding model range.\n\t *\n\t * @param {module:engine/view/range~Range} viewRange View range.\n\t * @returns {module:engine/model/range~Range} Corresponding model range.\n\t */\n\ttoModelRange( viewRange ) {\n\t\treturn new ModelRange( this.toModelPosition( viewRange.start ), this.toModelPosition( viewRange.end ) );\n\t}\n\n\t/**\n\t * Gets the corresponding view range.\n\t *\n\t * @param {module:engine/model/range~Range} modelRange Model range.\n\t * @returns {module:engine/view/range~Range} Corresponding view range.\n\t */\n\ttoViewRange( modelRange ) {\n\t\treturn new ViewRange( this.toViewPosition( modelRange.start ), this.toViewPosition( modelRange.end ) );\n\t}\n\n\t/**\n\t * Gets the corresponding model position.\n\t *\n\t * @fires viewToModelPosition\n\t * @param {module:engine/view/position~Position} viewPosition View position.\n\t * @returns {module:engine/model/position~Position} Corresponding model position.\n\t */\n\ttoModelPosition( viewPosition ) {\n\t\tconst data = {\n\t\t\tviewPosition,\n\t\t\tmapper: this\n\t\t};\n\n\t\tthis.fire( 'viewToModelPosition', data );\n\n\t\treturn data.modelPosition;\n\t}\n\n\t/**\n\t * Gets the corresponding view position.\n\t *\n\t * @fires modelToViewPosition\n\t * @param {module:engine/model/position~Position} modelPosition Model position.\n\t * @param {Object} [options] Additional options for position mapping process.\n\t * @param {Boolean} [options.isPhantom=false] Should be set to `true` if the model position to map is pointing to a place\n\t * in model tree which no longer exists. For example, it could be an end of a removed model range.\n\t * @returns {module:engine/view/position~Position} Corresponding view position.\n\t */\n\ttoViewPosition( modelPosition, options = { isPhantom: false } ) {\n\t\tconst data = {\n\t\t\tmodelPosition,\n\t\t\tmapper: this,\n\t\t\tisPhantom: options.isPhantom\n\t\t};\n\n\t\tthis.fire( 'modelToViewPosition', data );\n\n\t\treturn data.viewPosition;\n\t}\n\n\t/**\n\t * Gets all view elements bound to the given marker name.\n\t *\n\t * @param {String} name Marker name.\n\t * @returns {Set.<module:engine/view/element~Element>|null} View elements bound with given marker name or `null`\n\t * if no elements are bound to given marker name.\n\t */\n\tmarkerNameToElements( name ) {\n\t\tconst boundElements = this._markerNameToElements.get( name );\n\n\t\tif ( !boundElements ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst elements = new Set();\n\n\t\tfor ( const element of boundElements ) {\n\t\t\tif ( element.is( 'attributeElement' ) ) {\n\t\t\t\tfor ( const clone of element.getElementsWithSameId() ) {\n\t\t\t\t\telements.add( clone );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\telements.add( element );\n\t\t\t}\n\t\t}\n\n\t\treturn elements;\n\t}\n\n\t/**\n\t * Registers a callback that evaluates the length in the model of a view element with given name.\n\t *\n\t * The callback is fired with one argument, which is a view element instance. The callback is expected to return\n\t * a number representing the length of view element in model.\n\t *\n\t *\t\t// List item in view may contain nested list, which have other list items. In model though,\n\t *\t\t// the lists are represented by flat structure. Because of those differences, length of list view element\n\t *\t\t// may be greater than one. In the callback it's checked how many nested list items are in evaluated list item.\n\t *\n\t *\t\tfunction getViewListItemLength( element ) {\n\t *\t\t\tlet length = 1;\n\t *\n\t *\t\t\tfor ( let child of element.getChildren() ) {\n\t *\t\t\t\tif ( child.name == 'ul' || child.name == 'ol' ) {\n\t *\t\t\t\t\tfor ( let item of child.getChildren() ) {\n\t *\t\t\t\t\t\tlength += getViewListItemLength( item );\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\n\t *\t\t\treturn length;\n\t *\t\t}\n\t *\n\t *\t\tmapper.registerViewToModelLength( 'li', getViewListItemLength );\n\t *\n\t * @param {String} viewElementName Name of view element for which callback is registered.\n\t * @param {Function} lengthCallback Function return a length of view element instance in model.\n\t */\n\tregisterViewToModelLength( viewElementName, lengthCallback ) {\n\t\tthis._viewToModelLengthCallbacks.set( viewElementName, lengthCallback );\n\t}\n\n\t/**\n\t * For given `viewPosition`, finds and returns the closest ancestor of this position that has a mapping to\n\t * the model.\n\t *\n\t * @param {module:engine/view/position~Position} viewPosition Position for which mapped ancestor should be found.\n\t * @returns {module:engine/view/element~Element}\n\t */\n\tfindMappedViewAncestor( viewPosition ) {\n\t\tlet parent = viewPosition.parent;\n\n\t\twhile ( !this._viewToModelMapping.has( parent ) ) {\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn parent;\n\t}\n\n\t/**\n\t * Calculates model offset based on the view position and the block element.\n\t *\n\t * Example:\n\t *\n\t *\t\t<p>foo<b>ba|r</b></p> // _toModelOffset( b, 2, p ) -> 5\n\t *\n\t * Is a sum of:\n\t *\n\t *\t\t<p>foo|<b>bar</b></p> // _toModelOffset( p, 3, p ) -> 3\n\t *\t\t<p>foo<b>ba|r</b></p> // _toModelOffset( b, 2, b ) -> 2\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} viewParent Position parent.\n\t * @param {Number} viewOffset Position offset.\n\t * @param {module:engine/view/element~Element} viewBlock Block used as a base to calculate offset.\n\t * @returns {Number} Offset in the model.\n\t */\n\t_toModelOffset( viewParent, viewOffset, viewBlock ) {\n\t\tif ( viewBlock != viewParent ) {\n\t\t\t// See example.\n\t\t\tconst offsetToParentStart = this._toModelOffset( viewParent.parent, viewParent.index, viewBlock );\n\t\t\tconst offsetInParent = this._toModelOffset( viewParent, viewOffset, viewParent );\n\n\t\t\treturn offsetToParentStart + offsetInParent;\n\t\t}\n\n\t\t// viewBlock == viewParent, so we need to calculate the offset in the parent element.\n\n\t\t// If the position is a text it is simple (\"ba|r\" -> 2).\n\t\tif ( viewParent.is( 'text' ) ) {\n\t\t\treturn viewOffset;\n\t\t}\n\n\t\t// If the position is in an element we need to sum lengths of siblings ( <b> bar </b> foo | -> 3 + 3 = 6 ).\n\t\tlet modelOffset = 0;\n\n\t\tfor ( let i = 0; i < viewOffset; i++ ) {\n\t\t\tmodelOffset += this.getModelLength( viewParent.getChild( i ) );\n\t\t}\n\n\t\treturn modelOffset;\n\t}\n\n\t/**\n\t * Gets the length of the view element in the model.\n\t *\n\t * The length is calculated as follows:\n\t * * if {@link #registerViewToModelLength length mapping callback} is provided for given `viewNode` it is used to\n\t * evaluate model length (`viewNode` is used as first and only parameter passed to the callback),\n\t * * length of a {@link module:engine/view/text~Text text node} is equal to the length of it's\n\t * {@link module:engine/view/text~Text#data data},\n\t * * length of a {@link module:engine/view/uielement~UIElement ui element} is equal to 0,\n\t * * length of a mapped {@link module:engine/view/element~Element element} is equal to 1,\n\t * * length of a not-mapped {@link module:engine/view/element~Element element} is equal to the length of it's children.\n\t *\n\t * Examples:\n\t *\n\t *\t\tfoo -> 3 // Text length is equal to it's data length.\n\t *\t\t<p>foo</p> -> 1 // Length of an element which is mapped is by default equal to 1.\n\t *\t\t<b>foo</b> -> 3 // Length of an element which is not mapped is a length of its children.\n\t *\t\t<div><p>x</p><p>y</p></div> -> 2 // Assuming that <div> is not mapped and <p> are mapped.\n\t *\n\t * @param {module:engine/view/element~Element} viewNode View node.\n\t * @returns {Number} Length of the node in the tree model.\n\t */\n\tgetModelLength( viewNode ) {\n\t\tif ( this._viewToModelLengthCallbacks.get( viewNode.name ) ) {\n\t\t\tconst callback = this._viewToModelLengthCallbacks.get( viewNode.name );\n\n\t\t\treturn callback( viewNode );\n\t\t} else if ( this._viewToModelMapping.has( viewNode ) ) {\n\t\t\treturn 1;\n\t\t} else if ( viewNode.is( 'text' ) ) {\n\t\t\treturn viewNode.data.length;\n\t\t} else if ( viewNode.is( 'uiElement' ) ) {\n\t\t\treturn 0;\n\t\t} else {\n\t\t\tlet len = 0;\n\n\t\t\tfor ( const child of viewNode.getChildren() ) {\n\t\t\t\tlen += this.getModelLength( child );\n\t\t\t}\n\n\t\t\treturn len;\n\t\t}\n\t}\n\n\t/**\n\t * Finds the position in the view node (or its children) with the expected model offset.\n\t *\n\t * Example:\n\t *\n\t *\t\t<p>fo<b>bar</b>bom</p> -> expected offset: 4\n\t *\n\t *\t\t_findPositionIn( p, 4 ):\n\t *\t\t<p>|fo<b>bar</b>bom</p> -> expected offset: 4, actual offset: 0\n\t *\t\t<p>fo|<b>bar</b>bom</p> -> expected offset: 4, actual offset: 2\n\t *\t\t<p>fo<b>bar</b>|bom</p> -> expected offset: 4, actual offset: 5 -> we are too far\n\t *\n\t *\t\t_findPositionIn( b, 4 - ( 5 - 3 ) ):\n\t *\t\t<p>fo<b>|bar</b>bom</p> -> expected offset: 2, actual offset: 0\n\t *\t\t<p>fo<b>bar|</b>bom</p> -> expected offset: 2, actual offset: 3 -> we are too far\n\t *\n\t *\t\t_findPositionIn( bar, 2 - ( 3 - 3 ) ):\n\t *\t\tWe are in the text node so we can simple find the offset.\n\t *\t\t<p>fo<b>ba|r</b>bom</p> -> expected offset: 2, actual offset: 2 -> position found\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} viewParent Tree view element in which we are looking for the position.\n\t * @param {Number} expectedOffset Expected offset.\n\t * @returns {module:engine/view/position~Position} Found position.\n\t */\n\t_findPositionIn( viewParent, expectedOffset ) {\n\t\t// Last scanned view node.\n\t\tlet viewNode;\n\t\t// Length of the last scanned view node.\n\t\tlet lastLength = 0;\n\n\t\tlet modelOffset = 0;\n\t\tlet viewOffset = 0;\n\n\t\t// In the text node it is simple: offset in the model equals offset in the text.\n\t\tif ( viewParent.is( 'text' ) ) {\n\t\t\treturn new ViewPosition( viewParent, expectedOffset );\n\t\t}\n\n\t\t// In other cases we add lengths of child nodes to find the proper offset.\n\n\t\t// If it is smaller we add the length.\n\t\twhile ( modelOffset < expectedOffset ) {\n\t\t\tviewNode = viewParent.getChild( viewOffset );\n\t\t\tlastLength = this.getModelLength( viewNode );\n\t\t\tmodelOffset += lastLength;\n\t\t\tviewOffset++;\n\t\t}\n\n\t\t// If it equals we found the position.\n\t\tif ( modelOffset == expectedOffset ) {\n\t\t\treturn this._moveViewPositionToTextNode( new ViewPosition( viewParent, viewOffset ) );\n\t\t}\n\t\t// If it is higher we need to enter last child.\n\t\telse {\n\t\t\t// ( modelOffset - lastLength ) is the offset to the child we enter,\n\t\t\t// so we subtract it from the expected offset to fine the offset in the child.\n\t\t\treturn this._findPositionIn( viewNode, expectedOffset - ( modelOffset - lastLength ) );\n\t\t}\n\t}\n\n\t/**\n\t * Because we prefer positions in text nodes over positions next to text node moves view position to the text node\n\t * if it was next to it.\n\t *\n\t *\t\t<p>[]<b>foo</b></p> -> <p>[]<b>foo</b></p> // do not touch if position is not directly next to text\n\t *\t\t<p>foo[]<b>foo</b></p> -> <p>foo{}<b>foo</b></p> // move to text node\n\t *\t\t<p><b>[]foo</b></p> -> <p><b>{}foo</b></p> // move to text node\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} viewPosition Position potentially next to text node.\n\t * @returns {module:engine/view/position~Position} Position in text node if possible.\n\t */\n\t_moveViewPositionToTextNode( viewPosition ) {\n\t\t// If the position is just after text node, put it at the end of that text node.\n\t\t// If the position is just before text node, put it at the beginning of that text node.\n\t\tconst nodeBefore = viewPosition.nodeBefore;\n\t\tconst nodeAfter = viewPosition.nodeAfter;\n\n\t\tif ( nodeBefore instanceof ViewText ) {\n\t\t\treturn new ViewPosition( nodeBefore, nodeBefore.data.length );\n\t\t} else if ( nodeAfter instanceof ViewText ) {\n\t\t\treturn new ViewPosition( nodeAfter, 0 );\n\t\t}\n\n\t\t// Otherwise, just return the given position.\n\t\treturn viewPosition;\n\t}\n\n\t/**\n\t * Fired for each model-to-view position mapping request. The purpose of this event is to enable custom model-to-view position\n\t * mapping. Callbacks added to this event take {@link module:engine/model/position~Position model position} and are expected to\n\t * calculate {@link module:engine/view/position~Position view position}. Calculated view position should be added as `viewPosition`\n\t * value in `data` object that is passed as one of parameters to the event callback.\n\t *\n\t * \t\t// Assume that \"captionedImage\" model element is converted to <img> and following <span> elements in view,\n\t * \t\t// and the model element is bound to <img> element. Force mapping model positions inside \"captionedImage\" to that\n\t * \t\t// <span> element.\n\t *\t\tmapper.on( 'modelToViewPosition', ( evt, data ) => {\n\t *\t\t\tconst positionParent = modelPosition.parent;\n\t *\n\t *\t\t\tif ( positionParent.name == 'captionedImage' ) {\n\t *\t\t\t\tconst viewImg = data.mapper.toViewElement( positionParent );\n\t *\t\t\t\tconst viewCaption = viewImg.nextSibling; // The <span> element.\n\t *\n\t *\t\t\t\tdata.viewPosition = new ViewPosition( viewCaption, modelPosition.offset );\n\t *\n\t *\t\t\t\t// Stop the event if other callbacks should not modify calculated value.\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * **Note:** keep in mind that sometimes a \"phantom\" model position is being converted. \"Phantom\" model position is\n\t * a position that points to a non-existing place in model. Such position might still be valid for conversion, though\n\t * (it would point to a correct place in view when converted). One example of such situation is when a range is\n\t * removed from model, there may be a need to map the range's end (which is no longer valid model position). To\n\t * handle such situation, check `data.isPhantom` flag:\n\t *\n\t * \t\t// Assume that there is \"customElement\" model element and whenever position is before it, we want to move it\n\t * \t\t// to the inside of the view element bound to \"customElement\".\n\t *\t\tmapper.on( 'modelToViewPosition', ( evt, data ) => {\n\t *\t\t\tif ( data.isPhantom ) {\n\t *\t\t\t\treturn;\n\t *\t\t\t}\n\t *\n\t *\t\t\t// Below line might crash for phantom position that does not exist in model.\n\t *\t\t\tconst sibling = data.modelPosition.nodeBefore;\n\t *\n\t *\t\t\t// Check if this is the element we are interested in.\n\t *\t\t\tif ( !sibling.is( 'customElement' ) ) {\n\t *\t\t\t\treturn;\n\t *\t\t\t}\n\t *\n\t *\t\t\tconst viewElement = data.mapper.toViewElement( sibling );\n\t *\n\t *\t\t\tdata.viewPosition = new ViewPosition( sibling, 0 );\n\t *\n\t *\t\t\tevt.stop();\n\t *\t\t} );\n\t *\n\t * **Note:** default mapping callback is provided with `low` priority setting and does not cancel the event, so it is possible to\n\t * attach a custom callback after default callback and also use `data.viewPosition` calculated by default callback\n\t * (for example to fix it).\n\t *\n\t * **Note:** default mapping callback will not fire if `data.viewPosition` is already set.\n\t *\n\t * **Note:** these callbacks are called **very often**. For efficiency reasons, it is advised to use them only when position\n\t * mapping between given model and view elements is unsolvable using just elements mapping and default algorithm. Also,\n\t * the condition that checks if special case scenario happened should be as simple as possible.\n\t *\n\t * @event modelToViewPosition\n\t * @param {Object} data Data pipeline object that can store and pass data between callbacks. The callback should add\n\t * `viewPosition` value to that object with calculated {@link module:engine/view/position~Position view position}.\n\t * @param {module:engine/conversion/mapper~Mapper} data.mapper Mapper instance that fired the event.\n\t */\n\n\t/**\n\t * Fired for each view-to-model position mapping request. See {@link module:engine/conversion/mapper~Mapper#event:modelToViewPosition}.\n\t *\n\t * \t\t// See example in `modelToViewPosition` event description.\n\t * \t\t// This custom mapping will map positions from <span> element next to <img> to the \"captionedImage\" element.\n\t *\t\tmapper.on( 'viewToModelPosition', ( evt, data ) => {\n\t *\t\t\tconst positionParent = viewPosition.parent;\n\t *\n\t *\t\t\tif ( positionParent.hasClass( 'image-caption' ) ) {\n\t *\t\t\t\tconst viewImg = positionParent.previousSibling;\n\t *\t\t\t\tconst modelImg = data.mapper.toModelElement( viewImg );\n\t *\n\t *\t\t\t\tdata.modelPosition = new ModelPosition( modelImg, viewPosition.offset );\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * **Note:** default mapping callback is provided with `low` priority setting and does not cancel the event, so it is possible to\n\t * attach a custom callback after default callback and also use `data.modelPosition` calculated by default callback\n\t * (for example to fix it).\n\t *\n\t * **Note:** default mapping callback will not fire if `data.modelPosition` is already set.\n\t *\n\t * **Note:** these callbacks are called **very often**. For efficiency reasons, it is advised to use them only when position\n\t * mapping between given model and view elements is unsolvable using just elements mapping and default algorithm. Also,\n\t * the condition that checks if special case scenario happened should be as simple as possible.\n\t *\n\t * @event viewToModelPosition\n\t * @param {Object} data Data pipeline object that can store and pass data between callbacks. The callback should add\n\t * `modelPosition` value to that object with calculated {@link module:engine/model/position~Position model position}.\n\t * @param {module:engine/conversion/mapper~Mapper} data.mapper Mapper instance that fired the event.\n\t */\n}\n\nmix( Mapper, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/conversion/modelconsumable\n */\n\nimport TextProxy from '../model/textproxy';\n\n/**\n * Manages a list of consumable values for {@link module:engine/model/item~Item model items}.\n *\n * Consumables are various aspects of the model. A model item can be broken down into singular properties that might be\n * taken into consideration when converting that item.\n *\n * `ModelConsumable` is used by {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} while analyzing changed\n * parts of {@link module:engine/model/document~Document the document}. The added / changed / removed model items are broken down\n * into singular properties (the item itself and it's attributes). All those parts are saved in `ModelConsumable`. Then,\n * during conversion, when given part of model item is converted (i.e. the view element has been inserted into the view,\n * but without attributes), consumable value is removed from `ModelConsumable`.\n *\n * For model items, `ModelConsumable` stores consumable values of one of following types: `insert`, `addattribute:<attributeKey>`,\n * `changeattributes:<attributeKey>`, `removeattributes:<attributeKey>`.\n *\n * In most cases, it is enough to let {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}\n * gather consumable values, so there is no need to use\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#add add method} directly.\n * However, it is important to understand how consumable values can be\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed}.\n * See {@link module:engine/conversion/downcasthelpers default downcast converters} for more information.\n *\n * Keep in mind, that one conversion event may have multiple callbacks (converters) attached to it. Each of those is\n * able to convert one or more parts of the model. However, when one of those callbacks actually converts\n * something, other should not, because they would duplicate the results. Using `ModelConsumable` helps avoiding\n * this situation, because callbacks should only convert those values, which were not yet consumed from `ModelConsumable`.\n *\n * Consuming multiple values in a single callback:\n *\n *\t\t// Converter for custom `image` element that might have a `caption` element inside which changes\n *\t\t// how the image is displayed in the view:\n *\t\t//\n *\t\t// Model:\n *\t\t//\n *\t\t// [image]\n *\t\t// └─ [caption]\n *\t\t// └─ foo\n *\t\t//\n *\t\t// View:\n *\t\t//\n *\t\t// <figure>\n *\t\t// ├─ <img />\n *\t\t// └─ <caption>\n *\t\t// └─ foo\n *\t\tmodelConversionDispatcher.on( 'insert:image', ( evt, data, conversionApi ) => {\n *\t\t\t// First, consume the `image` element.\n *\t\t\tconversionApi.consumable.consume( data.item, 'insert' );\n *\n *\t\t\t// Just create normal image element for the view.\n *\t\t\t// Maybe it will be \"decorated\" later.\n *\t\t\tconst viewImage = new ViewElement( 'img' );\n *\t\t\tconst insertPosition = conversionApi.mapper.toViewPosition( data.range.start );\n *\t\t\tconst viewWriter = conversionApi.writer;\n *\n *\t\t\t// Check if the `image` element has children.\n *\t\t\tif ( data.item.childCount > 0 ) {\n *\t\t\t\tconst modelCaption = data.item.getChild( 0 );\n *\n *\t\t\t\t// `modelCaption` insertion change is consumed from consumable values.\n *\t\t\t\t// It will not be converted by other converters, but it's children (probably some text) will be.\n *\t\t\t\t// Through mapping, converters for text will know where to insert contents of `modelCaption`.\n *\t\t\t\tif ( conversionApi.consumable.consume( modelCaption, 'insert' ) ) {\n *\t\t\t\t\tconst viewCaption = new ViewElement( 'figcaption' );\n *\n *\t\t\t\t\tconst viewImageHolder = new ViewElement( 'figure', null, [ viewImage, viewCaption ] );\n *\n *\t\t\t\t\tconversionApi.mapper.bindElements( modelCaption, viewCaption );\n *\t\t\t\t\tconversionApi.mapper.bindElements( data.item, viewImageHolder );\n *\t\t\t\t\tviewWriter.insert( insertPosition, viewImageHolder );\n *\t\t\t\t}\n *\t\t\t} else {\n *\t\t\t\tconversionApi.mapper.bindElements( data.item, viewImage );\n *\t\t\t\tviewWriter.insert( insertPosition, viewImage );\n *\t\t\t}\n *\n *\t\t\tevt.stop();\n *\t\t} );\n */\nexport default class ModelConsumable {\n\t/**\n\t * Creates an empty consumables list.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Contains list of consumable values.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} module:engine/conversion/modelconsumable~ModelConsumable#_consumable\n\t\t */\n\t\tthis._consumable = new Map();\n\n\t\t/**\n\t\t * For each {@link module:engine/model/textproxy~TextProxy} added to `ModelConsumable`, this registry holds parent\n\t\t * of that `TextProxy` and start and end indices of that `TextProxy`. This allows identification of `TextProxy`\n\t\t * instances that points to the same part of the model but are different instances. Each distinct `TextProxy`\n\t\t * is given unique `Symbol` which is then registered as consumable. This process is transparent for `ModelConsumable`\n\t\t * API user because whenever `TextProxy` is added, tested, consumed or reverted, internal mechanisms of\n\t\t * `ModelConsumable` translates `TextProxy` to that unique `Symbol`.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} module:engine/conversion/modelconsumable~ModelConsumable#_textProxyRegistry\n\t\t */\n\t\tthis._textProxyRegistry = new Map();\n\t}\n\n\t/**\n\t * Adds a consumable value to the consumables list and links it with given model item.\n\t *\n\t *\t\tmodelConsumable.add( modelElement, 'insert' ); // Add `modelElement` insertion change to consumable values.\n\t *\t\tmodelConsumable.add( modelElement, 'addAttribute:bold' ); // Add `bold` attribute insertion on `modelElement` change.\n\t *\t\tmodelConsumable.add( modelElement, 'removeAttribute:bold' ); // Add `bold` attribute removal on `modelElement` change.\n\t *\t\tmodelConsumable.add( modelSelection, 'selection' ); // Add `modelSelection` to consumable values.\n\t *\t\tmodelConsumable.add( modelRange, 'range' ); // Add `modelRange` to consumable values.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection|module:engine/model/range~Range} item\n\t * Model item, range or selection that has the consumable.\n\t * @param {String} type Consumable type. Will be normalized to a proper form, that is either `<word>` or `<part>:<part>`.\n\t * Second colon and everything after will be cut. Passing event name is a safe and good practice.\n\t */\n\tadd( item, type ) {\n\t\ttype = _normalizeConsumableType( type );\n\n\t\tif ( item instanceof TextProxy ) {\n\t\t\titem = this._getSymbolForTextProxy( item );\n\t\t}\n\n\t\tif ( !this._consumable.has( item ) ) {\n\t\t\tthis._consumable.set( item, new Map() );\n\t\t}\n\n\t\tthis._consumable.get( item ).set( type, true );\n\t}\n\n\t/**\n\t * Removes given consumable value from given model item.\n\t *\n\t *\t\tmodelConsumable.consume( modelElement, 'insert' ); // Remove `modelElement` insertion change from consumable values.\n\t *\t\tmodelConsumable.consume( modelElement, 'addAttribute:bold' ); // Remove `bold` attribute insertion on `modelElement` change.\n\t *\t\tmodelConsumable.consume( modelElement, 'removeAttribute:bold' ); // Remove `bold` attribute removal on `modelElement` change.\n\t *\t\tmodelConsumable.consume( modelSelection, 'selection' ); // Remove `modelSelection` from consumable values.\n\t *\t\tmodelConsumable.consume( modelRange, 'range' ); // Remove 'modelRange' from consumable values.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection|module:engine/model/range~Range} item\n\t * Model item, range or selection from which consumable will be consumed.\n\t * @param {String} type Consumable type. Will be normalized to a proper form, that is either `<word>` or `<part>:<part>`.\n\t * Second colon and everything after will be cut. Passing event name is a safe and good practice.\n\t * @returns {Boolean} `true` if consumable value was available and was consumed, `false` otherwise.\n\t */\n\tconsume( item, type ) {\n\t\ttype = _normalizeConsumableType( type );\n\n\t\tif ( item instanceof TextProxy ) {\n\t\t\titem = this._getSymbolForTextProxy( item );\n\t\t}\n\n\t\tif ( this.test( item, type ) ) {\n\t\t\tthis._consumable.get( item ).set( type, false );\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Tests whether there is a consumable value of given type connected with given model item.\n\t *\n\t *\t\tmodelConsumable.test( modelElement, 'insert' ); // Check for `modelElement` insertion change.\n\t *\t\tmodelConsumable.test( modelElement, 'addAttribute:bold' ); // Check for `bold` attribute insertion on `modelElement` change.\n\t *\t\tmodelConsumable.test( modelElement, 'removeAttribute:bold' ); // Check for `bold` attribute removal on `modelElement` change.\n\t *\t\tmodelConsumable.test( modelSelection, 'selection' ); // Check if `modelSelection` is consumable.\n\t *\t\tmodelConsumable.test( modelRange, 'range' ); // Check if `modelRange` is consumable.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection|module:engine/model/range~Range} item\n\t * Model item, range or selection to be tested.\n\t * @param {String} type Consumable type. Will be normalized to a proper form, that is either `<word>` or `<part>:<part>`.\n\t * Second colon and everything after will be cut. Passing event name is a safe and good practice.\n\t * @returns {null|Boolean} `null` if such consumable was never added, `false` if the consumable values was\n\t * already consumed or `true` if it was added and not consumed yet.\n\t */\n\ttest( item, type ) {\n\t\ttype = _normalizeConsumableType( type );\n\n\t\tif ( item instanceof TextProxy ) {\n\t\t\titem = this._getSymbolForTextProxy( item );\n\t\t}\n\n\t\tconst itemConsumables = this._consumable.get( item );\n\n\t\tif ( itemConsumables === undefined ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst value = itemConsumables.get( type );\n\n\t\tif ( value === undefined ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn value;\n\t}\n\n\t/**\n\t * Reverts consuming of consumable value.\n\t *\n\t *\t\tmodelConsumable.revert( modelElement, 'insert' ); // Revert consuming `modelElement` insertion change.\n\t *\t\tmodelConsumable.revert( modelElement, 'addAttribute:bold' ); // Revert consuming `bold` attribute insert from `modelElement`.\n\t *\t\tmodelConsumable.revert( modelElement, 'removeAttribute:bold' ); // Revert consuming `bold` attribute remove from `modelElement`.\n\t *\t\tmodelConsumable.revert( modelSelection, 'selection' ); // Revert consuming `modelSelection`.\n\t *\t\tmodelConsumable.revert( modelRange, 'range' ); // Revert consuming `modelRange`.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection|module:engine/model/range~Range} item\n\t * Model item, range or selection to be reverted.\n\t * @param {String} type Consumable type.\n\t * @returns {null|Boolean} `true` if consumable has been reversed, `false` otherwise. `null` if the consumable has\n\t * never been added.\n\t */\n\trevert( item, type ) {\n\t\ttype = _normalizeConsumableType( type );\n\n\t\tif ( item instanceof TextProxy ) {\n\t\t\titem = this._getSymbolForTextProxy( item );\n\t\t}\n\n\t\tconst test = this.test( item, type );\n\n\t\tif ( test === false ) {\n\t\t\tthis._consumable.get( item ).set( type, true );\n\n\t\t\treturn true;\n\t\t} else if ( test === true ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Gets a unique symbol for passed {@link module:engine/model/textproxy~TextProxy} instance. All `TextProxy` instances that\n\t * have same parent, same start index and same end index will get the same symbol.\n\t *\n\t * Used internally to correctly consume `TextProxy` instances.\n\t *\n\t * @private\n\t * @param {module:engine/model/textproxy~TextProxy} textProxy `TextProxy` instance to get a symbol for.\n\t * @returns {Symbol} Symbol representing all equal instances of `TextProxy`.\n\t */\n\t_getSymbolForTextProxy( textProxy ) {\n\t\tlet symbol = null;\n\n\t\tconst startMap = this._textProxyRegistry.get( textProxy.startOffset );\n\n\t\tif ( startMap ) {\n\t\t\tconst endMap = startMap.get( textProxy.endOffset );\n\n\t\t\tif ( endMap ) {\n\t\t\t\tsymbol = endMap.get( textProxy.parent );\n\t\t\t}\n\t\t}\n\n\t\tif ( !symbol ) {\n\t\t\tsymbol = this._addSymbolForTextProxy( textProxy.startOffset, textProxy.endOffset, textProxy.parent );\n\t\t}\n\n\t\treturn symbol;\n\t}\n\n\t/**\n\t * Adds a symbol for given properties that characterizes a {@link module:engine/model/textproxy~TextProxy} instance.\n\t *\n\t * Used internally to correctly consume `TextProxy` instances.\n\t *\n\t * @private\n\t * @param {Number} startIndex Text proxy start index in it's parent.\n\t * @param {Number} endIndex Text proxy end index in it's parent.\n\t * @param {module:engine/model/element~Element} parent Text proxy parent.\n\t * @returns {Symbol} Symbol generated for given properties.\n\t */\n\t_addSymbolForTextProxy( start, end, parent ) {\n\t\tconst symbol = Symbol( 'textProxySymbol' );\n\t\tlet startMap, endMap;\n\n\t\tstartMap = this._textProxyRegistry.get( start );\n\n\t\tif ( !startMap ) {\n\t\t\tstartMap = new Map();\n\t\t\tthis._textProxyRegistry.set( start, startMap );\n\t\t}\n\n\t\tendMap = startMap.get( end );\n\n\t\tif ( !endMap ) {\n\t\t\tendMap = new Map();\n\t\t\tstartMap.set( end, endMap );\n\t\t}\n\n\t\tendMap.set( parent, symbol );\n\n\t\treturn symbol;\n\t}\n}\n\n// Returns a normalized consumable type name from given string. A normalized consumable type name is a string that has\n// at most one colon, for example: `insert` or `addMarker:highlight`. If string to normalize has more \"parts\" (more colons),\n// the other parts are dropped, for example: `addattribute:bold:$text` -> `addattributes:bold`.\n//\n// @param {String} type Consumable type.\n// @returns {String} Normalized consumable type.\nfunction _normalizeConsumableType( type ) {\n\tconst parts = type.split( ':' );\n\n\treturn parts.length > 1 ? parts[ 0 ] + ':' + parts[ 1 ] : parts[ 0 ];\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/conversion/downcastdispatcher\n */\n\nimport Consumable from './modelconsumable';\nimport Range from '../model/range';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { extend } from 'lodash-es';\n\n/**\n * `DowncastDispatcher` is a central point of downcasting (conversion from model to view), which is a process of reacting to changes\n * in the model and firing a set of events. Callbacks listening to those events are called converters. Those\n * converters role is to convert the model changes to changes in view (for example, adding view nodes or\n * changing attributes on view elements).\n *\n * During conversion process, `DowncastDispatcher` fires events, basing on state of the model and prepares\n * data for those events. It is important to understand that those events are connected with changes done on model,\n * for example: \"node has been inserted\" or \"attribute has changed\". This is in a contrary to upcasting (view to model conversion),\n * where we convert view state (view nodes) to a model tree.\n *\n * The events are prepared basing on a diff created by {@link module:engine/model/differ~Differ Differ}, which buffers them\n * and then passes to `DowncastDispatcher` as a diff between old model state and new model state.\n *\n * Note, that because changes are converted there is a need to have a mapping between model structure and view structure.\n * To map positions and elements during downcast (model to view conversion) use {@link module:engine/conversion/mapper~Mapper}.\n *\n * `DowncastDispatcher` fires following events for model tree changes:\n *\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert insert}\n * if a range of nodes has been inserted to the model tree,\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:remove remove}\n * if a range of nodes has been removed from the model tree,\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute attribute}\n * if attribute has been added, changed or removed from a model node.\n *\n * For {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert insert}\n * and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute attribute},\n * `DowncastDispatcher` generates {@link module:engine/conversion/modelconsumable~ModelConsumable consumables}.\n * These are used to have a control over which changes has been already consumed. It is useful when some converters\n * overwrite other or converts multiple changes (for example converts insertion of an element and also converts that\n * element's attributes during insertion).\n *\n * Additionally, `DowncastDispatcher` fires events for {@link module:engine/model/markercollection~Marker marker} changes:\n *\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker} if a marker has been added,\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:removeMarker} if a marker has been removed.\n *\n * Note, that changing a marker is done through removing the marker from the old range, and adding on the new range,\n * so both those events are fired.\n *\n * Finally, `DowncastDispatcher` also handles firing events for {@link module:engine/model/selection model selection}\n * conversion:\n *\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:selection}\n * which converts selection from model to view,\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute}\n * which is fired for every selection attribute,\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}\n * which is fired for every marker which contains selection.\n *\n * Unlike model tree and markers, events for selection are not fired for changes but for selection state.\n *\n * When providing custom listeners for `DowncastDispatcher` remember to check whether given change has not been\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed} yet.\n *\n * When providing custom listeners for `DowncastDispatcher` keep in mind that any callback that had\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed} a value from a consumable and\n * converted the change should also stop the event (for efficiency purposes).\n *\n * When providing custom listeners for `DowncastDispatcher` remember to use provided\n * {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer} to apply changes to the view document.\n *\n * Example of a custom converter for `DowncastDispatcher`:\n *\n *\t\t// We will convert inserting \"paragraph\" model element into the model.\n *\t\tdowncastDispatcher.on( 'insert:paragraph', ( evt, data, conversionApi ) => {\n *\t\t\t// Remember to check whether the change has not been consumed yet and consume it.\n *\t\t\tif ( conversionApi.consumable.consume( data.item, 'insert' ) ) {\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\t// Translate position in model to position in view.\n *\t\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n *\n *\t\t\t// Create <p> element that will be inserted in view at `viewPosition`.\n *\t\t\tconst viewElement = conversionApi.writer.createContainerElement( 'p' );\n *\n *\t\t\t// Bind the newly created view element to model element so positions will map accordingly in future.\n *\t\t\tconversionApi.mapper.bindElements( data.item, viewElement );\n *\n *\t\t\t// Add the newly created view element to the view.\n *\t\t\tconversionApi.writer.insert( viewPosition, viewElement );\n *\n *\t\t\t// Remember to stop the event propagation.\n *\t\t\tevt.stop();\n *\t\t} );\n */\nexport default class DowncastDispatcher {\n\t/**\n\t * Creates a `DowncastDispatcher` instance.\n\t *\n\t * @see module:engine/conversion/downcastdispatcher~DowncastConversionApi\n\t * @param {Object} conversionApi Additional properties for interface that will be passed to events fired\n\t * by `DowncastDispatcher`.\n\t */\n\tconstructor( conversionApi ) {\n\t\t/**\n\t\t * Interface passed by dispatcher to the events callbacks.\n\t\t *\n\t\t * @member {module:engine/conversion/downcastdispatcher~DowncastConversionApi}\n\t\t */\n\t\tthis.conversionApi = extend( { dispatcher: this }, conversionApi );\n\t}\n\n\t/**\n\t * Takes {@link module:engine/model/differ~Differ model differ} object with buffered changes and fires conversion basing on it.\n\t *\n\t * @param {module:engine/model/differ~Differ} differ Differ object with buffered changes.\n\t * @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with converted model.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertChanges( differ, markers, writer ) {\n\t\t// Before the view is updated, remove markers which have changed.\n\t\tfor ( const change of differ.getMarkersToRemove() ) {\n\t\t\tthis.convertMarkerRemove( change.name, change.range, writer );\n\t\t}\n\n\t\t// Convert changes that happened on model tree.\n\t\tfor ( const entry of differ.getChanges() ) {\n\t\t\tif ( entry.type == 'insert' ) {\n\t\t\t\tthis.convertInsert( Range._createFromPositionAndShift( entry.position, entry.length ), writer );\n\t\t\t} else if ( entry.type == 'remove' ) {\n\t\t\t\tthis.convertRemove( entry.position, entry.length, entry.name, writer );\n\t\t\t} else {\n\t\t\t\t// entry.type == 'attribute'.\n\t\t\t\tthis.convertAttribute( entry.range, entry.attributeKey, entry.attributeOldValue, entry.attributeNewValue, writer );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const markerName of this.conversionApi.mapper.flushUnboundMarkerNames() ) {\n\t\t\tconst markerRange = markers.get( markerName ).getRange();\n\n\t\t\tthis.convertMarkerRemove( markerName, markerRange, writer );\n\t\t\tthis.convertMarkerAdd( markerName, markerRange, writer );\n\t\t}\n\n\t\t// After the view is updated, convert markers which have changed.\n\t\tfor ( const change of differ.getMarkersToAdd() ) {\n\t\t\tthis.convertMarkerAdd( change.name, change.range, writer );\n\t\t}\n\t}\n\n\t/**\n\t * Starts conversion of a range insertion.\n\t *\n\t * For each node in the range, {@link #event:insert insert event is fired}. For each attribute on each node,\n\t * {@link #event:attribute attribute event is fired}.\n\t *\n\t * @fires insert\n\t * @fires attribute\n\t * @param {module:engine/model/range~Range} range Inserted range.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertInsert( range, writer ) {\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create a list of things that can be consumed, consisting of nodes and their attributes.\n\t\tthis.conversionApi.consumable = this._createInsertConsumable( range );\n\n\t\t// Fire a separate insert event for each node and text fragment contained in the range.\n\t\tfor ( const value of range ) {\n\t\t\tconst item = value.item;\n\t\t\tconst itemRange = Range._createFromPositionAndShift( value.previousPosition, value.length );\n\t\t\tconst data = {\n\t\t\t\titem,\n\t\t\t\trange: itemRange\n\t\t\t};\n\n\t\t\tthis._testAndFire( 'insert', data );\n\n\t\t\t// Fire a separate addAttribute event for each attribute that was set on inserted items.\n\t\t\t// This is important because most attributes converters will listen only to add/change/removeAttribute events.\n\t\t\t// If we would not add this part, attributes on inserted nodes would not be converted.\n\t\t\tfor ( const key of item.getAttributeKeys() ) {\n\t\t\t\tdata.attributeKey = key;\n\t\t\t\tdata.attributeOldValue = null;\n\t\t\t\tdata.attributeNewValue = item.getAttribute( key );\n\n\t\t\t\tthis._testAndFire( `attribute:${ key }`, data );\n\t\t\t}\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Fires conversion of a single node removal. Fires {@link #event:remove remove event} with provided data.\n\t *\n\t * @param {module:engine/model/position~Position} position Position from which node was removed.\n\t * @param {Number} length Offset size of removed node.\n\t * @param {String} name Name of removed node.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertRemove( position, length, name, writer ) {\n\t\tthis.conversionApi.writer = writer;\n\n\t\tthis.fire( 'remove:' + name, { position, length }, this.conversionApi );\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Starts conversion of attribute change on given `range`.\n\t *\n\t * For each node in the given `range`, {@link #event:attribute attribute event} is fired with the passed data.\n\t *\n\t * @fires attribute\n\t * @param {module:engine/model/range~Range} range Changed range.\n\t * @param {String} key Key of the attribute that has changed.\n\t * @param {*} oldValue Attribute value before the change or `null` if the attribute has not been set before.\n\t * @param {*} newValue New attribute value or `null` if the attribute has been removed.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertAttribute( range, key, oldValue, newValue, writer ) {\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create a list with attributes to consume.\n\t\tthis.conversionApi.consumable = this._createConsumableForRange( range, `attribute:${ key }` );\n\n\t\t// Create a separate attribute event for each node in the range.\n\t\tfor ( const value of range ) {\n\t\t\tconst item = value.item;\n\t\t\tconst itemRange = Range._createFromPositionAndShift( value.previousPosition, value.length );\n\t\t\tconst data = {\n\t\t\t\titem,\n\t\t\t\trange: itemRange,\n\t\t\t\tattributeKey: key,\n\t\t\t\tattributeOldValue: oldValue,\n\t\t\t\tattributeNewValue: newValue\n\t\t\t};\n\n\t\t\tthis._testAndFire( `attribute:${ key }`, data );\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Starts model selection conversion.\n\t *\n\t * Fires events for given {@link module:engine/model/selection~Selection selection} to start selection conversion.\n\t *\n\t * @fires selection\n\t * @fires addMarker\n\t * @fires attribute\n\t * @param {module:engine/model/selection~Selection} selection Selection to convert.\n\t * @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with converted model.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertSelection( selection, markers, writer ) {\n\t\tconst markersAtSelection = Array.from( markers.getMarkersAtPosition( selection.getFirstPosition() ) );\n\n\t\tthis.conversionApi.writer = writer;\n\t\tthis.conversionApi.consumable = this._createSelectionConsumable( selection, markersAtSelection );\n\n\t\tthis.fire( 'selection', { selection }, this.conversionApi );\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const marker of markersAtSelection ) {\n\t\t\tconst markerRange = marker.getRange();\n\n\t\t\tif ( !shouldMarkerChangeBeConverted( selection.getFirstPosition(), marker, this.conversionApi.mapper ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst data = {\n\t\t\t\titem: selection,\n\t\t\t\tmarkerName: marker.name,\n\t\t\t\tmarkerRange\n\t\t\t};\n\n\t\t\tif ( this.conversionApi.consumable.test( selection, 'addMarker:' + marker.name ) ) {\n\t\t\t\tthis.fire( 'addMarker:' + marker.name, data, this.conversionApi );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const key of selection.getAttributeKeys() ) {\n\t\t\tconst data = {\n\t\t\t\titem: selection,\n\t\t\t\trange: selection.getFirstRange(),\n\t\t\t\tattributeKey: key,\n\t\t\t\tattributeOldValue: null,\n\t\t\t\tattributeNewValue: selection.getAttribute( key )\n\t\t\t};\n\n\t\t\t// Do not fire event if the attribute has been consumed.\n\t\t\tif ( this.conversionApi.consumable.test( selection, 'attribute:' + data.attributeKey ) ) {\n\t\t\t\tthis.fire( 'attribute:' + data.attributeKey + ':$text', data, this.conversionApi );\n\t\t\t}\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Converts added marker. Fires {@link #event:addMarker addMarker} event for each item\n\t * in marker's range. If range is collapsed single event is dispatched. See event description for more details.\n\t *\n\t * @fires addMarker\n\t * @param {String} markerName Marker name.\n\t * @param {module:engine/model/range~Range} markerRange Marker range.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertMarkerAdd( markerName, markerRange, writer ) {\n\t\t// Do not convert if range is in graveyard or not in the document (e.g. in DocumentFragment).\n\t\tif ( !markerRange.root.document || markerRange.root.rootName == '$graveyard' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// In markers' case, event name == consumable name.\n\t\tconst eventName = 'addMarker:' + markerName;\n\n\t\t//\n\t\t// First, fire an event for the whole marker.\n\t\t//\n\t\tconst consumable = new Consumable();\n\t\tconsumable.add( markerRange, eventName );\n\n\t\tthis.conversionApi.consumable = consumable;\n\n\t\tthis.fire( eventName, { markerName, markerRange }, this.conversionApi );\n\n\t\t//\n\t\t// Do not fire events for each item inside the range if the range got consumed.\n\t\t//\n\t\tif ( !consumable.test( markerRange, eventName ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t//\n\t\t// Then, fire an event for each item inside the marker range.\n\t\t//\n\t\tthis.conversionApi.consumable = this._createConsumableForRange( markerRange, eventName );\n\n\t\tfor ( const item of markerRange.getItems() ) {\n\t\t\t// Do not fire event for already consumed items.\n\t\t\tif ( !this.conversionApi.consumable.test( item, eventName ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst data = { item, range: Range._createOn( item ), markerName, markerRange };\n\n\t\t\tthis.fire( eventName, data, this.conversionApi );\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Fires conversion of marker removal. Fires {@link #event:removeMarker removeMarker} event with provided data.\n\t *\n\t * @fires removeMarker\n\t * @param {String} markerName Marker name.\n\t * @param {module:engine/model/range~Range} markerRange Marker range.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertMarkerRemove( markerName, markerRange, writer ) {\n\t\t// Do not convert if range is in graveyard or not in the document (e.g. in DocumentFragment).\n\t\tif ( !markerRange.root.document || markerRange.root.rootName == '$graveyard' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.conversionApi.writer = writer;\n\n\t\tthis.fire( 'removeMarker:' + markerName, { markerName, markerRange }, this.conversionApi );\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} with values to consume from given range,\n\t * assuming that the range has just been inserted to the model.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range Inserted range.\n\t * @returns {module:engine/conversion/modelconsumable~ModelConsumable} Values to consume.\n\t */\n\t_createInsertConsumable( range ) {\n\t\tconst consumable = new Consumable();\n\n\t\tfor ( const value of range ) {\n\t\t\tconst item = value.item;\n\n\t\t\tconsumable.add( item, 'insert' );\n\n\t\t\tfor ( const key of item.getAttributeKeys() ) {\n\t\t\t\tconsumable.add( item, 'attribute:' + key );\n\t\t\t}\n\t\t}\n\n\t\treturn consumable;\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} with values to consume for given range.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range Affected range.\n\t * @param {String} type Consumable type.\n\t * @returns {module:engine/conversion/modelconsumable~ModelConsumable} Values to consume.\n\t */\n\t_createConsumableForRange( range, type ) {\n\t\tconst consumable = new Consumable();\n\n\t\tfor ( const item of range.getItems() ) {\n\t\t\tconsumable.add( item, type );\n\t\t}\n\n\t\treturn consumable;\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} with selection consumable values.\n\t *\n\t * @private\n\t * @param {module:engine/model/selection~Selection} selection Selection to create consumable from.\n\t * @param {Iterable.<module:engine/model/markercollection~Marker>} markers Markers which contains selection.\n\t * @returns {module:engine/conversion/modelconsumable~ModelConsumable} Values to consume.\n\t */\n\t_createSelectionConsumable( selection, markers ) {\n\t\tconst consumable = new Consumable();\n\n\t\tconsumable.add( selection, 'selection' );\n\n\t\tfor ( const marker of markers ) {\n\t\t\tconsumable.add( selection, 'addMarker:' + marker.name );\n\t\t}\n\n\t\tfor ( const key of selection.getAttributeKeys() ) {\n\t\t\tconsumable.add( selection, 'attribute:' + key );\n\t\t}\n\n\t\treturn consumable;\n\t}\n\n\t/**\n\t * Tests passed `consumable` to check whether given event can be fired and if so, fires it.\n\t *\n\t * @private\n\t * @fires insert\n\t * @fires attribute\n\t * @param {String} type Event type.\n\t * @param {Object} data Event data.\n\t */\n\t_testAndFire( type, data ) {\n\t\tif ( !this.conversionApi.consumable.test( data.item, type ) ) {\n\t\t\t// Do not fire event if the item was consumed.\n\t\t\treturn;\n\t\t}\n\n\t\tconst name = data.item.name || '$text';\n\n\t\tthis.fire( type + ':' + name, data, this.conversionApi );\n\t}\n\n\t/**\n\t * Clears conversion API object.\n\t *\n\t * @private\n\t */\n\t_clearConversionApi() {\n\t\tdelete this.conversionApi.writer;\n\t\tdelete this.conversionApi.consumable;\n\t}\n\n\t/**\n\t * Fired for inserted nodes.\n\t *\n\t * `insert` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `insert:name`. `name` is either `'$text'`, when {@link module:engine/model/text~Text a text node} has been inserted,\n\t * or {@link module:engine/model/element~Element#name name} of inserted element.\n\t *\n\t * This way listeners can either listen to a general `insert` event or specific event (for example `insert:paragraph`).\n\t *\n\t * @event insert\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/item~Item} data.item Inserted item.\n\t * @param {module:engine/model/range~Range} data.range Range spanning over inserted item.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired for removed nodes.\n\t *\n\t * `remove` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `remove:name`. `name` is either `'$text'`, when {@link module:engine/model/text~Text a text node} has been removed,\n\t * or the {@link module:engine/model/element~Element#name name} of removed element.\n\t *\n\t * This way listeners can either listen to a general `remove` event or specific event (for example `remove:paragraph`).\n\t *\n\t * @event remove\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/position~Position} data.position Position from which the node has been removed.\n\t * @param {Number} data.length Offset size of the removed node.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired in the following cases:\n\t *\n\t * * when an attribute has been added, changed, or removed from a node,\n\t * * when a node with an attribute is inserted,\n\t * * when collapsed model selection attribute is converted.\n\t *\n\t * `attribute` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `attribute:attributeKey:name`. `attributeKey` is the key of added/changed/removed attribute.\n\t * `name` is either `'$text'` if change was on {@link module:engine/model/text~Text a text node},\n\t * or the {@link module:engine/model/element~Element#name name} of element which attribute has changed.\n\t *\n\t * This way listeners can either listen to a general `attribute:bold` event or specific event (for example `attribute:src:image`).\n\t *\n\t * @event attribute\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/item~Item|module:engine/model/documentselection~DocumentSelection} data.item Changed item\n\t * or converted selection.\n\t * @param {module:engine/model/range~Range} data.range Range spanning over changed item or selection range.\n\t * @param {String} data.attributeKey Attribute key.\n\t * @param {*} data.attributeOldValue Attribute value before the change. This is `null` when selection attribute is converted.\n\t * @param {*} data.attributeNewValue New attribute value.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired for {@link module:engine/model/selection~Selection selection} changes.\n\t *\n\t * @event selection\n\t * @param {module:engine/model/selection~Selection} selection Selection that is converted.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired when a new marker is added to the model. Also fired when collapsed model selection that is inside marker is converted.\n\t *\n\t * `addMarker` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `addMarker:markerName`. By specifying certain marker names, you can make the events even more gradual. For example,\n\t * if markers are named `foo:abc`, `foo:bar`, then it is possible to listen to `addMarker:foo` or `addMarker:foo:abc` and\n\t * `addMarker:foo:bar` events.\n\t *\n\t * If the marker range is not collapsed:\n\t *\n\t * * the event is fired for each item in the marker range one by one,\n\t * * `conversionApi.consumable` includes each item of the marker range and the consumable value is same as event name.\n\t *\n\t * If the marker range is collapsed:\n\t *\n\t * * there is only one event,\n\t * * `conversionApi.consumable` includes marker range with event name.\n\t *\n\t * If selection inside a marker is converted:\n\t *\n\t * * there is only one event,\n\t * * `conversionApi.consumable` includes selection instance with event name.\n\t *\n\t * @event addMarker\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection} data.item Item inside the new marker or\n\t * the selection that is being converted.\n\t * @param {module:engine/model/range~Range} [data.range] Range spanning over converted item. Available only in marker conversion, if\n\t * the marker range was not collapsed.\n\t * @param {module:engine/model/range~Range} data.markerRange Marker range.\n\t * @param {String} data.markerName Marker name.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired when marker is removed from the model.\n\t *\n\t * `removeMarker` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `removeMarker:markerName`. By specifying certain marker names, you can make the events even more gradual. For example,\n\t * if markers are named `foo:abc`, `foo:bar`, then it is possible to listen to `removeMarker:foo` or `removeMarker:foo:abc` and\n\t * `removeMarker:foo:bar` events.\n\t *\n\t * @event removeMarker\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/range~Range} data.markerRange Marker range.\n\t * @param {String} data.markerName Marker name.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n}\n\nmix( DowncastDispatcher, EmitterMixin );\n\n// Helper function, checks whether change of `marker` at `modelPosition` should be converted. Marker changes are not\n// converted if they happen inside an element with custom conversion method.\n//\n// @param {module:engine/model/position~Position} modelPosition\n// @param {module:engine/model/markercollection~Marker} marker\n// @param {module:engine/conversion/mapper~Mapper} mapper\n// @returns {Boolean}\nfunction shouldMarkerChangeBeConverted( modelPosition, marker, mapper ) {\n\tconst range = marker.getRange();\n\tconst ancestors = Array.from( modelPosition.getAncestors() );\n\tancestors.shift(); // Remove root element. It cannot be passed to `model.Range#containsItem`.\n\tancestors.reverse();\n\n\tconst hasCustomHandling = ancestors.some( element => {\n\t\tif ( range.containsItem( element ) ) {\n\t\t\tconst viewElement = mapper.toViewElement( element );\n\n\t\t\treturn !!viewElement.getCustomProperty( 'addHighlight' );\n\t\t}\n\t} );\n\n\treturn !hasCustomHandling;\n}\n\n/**\n * Conversion interface that is registered for given {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}\n * and is passed as one of parameters when {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher dispatcher}\n * fires it's events.\n *\n * @interface module:engine/conversion/downcastdispatcher~DowncastConversionApi\n */\n\n/**\n * The {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} instance.\n *\n * @member {module:engine/conversion/downcastdispatcher~DowncastDispatcher} #dispatcher\n */\n\n/**\n * Stores information about what parts of processed model item are still waiting to be handled. After a piece of model item\n * was converted, appropriate consumable value should be {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed}.\n *\n * @member {module:engine/conversion/modelconsumable~ModelConsumable} #consumable\n */\n\n/**\n * The {@link module:engine/conversion/mapper~Mapper} instance.\n *\n * @member {module:engine/conversion/mapper~Mapper} #mapper\n */\n\n/**\n * The {@link module:engine/view/downcastwriter~DowncastWriter} instance used to manipulate data during conversion.\n *\n * @member {module:engine/view/downcastwriter~DowncastWriter} #writer\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/selection\n */\n\nimport Position from './position';\nimport Element from './element';\nimport Node from './node';\nimport Range from './range';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\n/**\n * Selection is a set of {@link module:engine/model/range~Range ranges}. It has a direction specified by its\n * {@link module:engine/model/selection~Selection#anchor anchor} and {@link module:engine/model/selection~Selection#focus focus}\n * (it can be {@link module:engine/model/selection~Selection#isBackward forward or backward}).\n * Additionally, selection may have its own attributes (think – whether text typed in in this selection\n * should have those attributes – e.g. whether you type a bolded text).\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Selection {\n\t/**\n\t * Creates a new selection instance based on the given {@link module:engine/model/selection~Selectable selectable}\n\t * or creates an empty selection if no arguments were passed.\n\t *\n\t *\t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t *\t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the given document selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst documentSelection = model.document.selection;\n\t *\t\tconst selection = writer.createSelection( documentSelection );\n\t *\n\t *\t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates selection at the given offset in the given element.\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/model/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * Selection's constructor allow passing additional options (`'backward'`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t */\n\tconstructor( selectable, placeOrOffset, options ) {\n\t\t/**\n\t\t * Specifies whether the last added range was added as a backward or forward range.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._lastRangeBackward = false;\n\n\t\t/**\n\t\t * Stores selection ranges.\n\t\t *\n\t\t * @protected\n\t\t * @type {Array.<module:engine/model/range~Range>}\n\t\t */\n\t\tthis._ranges = [];\n\n\t\t/**\n\t\t * List of attributes set on current selection.\n\t\t *\n\t\t * @protected\n\t\t * @type {Map.<String,*>}\n\t\t */\n\t\tthis._attrs = new Map();\n\n\t\tif ( selectable ) {\n\t\t\tthis.setTo( selectable, placeOrOffset, options );\n\t\t}\n\t}\n\n\t/**\n\t * Selection anchor. Anchor is the position from which the selection was started. If a user is making a selection\n\t * by dragging the mouse, the anchor is where the user pressed the mouse button (the beggining of the selection).\n\t *\n\t * Anchor and {@link #focus} define the direction of the selection, which is important\n\t * when expanding/shrinking selection. The focus moves, while the anchor should remain in the same place.\n\t *\n\t * Anchor is always set to the {@link module:engine/model/range~Range#start start} or\n\t * {@link module:engine/model/range~Range#end end} position of the last of selection's ranges. Whether it is\n\t * the `start` or `end` depends on the specified `options.backward`. See the {@link #setTo `setTo()`} method.\n\t *\n\t * May be set to `null` if there are no ranges in the selection.\n\t *\n\t * @see #focus\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget anchor() {\n\t\tif ( this._ranges.length > 0 ) {\n\t\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\n\t\t\treturn this._lastRangeBackward ? range.end : range.start;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Selection focus. Focus is the position where the selection ends. If a user is making a selection\n\t * by dragging the mouse, the focus is where the mouse cursor is.\n\t *\n\t * May be set to `null` if there are no ranges in the selection.\n\t *\n\t * @see #anchor\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget focus() {\n\t\tif ( this._ranges.length > 0 ) {\n\t\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\n\t\t\treturn this._lastRangeBackward ? range.start : range.end;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Whether the selection is collapsed. Selection is collapsed when there is exactly one range in it\n\t * and it is collapsed.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\tconst length = this._ranges.length;\n\n\t\tif ( length === 1 ) {\n\t\t\treturn this._ranges[ 0 ].isCollapsed;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the number of ranges in the selection.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._ranges.length;\n\t}\n\n\t/**\n\t * Specifies whether the selection's {@link #focus} precedes the selection's {@link #anchor}.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn !this.isCollapsed && this._lastRangeBackward;\n\t}\n\n\t/**\n\t * Checks whether this selection is equal to the given selection. Selections are equal if they have the same directions,\n\t * the same number of ranges and all ranges from one selection equal to ranges from the another selection.\n\t *\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are equal, `false` otherwise.\n\t */\n\tisEqual( otherSelection ) {\n\t\tif ( this.rangeCount != otherSelection.rangeCount ) {\n\t\t\treturn false;\n\t\t} else if ( this.rangeCount === 0 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ( !this.anchor.isEqual( otherSelection.anchor ) || !this.focus.isEqual( otherSelection.focus ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor ( const thisRange of this._ranges ) {\n\t\t\tlet found = false;\n\n\t\t\tfor ( const otherRange of otherSelection._ranges ) {\n\t\t\t\tif ( thisRange.isEqual( otherRange ) ) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( !found ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns an iterable object that iterates over copies of selection ranges.\n\t *\n\t * @returns {Iterable.<module:engine/model/range~Range>}\n\t */\n\t* getRanges() {\n\t\tfor ( const range of this._ranges ) {\n\t\t\tyield new Range( range.start, range.end );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a copy of the first range in the selection.\n\t * First range is the one which {@link module:engine/model/range~Range#start start} position\n\t * {@link module:engine/model/position~Position#isBefore is before} start position of all other ranges\n\t * (not to confuse with the first range added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\tlet first = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !first || range.start.isBefore( first.start ) ) {\n\t\t\t\tfirst = range;\n\t\t\t}\n\t\t}\n\n\t\treturn first ? new Range( first.start, first.end ) : null;\n\t}\n\n\t/**\n\t * Returns a copy of the last range in the selection.\n\t * Last range is the one which {@link module:engine/model/range~Range#end end} position\n\t * {@link module:engine/model/position~Position#isAfter is after} end position of all other ranges (not to confuse with the range most\n\t * recently added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\tlet last = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !last || range.end.isAfter( last.end ) ) {\n\t\t\t\tlast = range;\n\t\t\t}\n\t\t}\n\n\t\treturn last ? new Range( last.start, last.end ) : null;\n\t}\n\n\t/**\n\t * Returns the first position in the selection.\n\t * First position is the position that {@link module:engine/model/position~Position#isBefore is before}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\tconst first = this.getFirstRange();\n\n\t\treturn first ? first.start.clone() : null;\n\t}\n\n\t/**\n\t * Returns the last position in the selection.\n\t * Last position is the position that {@link module:engine/model/position~Position#isAfter is after}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\tconst lastRange = this.getLastRange();\n\n\t\treturn lastRange ? lastRange.end.clone() : null;\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/model/selection~Selectable selectable}.\n\t *\n\t *\t\t// Removes all selection's ranges.\n\t *\t\tselection.setTo( null );\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tselection.setTo( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t *\t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tselection.setTo( ranges );\n\t *\n\t *\t\t// Sets selection to other selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tselection.setTo( otherSelection );\n\t *\n\t *\t\t// Sets selection to the given document selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst documentSelection = new DocumentSelection( doc );\n\t *\t\tselection.setTo( documentSelection );\n\t *\n\t *\t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tselection.setTo( position );\n\t *\n\t *\t\t// Sets collapsed selection at the position of the given node and an offset.\n\t *\t\tselection.setTo( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of\n \t * that element and ends after the last child of that element.\n\t *\n\t *\t\tselection.setTo( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\tselection.setTo( paragraph, 'on' );\n\t *\n\t * `Selection#setTo()`' method allow passing additional options (`backward`) as the last argument.\n\t *\n\t *\t\t// Sets backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t */\n\tsetTo( selectable, placeOrOffset, options ) {\n\t\tif ( selectable === null ) {\n\t\t\tthis._setRanges( [] );\n\t\t} else if ( selectable instanceof Selection ) {\n\t\t\tthis._setRanges( selectable.getRanges(), selectable.isBackward );\n\t\t} else if ( selectable && typeof selectable.getRanges == 'function' ) {\n\t\t\t// We assume that the selectable is a DocumentSelection.\n\t\t\t// It can't be imported here, because it would lead to circular imports.\n\t\t\tthis._setRanges( selectable.getRanges(), selectable.isBackward );\n\t\t} else if ( selectable instanceof Range ) {\n\t\t\tthis._setRanges( [ selectable ], !!placeOrOffset && !!placeOrOffset.backward );\n\t\t} else if ( selectable instanceof Position ) {\n\t\t\tthis._setRanges( [ new Range( selectable ) ] );\n\t\t} else if ( selectable instanceof Node ) {\n\t\t\tconst backward = !!options && !!options.backward;\n\t\t\tlet range;\n\n\t\t\tif ( placeOrOffset == 'in' ) {\n\t\t\t\trange = Range._createIn( selectable );\n\t\t\t} else if ( placeOrOffset == 'on' ) {\n\t\t\t\trange = Range._createOn( selectable );\n\t\t\t} else if ( placeOrOffset !== undefined ) {\n\t\t\t\trange = new Range( Position._createAt( selectable, placeOrOffset ) );\n\t\t\t} else {\n\t\t\t\t/**\n\t\t\t\t * selection.setTo requires the second parameter when the first parameter is a node.\n\t\t\t\t *\n\t\t\t\t * @error model-selection-setTo-required-second-parameter\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-selection-setTo-required-second-parameter: ' +\n\t\t\t\t\t'selection.setTo requires the second parameter when the first parameter is a node.',\n\t\t\t\t\t[ this, selectable ]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis._setRanges( [ range ], backward );\n\t\t} else if ( isIterable( selectable ) ) {\n\t\t\t// We assume that the selectable is an iterable of ranges.\n\t\t\tthis._setRanges( selectable, placeOrOffset && !!placeOrOffset.backward );\n\t\t} else {\n\t\t\t/**\n\t\t\t * Cannot set the selection to the given place.\n\t\t\t *\n\t\t\t * Invalid parameters were specified when setting the selection. Common issues:\n\t\t\t *\n\t\t\t * * A {@link module:engine/model/textproxy~TextProxy} instance was passed instead of\n\t\t\t * a real {@link module:engine/model/text~Text}.\n\t\t\t * * View nodes were passed instead of model nodes.\n\t\t\t * * `null`/`undefined` was passed.\n\t\t\t *\n\t\t\t * @error model-selection-setTo-not-selectable\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-selection-setTo-not-selectable: Cannot set the selection to the given place.',\n\t\t\t\t[ this, selectable ]\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Replaces all ranges that were added to the selection with given array of ranges. Last range of the array\n\t * is treated like the last added range and is used to set {@link module:engine/model/selection~Selection#anchor} and\n\t * {@link module:engine/model/selection~Selection#focus}. Accepts a flag describing in which direction the selection is made.\n\t *\n\t * @protected\n\t * @fires change:range\n\t * @param {Iterable.<module:engine/model/range~Range>} newRanges Ranges to set.\n\t * @param {Boolean} [isLastBackward=false] Flag describing if last added range was selected forward - from start to end (`false`)\n\t * or backward - from end to start (`true`).\n\t */\n\t_setRanges( newRanges, isLastBackward = false ) {\n\t\tnewRanges = Array.from( newRanges );\n\n\t\t// Check whether there is any range in new ranges set that is different than all already added ranges.\n\t\tconst anyNewRange = newRanges.some( newRange => {\n\t\t\tif ( !( newRange instanceof Range ) ) {\n\t\t\t\t/**\n\t\t\t\t * Selection range set to an object that is not an instance of {@link module:engine/model/range~Range}.\n\t\t\t\t *\n\t\t\t\t * Only {@link module:engine/model/range~Range} instances can be used to set a selection.\n\t\t\t\t * Common mistakes leading to this error are:\n\t\t\t\t *\n\t\t\t\t * * using DOM `Range` object,\n\t\t\t\t * * incorrect CKEditor 5 installation with multiple `ckeditor5-engine` packages having different versions.\n\t\t\t\t *\n\t\t\t\t * @error model-selection-set-ranges-not-range\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-selection-set-ranges-not-range: ' +\n\t\t\t\t\t'Selection range set to an object that is not an instance of model.Range.',\n\t\t\t\t\t[ this, newRanges ]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn this._ranges.every( oldRange => {\n\t\t\t\treturn !oldRange.isEqual( newRange );\n\t\t\t} );\n\t\t} );\n\n\t\t// Don't do anything if nothing changed.\n\t\tif ( newRanges.length === this._ranges.length && !anyNewRange ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._removeAllRanges();\n\n\t\tfor ( const range of newRanges ) {\n\t\t\tthis._pushRange( range );\n\t\t}\n\n\t\tthis._lastRangeBackward = !!isLastBackward;\n\n\t\tthis.fire( 'change:range', { directChange: true } );\n\t}\n\n\t/**\n\t * Moves {@link module:engine/model/selection~Selection#focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as\n\t * {@link module:engine/model/writer~Writer#createPositionAt writer.createPositionAt()} parameters.\n\t *\n\t * @fires change:range\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tsetFocus( itemOrPosition, offset ) {\n\t\tif ( this.anchor === null ) {\n\t\t\t/**\n\t\t\t * Cannot set selection focus if there are no ranges in selection.\n\t\t\t *\n\t\t\t * @error model-selection-setFocus-no-ranges\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-selection-setFocus-no-ranges: Cannot set selection focus if there are no ranges in selection.',\n\t\t\t\t[ this, itemOrPosition ]\n\t\t\t);\n\t\t}\n\n\t\tconst newFocus = Position._createAt( itemOrPosition, offset );\n\n\t\tif ( newFocus.compareWith( this.focus ) == 'same' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst anchor = this.anchor;\n\n\t\tif ( this._ranges.length ) {\n\t\t\tthis._popRange();\n\t\t}\n\n\t\tif ( newFocus.compareWith( anchor ) == 'before' ) {\n\t\t\tthis._pushRange( new Range( newFocus, anchor ) );\n\t\t\tthis._lastRangeBackward = true;\n\t\t} else {\n\t\t\tthis._pushRange( new Range( anchor, newFocus ) );\n\t\t\tthis._lastRangeBackward = false;\n\t\t}\n\n\t\tthis.fire( 'change:range', { directChange: true } );\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on the selection.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this._attrs.get( key );\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this._attrs.entries();\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attribute keys.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this._attrs.keys();\n\t}\n\n\t/**\n\t * Checks if the selection has an attribute for given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on selection, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this._attrs.has( key );\n\t}\n\n\t/**\n\t * Removes an attribute with given key from the selection.\n\t *\n\t * If given attribute was set on the selection, fires the {@link #event:change:range} event with\n\t * removed attribute key.\n\t *\n\t * @fires change:attribute\n\t * @param {String} key Key of attribute to remove.\n\t */\n\tremoveAttribute( key ) {\n\t\tif ( this.hasAttribute( key ) ) {\n\t\t\tthis._attrs.delete( key );\n\n\t\t\tthis.fire( 'change:attribute', { attributeKeys: [ key ], directChange: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Sets attribute on the selection. If attribute with the same key already is set, it's value is overwritten.\n\t *\n\t * If the attribute value has changed, fires the {@link #event:change:range} event with\n\t * the attribute key.\n\t *\n\t * @fires change:attribute\n\t * @param {String} key Key of attribute to set.\n\t * @param {*} value Attribute value.\n\t */\n\tsetAttribute( key, value ) {\n\t\tif ( this.getAttribute( key ) !== value ) {\n\t\t\tthis._attrs.set( key, value );\n\n\t\t\tthis.fire( 'change:attribute', { attributeKeys: [ key ], directChange: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/model/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\tif ( this.rangeCount !== 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst range = this.getFirstRange();\n\t\tconst nodeAfterStart = range.start.nodeAfter;\n\t\tconst nodeBeforeEnd = range.end.nodeBefore;\n\n\t\treturn ( nodeAfterStart instanceof Element && nodeAfterStart == nodeBeforeEnd ) ? nodeAfterStart : null;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tselection.is( 'selection' ); // -> true\n\t *\t\tselection.is( 'model:selection' ); // -> true\n\t *\n\t *\t\tselection.is( 'view:selection' ); // -> false\n\t *\t\tselection.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'selection' || type == 'model:selection';\n\t}\n\n\t/**\n\t * Gets elements of type {@link module:engine/model/schema~Schema#isBlock \"block\"} touched by the selection.\n\t *\n\t * This method's result can be used for example to apply block styling to all blocks covered by this selection.\n\t *\n\t * **Note:** `getSelectedBlocks()` returns blocks that are nested in other non-block elements\n\t * but will not return blocks nested in other blocks.\n\t *\n\t * In this case the function will return exactly all 3 paragraphs (note: `<blockQuote>` is not a block itself):\n\t *\n\t *\t\t<paragraph>[a</paragraph>\n\t *\t\t<blockQuote>\n\t *\t\t\t<paragraph>b</paragraph>\n\t *\t\t</blockQuote>\n\t *\t\t<paragraph>c]d</paragraph>\n\t *\n\t * In this case the paragraph will also be returned, despite the collapsed selection:\n\t *\n\t *\t\t<paragraph>[]a</paragraph>\n\t *\n\t * In such a scenario, however, only blocks A, B & E will be returned as blocks C & D are nested in block B:\n\t *\n\t *\t\t[<blockA></blockA>\n\t *\t\t<blockB>\n\t *\t\t\t<blockC></blockC>\n\t *\t\t\t<blockD></blockD>\n\t *\t\t</blockB>\n\t *\t\t<blockE></blockE>]\n\t *\n\t * If the selection is inside a block all the inner blocks (A & B) are returned:\n\t *\n\t * \t\t<block>\n\t *\t\t\t<blockA>[a</blockA>\n\t * \t\t\t<blockB>b]</blockB>\n\t * \t\t</block>\n\t *\n\t * **Special case**: If a selection ends at the beginning of a block, that block is not returned as from user perspective\n\t * this block wasn't selected. See [#984](https://github.com/ckeditor/ckeditor5-engine/issues/984) for more details.\n\t *\n\t *\t\t<paragraph>[a</paragraph>\n\t *\t\t<paragraph>b</paragraph>\n\t *\t\t<paragraph>]c</paragraph> // this block will not be returned\n\t *\n\t * @returns {Iterable.<module:engine/model/element~Element>}\n\t */\n\t* getSelectedBlocks() {\n\t\tconst visited = new WeakSet();\n\n\t\tfor ( const range of this.getRanges() ) {\n\t\t\t// Get start block of range in case of a collapsed range.\n\t\t\tconst startBlock = getParentBlock( range.start, visited );\n\n\t\t\tif ( startBlock && isTopBlockInRange( startBlock, range ) ) {\n\t\t\t\tyield startBlock;\n\t\t\t}\n\n\t\t\tfor ( const value of range.getWalker() ) {\n\t\t\t\tconst block = value.item;\n\n\t\t\t\tif ( value.type == 'elementEnd' && isUnvisitedTopBlock( block, visited, range ) ) {\n\t\t\t\t\tyield block;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst endBlock = getParentBlock( range.end, visited );\n\n\t\t\t// #984. Don't return the end block if the range ends right at its beginning.\n\t\t\tif ( endBlock && !range.end.isTouching( Position._createAt( endBlock, 0 ) ) && isTopBlockInRange( endBlock, range ) ) {\n\t\t\t\tyield endBlock;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether the selection contains the entire content of the given element. This means that selection must start\n\t * at a position {@link module:engine/model/position~Position#isTouching touching} the element's start and ends at position\n\t * touching the element's end.\n\t *\n\t * By default, this method will check whether the entire content of the selection's current root is selected.\n\t * Useful to check if e.g. the user has just pressed <kbd>Ctrl</kbd> + <kbd>A</kbd>.\n\t *\n\t * @param {module:engine/model/element~Element} [element=this.anchor.root]\n\t * @returns {Boolean}\n\t */\n\tcontainsEntireContent( element = this.anchor.root ) {\n\t\tconst limitStartPosition = Position._createAt( element, 0 );\n\t\tconst limitEndPosition = Position._createAt( element, 'end' );\n\n\t\treturn limitStartPosition.isTouching( this.getFirstPosition() ) &&\n\t\t\tlimitEndPosition.isTouching( this.getLastPosition() );\n\t}\n\n\t/**\n\t * Adds given range to internal {@link #_ranges ranges array}. Throws an error\n\t * if given range is intersecting with any range that is already stored in this selection.\n\t *\n\t * @protected\n\t * @param {module:engine/model/range~Range} range Range to add.\n\t */\n\t_pushRange( range ) {\n\t\tthis._checkRange( range );\n\t\tthis._ranges.push( new Range( range.start, range.end ) );\n\t}\n\n\t/**\n\t * Checks if given range intersects with ranges that are already in the selection. Throws an error if it does.\n\t *\n\t * @protected\n\t * @param {module:engine/model/range~Range} range Range to check.\n\t */\n\t_checkRange( range ) {\n\t\tfor ( let i = 0; i < this._ranges.length; i++ ) {\n\t\t\tif ( range.isIntersecting( this._ranges[ i ] ) ) {\n\t\t\t\t/**\n\t\t\t\t * Trying to add a range that intersects with another range in the selection.\n\t\t\t\t *\n\t\t\t\t * @error model-selection-range-intersects\n\t\t\t\t * @param {module:engine/model/range~Range} addedRange Range that was added to the selection.\n\t\t\t\t * @param {module:engine/model/range~Range} intersectingRange Range in the selection that intersects with `addedRange`.\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-selection-range-intersects: Trying to add a range that intersects with another range in the selection.',\n\t\t\t\t\t[ this, range ],\n\t\t\t\t\t{ addedRange: range, intersectingRange: this._ranges[ i ] }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Deletes ranges from internal range array. Uses {@link #_popRange _popRange} to\n\t * ensure proper ranges removal.\n\t *\n\t * @protected\n\t */\n\t_removeAllRanges() {\n\t\twhile ( this._ranges.length > 0 ) {\n\t\t\tthis._popRange();\n\t\t}\n\t}\n\n\t/**\n\t * Removes most recently added range from the selection.\n\t *\n\t * @protected\n\t */\n\t_popRange() {\n\t\tthis._ranges.pop();\n\t}\n\n\t/**\n\t * Fired when selection range(s) changed.\n\t *\n\t * @event change:range\n\t * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n\t * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n\t * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its position\n\t * was directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n\t * changed because the structure of the model has been changed (which means an indirect change).\n\t * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n\t * which mean that they are not updated once the document changes.\n\t */\n\n\t/**\n\t * Fired when selection attribute changed.\n\t *\n\t * @event change:attribute\n\t * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n\t * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n\t * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its attributes\n\t * were directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n\t * changed in the model and its attributes were refreshed (which means an indirect change).\n\t * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n\t * which mean that they are not updated once the document changes.\n\t * @param {Array.<String>} attributeKeys Array containing keys of attributes that changed.\n\t */\n}\n\nmix( Selection, EmitterMixin );\n\n// Checks whether the given element extends $block in the schema and has a parent (is not a root).\n// Marks it as already visited.\nfunction isUnvisitedBlock( element, visited ) {\n\tif ( visited.has( element ) ) {\n\t\treturn false;\n\t}\n\n\tvisited.add( element );\n\n\treturn element.document.model.schema.isBlock( element ) && element.parent;\n}\n\n// Checks if the given element is a $block was not previously visited and is a top block in a range.\nfunction isUnvisitedTopBlock( element, visited, range ) {\n\treturn isUnvisitedBlock( element, visited ) && isTopBlockInRange( element, range );\n}\n\n// Finds the lowest element in position's ancestors which is a block.\n// It will search until first ancestor that is a limit element.\n// Marks all ancestors as already visited to not include any of them later on.\nfunction getParentBlock( position, visited ) {\n\tconst schema = position.parent.document.model.schema;\n\n\tconst ancestors = position.parent.getAncestors( { parentFirst: true, includeSelf: true } );\n\n\tlet hasParentLimit = false;\n\n\tconst block = ancestors.find( element => {\n\t\t// Stop searching after first parent node that is limit element.\n\t\tif ( hasParentLimit ) {\n\t\t\treturn false;\n\t\t}\n\n\t\thasParentLimit = schema.isLimit( element );\n\n\t\treturn !hasParentLimit && isUnvisitedBlock( element, visited );\n\t} );\n\n\t// Mark all ancestors of this position's parent, because find() might've stopped early and\n\t// the found block may be a child of another block.\n\tancestors.forEach( element => visited.add( element ) );\n\n\treturn block;\n}\n\n// Checks if the blocks is not nested in other block inside a range.\n//\n// @param {module:engine/model/elmenent~Element} block Block to check.\n// @param {module:engine/model/range~Range} range Range to check.\nfunction isTopBlockInRange( block, range ) {\n\tconst parentBlock = findAncestorBlock( block );\n\n\tif ( !parentBlock ) {\n\t\treturn true;\n\t}\n\n\t// Add loose flag to check as parentRange can be equal to range.\n\tconst isParentInRange = range.containsRange( Range._createOn( parentBlock ), true );\n\n\treturn !isParentInRange;\n}\n\n// Returns first ancestor block of a node.\n//\n// @param {module:engine/model/node~Node} node\n// @returns {module:engine/model/node~Node|undefined}\nfunction findAncestorBlock( node ) {\n\tconst schema = node.document.model.schema;\n\n\tlet parent = node.parent;\n\n\twhile ( parent ) {\n\t\tif ( schema.isBlock( parent ) ) {\n\t\t\treturn parent;\n\t\t}\n\n\t\tparent = parent.parent;\n\t}\n}\n\n/**\n * An entity that is used to set selection.\n *\n * See also {@link module:engine/model/selection~Selection#setTo}\n *\n * @typedef {\n * module:engine/model/selection~Selection|\n * module:engine/model/documentselection~DocumentSelection|\n * module:engine/model/position~Position|\n * module:engine/model/range~Range|\n * module:engine/model/node~Node|\n * Iterable.<module:engine/model/range~Range>|\n * null\n * } module:engine/model/selection~Selectable\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/liverange\n */\n\nimport Range from './range';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * `LiveRange` is a type of {@link module:engine/model/range~Range Range}\n * that updates itself as {@link module:engine/model/document~Document document}\n * is changed through operations. It may be used as a bookmark.\n *\n * **Note:** Be very careful when dealing with `LiveRange`. Each `LiveRange` instance bind events that might\n * have to be unbound. Use {@link module:engine/model/liverange~LiveRange#detach detach} whenever you don't need `LiveRange` anymore.\n */\nexport default class LiveRange extends Range {\n\t/**\n\t * Creates a live range.\n\t *\n\t * @see module:engine/model/range~Range\n\t */\n\tconstructor( start, end ) {\n\t\tsuper( start, end );\n\n\t\tbindWithDocument.call( this );\n\t}\n\n\t/**\n\t * Unbinds all events previously bound by `LiveRange`. Use it whenever you don't need `LiveRange` instance\n\t * anymore (i.e. when leaving scope in which it was declared or before re-assigning variable that was\n\t * referring to it).\n\t */\n\tdetach() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tliveRange.is( 'range' ); // -> true\n\t *\t\tliveRange.is( 'model:range' ); // -> true\n\t *\t\tliveRange.is( 'liveRange' ); // -> true\n\t *\t\tliveRange.is( 'model:liveRange' ); // -> true\n\t *\n\t *\t\tliveRange.is( 'view:range' ); // -> false\n\t *\t\tliveRange.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'liveRange' || type == 'model:liveRange' || super.is( type );\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/range~Range range instance} that is equal to this live range.\n\t *\n\t * @returns {module:engine/model/range~Range}\n\t */\n\ttoRange() {\n\t\treturn new Range( this.start, this.end );\n\t}\n\n\t/**\n\t * Creates a `LiveRange` instance that is equal to the given range.\n\t *\n\t * @param {module:engine/model/range~Range} range\n\t * @returns {module:engine/model/liverange~LiveRange}\n\t */\n\tstatic fromRange( range ) {\n\t\treturn new LiveRange( range.start, range.end );\n\t}\n\n\t/**\n\t * @see module:engine/model/range~Range._createIn\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liverange~LiveRange._createIn\n\t * @param {module:engine/model/element~Element} element\n\t * @returns {module:engine/model/liverange~LiveRange}\n\t */\n\n\t/**\n\t * @see module:engine/model/range~Range._createOn\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liverange~LiveRange._createOn\n\t * @param {module:engine/model/element~Element} element\n\t * @returns {module:engine/model/liverange~LiveRange}\n\t */\n\n\t/**\n\t * @see module:engine/model/range~Range._createFromPositionAndShift\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liverange~LiveRange._createFromPositionAndShift\n\t * @param {module:engine/model/position~Position} position\n\t * @param {Number} shift\n\t * @returns {module:engine/model/liverange~LiveRange}\n\t */\n\n\t/**\n\t * Fired when `LiveRange` instance boundaries have changed due to changes in the\n\t * {@link module:engine/model/document~Document document}.\n\t *\n\t * @event change:range\n\t * @param {module:engine/model/range~Range} oldRange Range with start and end position equal to start and end position of this live\n\t * range before it got changed.\n\t * @param {Object} data Object with additional information about the change.\n\t * @param {module:engine/model/position~Position|null} data.deletionPosition Source position for remove and merge changes.\n\t * Available if the range was moved to the graveyard root, `null` otherwise.\n\t */\n\n\t/**\n\t * Fired when `LiveRange` instance boundaries have not changed after a change in {@link module:engine/model/document~Document document}\n\t * but the change took place inside the range, effectively changing its content.\n\t *\n\t * @event change:content\n\t * @param {module:engine/model/range~Range} range Range with start and end position equal to start and end position of\n\t * change range.\n\t * @param {Object} data Object with additional information about the change.\n\t * @param {null} data.deletionPosition Due to the nature of this event, this property is always set to `null`. It is passed\n\t * for compatibility with the {@link module:engine/model/liverange~LiveRange#event:change:range} event.\n\t */\n}\n\n// Binds this `LiveRange` to the {@link module:engine/model/document~Document document}\n// that owns this range's {@link module:engine/model/range~Range#root root}.\n//\n// @private\nfunction bindWithDocument() {\n\tthis.listenTo(\n\t\tthis.root.document.model,\n\t\t'applyOperation',\n\t\t( event, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( !operation.isDocumentOperation ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttransform.call( this, operation );\n\t\t},\n\t\t{ priority: 'low' }\n\t);\n}\n\n// Updates this range accordingly to the updates applied to the model. Bases on change events.\n//\n// @private\n// @param {module:engine/model/operation/operation~Operation} operation Executed operation.\nfunction transform( operation ) {\n\t// Transform the range by the operation. Join the result ranges if needed.\n\tconst ranges = this.getTransformedByOperation( operation );\n\tconst result = Range._createFromRanges( ranges );\n\n\tconst boundariesChanged = !result.isEqual( this );\n\tconst contentChanged = doesOperationChangeRangeContent( this, operation );\n\n\tlet deletionPosition = null;\n\n\tif ( boundariesChanged ) {\n\t\t// If range boundaries have changed, fire `change:range` event.\n\t\t//\n\t\tif ( result.root.rootName == '$graveyard' ) {\n\t\t\t// If the range was moved to the graveyard root, set `deletionPosition`.\n\t\t\tif ( operation.type == 'remove' ) {\n\t\t\t\tdeletionPosition = operation.sourcePosition;\n\t\t\t} else {\n\t\t\t\t// Merge operation.\n\t\t\t\tdeletionPosition = operation.deletionPosition;\n\t\t\t}\n\t\t}\n\n\t\tconst oldRange = this.toRange();\n\n\t\tthis.start = result.start;\n\t\tthis.end = result.end;\n\n\t\tthis.fire( 'change:range', oldRange, { deletionPosition } );\n\t} else if ( contentChanged ) {\n\t\t// If range boundaries have not changed, but there was change inside the range, fire `change:content` event.\n\t\tthis.fire( 'change:content', this.toRange(), { deletionPosition } );\n\t}\n}\n\n// Checks whether given operation changes something inside the range (even if it does not change boundaries).\n//\n// @private\n// @param {module:engine/model/range~Range} range Range to check.\n// @param {module:engine/model/operation/operation~Operation} operation Executed operation.\n// @returns {Boolean}\nfunction doesOperationChangeRangeContent( range, operation ) {\n\tswitch ( operation.type ) {\n\t\tcase 'insert':\n\t\t\treturn range.containsPosition( operation.position );\n\t\tcase 'move':\n\t\tcase 'remove':\n\t\tcase 'reinsert':\n\t\tcase 'merge':\n\t\t\treturn range.containsPosition( operation.sourcePosition ) ||\n\t\t\t\trange.start.isEqual( operation.sourcePosition ) ||\n\t\t\t\trange.containsPosition( operation.targetPosition );\n\t\tcase 'split':\n\t\t\treturn range.containsPosition( operation.splitPosition ) || range.containsPosition( operation.insertionPosition );\n\t}\n\n\treturn false;\n}\n\nmix( LiveRange, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/documentselection\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\n\nimport Selection from './selection';\nimport LiveRange from './liverange';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\n\nconst storePrefix = 'selection:';\n\n/**\n * `DocumentSelection` is a special selection which is used as the\n * {@link module:engine/model/document~Document#selection document's selection}.\n * There can be only one instance of `DocumentSelection` per document.\n *\n * Document selection can only be changed by using the {@link module:engine/model/writer~Writer} instance\n * inside the {@link module:engine/model/model~Model#change `change()`} block, as it provides a secure way to modify model.\n *\n * `DocumentSelection` is automatically updated upon changes in the {@link module:engine/model/document~Document document}\n * to always contain valid ranges. Its attributes are inherited from the text unless set explicitly.\n *\n * Differences between {@link module:engine/model/selection~Selection} and `DocumentSelection` are:\n * * there is always a range in `DocumentSelection` - even if no ranges were added there is a \"default range\"\n * present in the selection,\n * * ranges added to this selection updates automatically when the document changes,\n * * attributes of `DocumentSelection` are updated automatically according to selection ranges.\n *\n * Since `DocumentSelection` uses {@link module:engine/model/liverange~LiveRange live ranges}\n * and is updated when {@link module:engine/model/document~Document document}\n * changes, it cannot be set on {@link module:engine/model/node~Node nodes}\n * that are inside {@link module:engine/model/documentfragment~DocumentFragment document fragment}.\n * If you need to represent a selection in document fragment,\n * use {@link module:engine/model/selection~Selection Selection class} instead.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class DocumentSelection {\n\t/**\n\t * Creates an empty live selection for given {@link module:engine/model/document~Document}.\n\t *\n\t * @param {module:engine/model/document~Document} doc Document which owns this selection.\n\t */\n\tconstructor( doc ) {\n\t\t/**\n\t\t * Selection used internally by that class (`DocumentSelection` is a proxy to that selection).\n\t\t *\n\t\t * @protected\n\t\t */\n\t\tthis._selection = new LiveSelection( doc );\n\n\t\tthis._selection.delegate( 'change:range' ).to( this );\n\t\tthis._selection.delegate( 'change:attribute' ).to( this );\n\t\tthis._selection.delegate( 'change:marker' ).to( this );\n\t}\n\n\t/**\n\t * Returns whether the selection is collapsed. Selection is collapsed when there is exactly one range which is\n\t * collapsed.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this._selection.isCollapsed;\n\t}\n\n\t/**\n\t * Selection anchor. Anchor may be described as a position where the most recent part of the selection starts.\n\t * Together with {@link #focus} they define the direction of selection, which is important\n\t * when expanding/shrinking selection. Anchor is always {@link module:engine/model/range~Range#start start} or\n\t * {@link module:engine/model/range~Range#end end} position of the most recently added range.\n\t *\n\t * Is set to `null` if there are no ranges in selection.\n\t *\n\t * @see #focus\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget anchor() {\n\t\treturn this._selection.anchor;\n\t}\n\n\t/**\n\t * Selection focus. Focus is a position where the selection ends.\n\t *\n\t * Is set to `null` if there are no ranges in selection.\n\t *\n\t * @see #anchor\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget focus() {\n\t\treturn this._selection.focus;\n\t}\n\n\t/**\n\t * Returns number of ranges in selection.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._selection.rangeCount;\n\t}\n\n\t/**\n\t * Describes whether `Documentselection` has own range(s) set, or if it is defaulted to\n\t * {@link module:engine/model/document~Document#_getDefaultRange document's default range}.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget hasOwnRange() {\n\t\treturn this._selection.hasOwnRange;\n\t}\n\n\t/**\n\t * Specifies whether the {@link #focus}\n\t * precedes {@link #anchor}.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn this._selection.isBackward;\n\t}\n\n\t/**\n\t * Describes whether the gravity is overridden (using {@link module:engine/model/writer~Writer#overrideSelectionGravity}) or not.\n\t *\n\t * Note that the gravity remains overridden as long as will not be restored the same number of times as it was overridden.\n\t *\n\t * @readonly\n\t * @returns {Boolean}\n\t */\n\tget isGravityOverridden() {\n\t\treturn this._selection.isGravityOverridden;\n\t}\n\n\t/**\n\t * A collection of selection markers.\n\t * Marker is a selection marker when selection range is inside the marker range.\n\t *\n\t * @readonly\n\t * @type {module:utils/collection~Collection.<module:engine/model/markercollection~Marker>}\n\t */\n\tget markers() {\n\t\treturn this._selection.markers;\n\t}\n\n\t/**\n\t * Used for the compatibility with the {@link module:engine/model/selection~Selection#isEqual} method.\n\t *\n\t * @protected\n\t */\n\tget _ranges() {\n\t\treturn this._selection._ranges;\n\t}\n\n\t/**\n\t * Returns an iterable that iterates over copies of selection ranges.\n\t *\n\t * @returns {Iterable.<module:engine/model/range~Range>}\n\t */\n\tgetRanges() {\n\t\treturn this._selection.getRanges();\n\t}\n\n\t/**\n\t * Returns the first position in the selection.\n\t * First position is the position that {@link module:engine/model/position~Position#isBefore is before}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\treturn this._selection.getFirstPosition();\n\t}\n\n\t/**\n\t * Returns the last position in the selection.\n\t * Last position is the position that {@link module:engine/model/position~Position#isAfter is after}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\treturn this._selection.getLastPosition();\n\t}\n\n\t/**\n\t * Returns a copy of the first range in the selection.\n\t * First range is the one which {@link module:engine/model/range~Range#start start} position\n\t * {@link module:engine/model/position~Position#isBefore is before} start position of all other ranges\n\t * (not to confuse with the first range added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\treturn this._selection.getFirstRange();\n\t}\n\n\t/**\n\t * Returns a copy of the last range in the selection.\n\t * Last range is the one which {@link module:engine/model/range~Range#end end} position\n\t * {@link module:engine/model/position~Position#isAfter is after} end position of all other ranges (not to confuse with the range most\n\t * recently added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\treturn this._selection.getLastRange();\n\t}\n\n\t/**\n\t * Gets elements of type {@link module:engine/model/schema~Schema#isBlock \"block\"} touched by the selection.\n\t *\n\t * This method's result can be used for example to apply block styling to all blocks covered by this selection.\n\t *\n\t * **Note:** `getSelectedBlocks()` returns blocks that are nested in other non-block elements\n\t * but will not return blocks nested in other blocks.\n\t *\n\t * In this case the function will return exactly all 3 paragraphs (note: `<blockQuote>` is not a block itself):\n\t *\n\t *\t\t<paragraph>[a</paragraph>\n\t *\t\t<blockQuote>\n\t *\t\t\t<paragraph>b</paragraph>\n\t *\t\t</blockQuote>\n\t *\t\t<paragraph>c]d</paragraph>\n\t *\n\t * In this case the paragraph will also be returned, despite the collapsed selection:\n\t *\n\t *\t\t<paragraph>[]a</paragraph>\n\t *\n\t * In such a scenario, however, only blocks A, B & E will be returned as blocks C & D are nested in block B:\n\t *\n\t *\t\t[<blockA></blockA>\n\t *\t\t<blockB>\n\t *\t\t\t<blockC></blockC>\n\t *\t\t\t<blockD></blockD>\n\t *\t\t</blockB>\n\t *\t\t<blockE></blockE>]\n\t *\n\t * If the selection is inside a block all the inner blocks (A & B) are returned:\n\t *\n\t * \t\t<block>\n\t *\t\t\t<blockA>[a</blockA>\n\t * \t\t\t<blockB>b]</blockB>\n\t * \t\t</block>\n\t *\n\t * **Special case**: If a selection ends at the beginning of a block, that block is not returned as from user perspective\n\t * this block wasn't selected. See [#984](https://github.com/ckeditor/ckeditor5-engine/issues/984) for more details.\n\t *\n\t *\t\t<paragraph>[a</paragraph>\n\t *\t\t<paragraph>b</paragraph>\n\t *\t\t<paragraph>]c</paragraph> // this block will not be returned\n\t *\n\t * @returns {Iterable.<module:engine/model/element~Element>}\n\t */\n\tgetSelectedBlocks() {\n\t\treturn this._selection.getSelectedBlocks();\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/model/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\treturn this._selection.getSelectedElement();\n\t}\n\n\t/**\n\t * Checks whether the selection contains the entire content of the given element. This means that selection must start\n\t * at a position {@link module:engine/model/position~Position#isTouching touching} the element's start and ends at position\n\t * touching the element's end.\n\t *\n\t * By default, this method will check whether the entire content of the selection's current root is selected.\n\t * Useful to check if e.g. the user has just pressed <kbd>Ctrl</kbd> + <kbd>A</kbd>.\n\t *\n\t * @param {module:engine/model/element~Element} [element=this.anchor.root]\n\t * @returns {Boolean}\n\t */\n\tcontainsEntireContent( element ) {\n\t\treturn this._selection.containsEntireContent( element );\n\t}\n\n\t/**\n\t * Unbinds all events previously bound by document selection.\n\t */\n\tdestroy() {\n\t\tthis._selection.destroy();\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attribute keys.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this._selection.getAttributeKeys();\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this._selection.getAttributes();\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on the selection.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this._selection.getAttribute( key );\n\t}\n\n\t/**\n\t * Checks if the selection has an attribute for given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on selection, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this._selection.hasAttribute( key );\n\t}\n\n\t/**\n\t * Refreshes selection attributes and markers according to the current position in the model.\n\t */\n\trefresh() {\n\t\tthis._selection._updateMarkers();\n\t\tthis._selection._updateAttributes( false );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tselection.is( 'selection' ); // -> true\n\t *\t\tselection.is( 'documentSelection' ); // -> true\n\t *\t\tselection.is( 'model:selection' ); // -> true\n\t *\t\tselection.is( 'model:documentSelection' ); // -> true\n\t *\n\t *\t\tselection.is( 'view:selection' ); // -> false\n\t *\t\tselection.is( 'element' ); // -> false\n\t *\t\tselection.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'selection' ||\n\t\t\ttype == 'model:selection' ||\n\t\t\ttype == 'documentSelection' ||\n\t\t\ttype == 'model:documentSelection';\n\t}\n\n\t/**\n\t * Moves {@link module:engine/model/documentselection~DocumentSelection#focus} to the specified location.\n\t * Should be used only within the {@link module:engine/model/writer~Writer#setSelectionFocus} method.\n\t *\n\t * The location can be specified in the same form as\n\t * {@link module:engine/model/writer~Writer#createPositionAt writer.createPositionAt()} parameters.\n\t *\n\t * @see module:engine/model/writer~Writer#setSelectionFocus\n\t * @protected\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\t_setFocus( itemOrPosition, offset ) {\n\t\tthis._selection.setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/model/selection~Selectable selectable}.\n\t * Should be used only within the {@link module:engine/model/writer~Writer#setSelection} method.\n\t *\n\t * @see module:engine/model/writer~Writer#setSelection\n\t * @protected\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t */\n\t_setTo( selectable, placeOrOffset, options ) {\n\t\tthis._selection.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Sets attribute on the selection. If attribute with the same key already is set, it's value is overwritten.\n\t * Should be used only within the {@link module:engine/model/writer~Writer#setSelectionAttribute} method.\n\t *\n\t * @see module:engine/model/writer~Writer#setSelectionAttribute\n\t * @protected\n\t * @param {String} key Key of the attribute to set.\n\t * @param {*} value Attribute value.\n\t */\n\t_setAttribute( key, value ) {\n\t\tthis._selection.setAttribute( key, value );\n\t}\n\n\t/**\n\t * Removes an attribute with given key from the selection.\n\t * If the given attribute was set on the selection, fires the {@link module:engine/model/selection~Selection#event:change:range}\n\t * event with removed attribute key.\n\t * Should be used only within the {@link module:engine/model/writer~Writer#removeSelectionAttribute} method.\n\t *\n\t * @see module:engine/model/writer~Writer#removeSelectionAttribute\n\t * @protected\n\t * @param {String} key Key of the attribute to remove.\n\t */\n\t_removeAttribute( key ) {\n\t\tthis._selection.removeAttribute( key );\n\t}\n\n\t/**\n\t * Returns an iterable that iterates through all selection attributes stored in current selection's parent.\n\t *\n\t * @protected\n\t * @returns {Iterable.<*>}\n\t */\n\t_getStoredAttributes() {\n\t\treturn this._selection._getStoredAttributes();\n\t}\n\n\t/**\n\t * Temporarily changes the gravity of the selection from the left to the right.\n\t *\n\t * The gravity defines from which direction the selection inherits its attributes. If it's the default left\n\t * gravity, the selection (after being moved by the the user) inherits attributes from its left hand side.\n\t * This method allows to temporarily override this behavior by forcing the gravity to the right.\n\t *\n\t * It returns an unique identifier which is required to restore the gravity. It guarantees the symmetry\n\t * of the process.\n\t *\n\t * @see module:engine/model/writer~Writer#overrideSelectionGravity\n\t * @protected\n\t * @returns {String} The unique id which allows restoring the gravity.\n\t */\n\t_overrideGravity() {\n\t\treturn this._selection.overrideGravity();\n\t}\n\n\t/**\n\t * Restores the {@link ~DocumentSelection#_overrideGravity overridden gravity}.\n\t *\n\t * Restoring the gravity is only possible using the unique identifier returned by\n\t * {@link ~DocumentSelection#_overrideGravity}. Note that the gravity remains overridden as long as won't be restored\n\t * the same number of times it was overridden.\n\t *\n\t * @see module:engine/model/writer~Writer#restoreSelectionGravity\n\t * @protected\n\t * @param {String} uid The unique id returned by {@link #_overrideGravity}.\n\t */\n\t_restoreGravity( uid ) {\n\t\tthis._selection.restoreGravity( uid );\n\t}\n\n\t/**\n\t * Generates and returns an attribute key for selection attributes store, basing on original attribute key.\n\t *\n\t * @protected\n\t * @param {String} key Attribute key to convert.\n\t * @returns {String} Converted attribute key, applicable for selection store.\n\t */\n\tstatic _getStoreAttributeKey( key ) {\n\t\treturn storePrefix + key;\n\t}\n\n\t/**\n\t * Checks whether the given attribute key is an attribute stored on an element.\n\t *\n\t * @protected\n\t * @param {String} key\n\t * @returns {Boolean}\n\t */\n\tstatic _isStoreAttributeKey( key ) {\n\t\treturn key.startsWith( storePrefix );\n\t}\n}\n\nmix( DocumentSelection, EmitterMixin );\n\n/**\n * Fired when selection range(s) changed.\n *\n * @event change:range\n * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its position\n * was directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n * changed because the structure of the model has been changed (which means an indirect change).\n * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n * which mean that they are not updated once the document changes.\n */\n\n/**\n * Fired when selection attribute changed.\n *\n * @event change:attribute\n * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its attributes\n * were directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n * changed in the model and its attributes were refreshed (which means an indirect change).\n * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n * which mean that they are not updated once the document changes.\n * @param {Array.<String>} attributeKeys Array containing keys of attributes that changed.\n */\n\n/**\n * Fired when selection marker(s) changed.\n *\n * @event change:marker\n * @param {Boolean} directChange This is always set to `false` in case of `change:marker` event as there is no possibility\n * to change markers directly through {@link module:engine/model/documentselection~DocumentSelection} API.\n * See also {@link module:engine/model/documentselection~DocumentSelection#event:change:range} and\n * {@link module:engine/model/documentselection~DocumentSelection#event:change:attribute}.\n * @param {Array.<module:engine/model/markercollection~Marker>} oldMarkers Markers in which the selection was before the change.\n */\n\n// `LiveSelection` is used internally by {@link module:engine/model/documentselection~DocumentSelection} and shouldn't be used directly.\n//\n// LiveSelection` is automatically updated upon changes in the {@link module:engine/model/document~Document document}\n// to always contain valid ranges. Its attributes are inherited from the text unless set explicitly.\n//\n// Differences between {@link module:engine/model/selection~Selection} and `LiveSelection` are:\n// * there is always a range in `LiveSelection` - even if no ranges were added there is a \"default range\"\n// present in the selection,\n// * ranges added to this selection updates automatically when the document changes,\n// * attributes of `LiveSelection` are updated automatically according to selection ranges.\n//\n// @extends module:engine/model/selection~Selection\n//\n\nclass LiveSelection extends Selection {\n\t// Creates an empty live selection for given {@link module:engine/model/document~Document}.\n\t// @param {module:engine/model/document~Document} doc Document which owns this selection.\n\tconstructor( doc ) {\n\t\tsuper();\n\n\t\t// List of selection markers.\n\t\t// Marker is a selection marker when selection range is inside the marker range.\n\t\t//\n\t\t// @type {module:utils/collection~Collection}\n\t\tthis.markers = new Collection( { idProperty: 'name' } );\n\n\t\t// Document which owns this selection.\n\t\t//\n\t\t// @protected\n\t\t// @member {module:engine/model/model~Model}\n\t\tthis._model = doc.model;\n\n\t\t// Document which owns this selection.\n\t\t//\n\t\t// @protected\n\t\t// @member {module:engine/model/document~Document}\n\t\tthis._document = doc;\n\n\t\t// Keeps mapping of attribute name to priority with which the attribute got modified (added/changed/removed)\n\t\t// last time. Possible values of priority are: `'low'` and `'normal'`.\n\t\t//\n\t\t// Priorities are used by internal `LiveSelection` mechanisms. All attributes set using `LiveSelection`\n\t\t// attributes API are set with `'normal'` priority.\n\t\t//\n\t\t// @private\n\t\t// @member {Map} module:engine/model/liveselection~LiveSelection#_attributePriority\n\t\tthis._attributePriority = new Map();\n\n\t\t// Contains data required to fix ranges which have been moved to the graveyard.\n\t\t// @private\n\t\t// @member {Array} module:engine/model/liveselection~LiveSelection#_fixGraveyardRangesData\n\t\tthis._fixGraveyardRangesData = [];\n\n\t\t// Flag that informs whether the selection ranges have changed. It is changed on true when `LiveRange#change:range` event is fired.\n\t\t// @private\n\t\t// @member {Array} module:engine/model/liveselection~LiveSelection#_hasChangedRange\n\t\tthis._hasChangedRange = false;\n\n\t\t// Each overriding gravity adds an UID to the set and each removal removes it.\n\t\t// Gravity is overridden when there's at least one UID in the set.\n\t\t// Gravity is restored when the set is empty.\n\t\t// This is to prevent conflicts when gravity is overridden by more than one feature at the same time.\n\t\t// @private\n\t\t// @type {Set}\n\t\tthis._overriddenGravityRegister = new Set();\n\n\t\t// Ensure selection is correct after each operation.\n\t\tthis.listenTo( this._model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( !operation.isDocumentOperation || operation.type == 'marker' || operation.type == 'rename' || operation.type == 'noop' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twhile ( this._fixGraveyardRangesData.length ) {\n\t\t\t\tconst { liveRange, sourcePosition } = this._fixGraveyardRangesData.shift();\n\n\t\t\t\tthis._fixGraveyardSelection( liveRange, sourcePosition );\n\t\t\t}\n\n\t\t\tif ( this._hasChangedRange ) {\n\t\t\t\tthis._hasChangedRange = false;\n\t\t\t\tthis.fire( 'change:range', { directChange: false } );\n\t\t\t}\n\t\t}, { priority: 'lowest' } );\n\n\t\t// Ensure selection is correct and up to date after each range change.\n\t\tthis.on( 'change:range', () => {\n\t\t\tfor ( const range of this.getRanges() ) {\n\t\t\t\tif ( !this._document._validateSelectionRange( range ) ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Range from {@link module:engine/model/documentselection~DocumentSelection document selection}\n\t\t\t\t\t * starts or ends at incorrect position.\n\t\t\t\t\t *\n\t\t\t\t\t * @error document-selection-wrong-position\n\t\t\t\t\t * @param {module:engine/model/range~Range} range\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t'document-selection-wrong-position: Range from document selection starts or ends at incorrect position.',\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\t{ range }\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Update markers data stored by the selection after each marker change.\n\t\tthis.listenTo( this._model.markers, 'update', () => this._updateMarkers() );\n\n\t\t// Ensure selection is up to date after each change block.\n\t\tthis.listenTo( this._document, 'change', ( evt, batch ) => {\n\t\t\tclearAttributesStoredInElement( this._model, batch );\n\t\t} );\n\t}\n\n\tget isCollapsed() {\n\t\tconst length = this._ranges.length;\n\n\t\treturn length === 0 ? this._document._getDefaultRange().isCollapsed : super.isCollapsed;\n\t}\n\n\tget anchor() {\n\t\treturn super.anchor || this._document._getDefaultRange().start;\n\t}\n\n\tget focus() {\n\t\treturn super.focus || this._document._getDefaultRange().end;\n\t}\n\n\tget rangeCount() {\n\t\treturn this._ranges.length ? this._ranges.length : 1;\n\t}\n\n\t// Describes whether `LiveSelection` has own range(s) set, or if it is defaulted to\n\t// {@link module:engine/model/document~Document#_getDefaultRange document's default range}.\n\t//\n\t// @readonly\n\t// @type {Boolean}\n\tget hasOwnRange() {\n\t\treturn this._ranges.length > 0;\n\t}\n\n\t// When set to `true` then selection attributes on node before the caret won't be taken\n\t// into consideration while updating selection attributes.\n\t//\n\t// @protected\n\t// @type {Boolean}\n\tget isGravityOverridden() {\n\t\treturn !!this._overriddenGravityRegister.size;\n\t}\n\n\t// Unbinds all events previously bound by live selection.\n\tdestroy() {\n\t\tfor ( let i = 0; i < this._ranges.length; i++ ) {\n\t\t\tthis._ranges[ i ].detach();\n\t\t}\n\n\t\tthis.stopListening();\n\t}\n\n\t* getRanges() {\n\t\tif ( this._ranges.length ) {\n\t\t\tyield* super.getRanges();\n\t\t} else {\n\t\t\tyield this._document._getDefaultRange();\n\t\t}\n\t}\n\n\tgetFirstRange() {\n\t\treturn super.getFirstRange() || this._document._getDefaultRange();\n\t}\n\n\tgetLastRange() {\n\t\treturn super.getLastRange() || this._document._getDefaultRange();\n\t}\n\n\tsetTo( selectable, optionsOrPlaceOrOffset, options ) {\n\t\tsuper.setTo( selectable, optionsOrPlaceOrOffset, options );\n\t\tthis._updateAttributes( true );\n\t\tthis._updateMarkers();\n\t}\n\n\tsetFocus( itemOrPosition, offset ) {\n\t\tsuper.setFocus( itemOrPosition, offset );\n\t\tthis._updateAttributes( true );\n\t\tthis._updateMarkers();\n\t}\n\n\tsetAttribute( key, value ) {\n\t\tif ( this._setAttribute( key, value ) ) {\n\t\t\t// Fire event with exact data.\n\t\t\tconst attributeKeys = [ key ];\n\t\t\tthis.fire( 'change:attribute', { attributeKeys, directChange: true } );\n\t\t}\n\t}\n\n\tremoveAttribute( key ) {\n\t\tif ( this._removeAttribute( key ) ) {\n\t\t\t// Fire event with exact data.\n\t\t\tconst attributeKeys = [ key ];\n\t\t\tthis.fire( 'change:attribute', { attributeKeys, directChange: true } );\n\t\t}\n\t}\n\n\toverrideGravity() {\n\t\tconst overrideUid = uid();\n\n\t\t// Remember that another overriding has been requested. It will need to be removed\n\t\t// before the gravity is to be restored.\n\t\tthis._overriddenGravityRegister.add( overrideUid );\n\n\t\tif ( this._overriddenGravityRegister.size === 1 ) {\n\t\t\tthis._updateAttributes( true );\n\t\t}\n\n\t\treturn overrideUid;\n\t}\n\n\trestoreGravity( uid ) {\n\t\tif ( !this._overriddenGravityRegister.has( uid ) ) {\n\t\t\t/**\n\t\t\t * Restoring gravity for an unknown UID is not possible. Make sure you are using a correct\n\t\t\t * UID obtained from the {@link module:engine/model/writer~Writer#overrideSelectionGravity} to restore.\n\t\t\t *\n\t\t\t * @error document-selection-gravity-wrong-restore\n\t\t\t * @param {String} uid The unique identifier returned by\n\t\t\t * {@link module:engine/model/documentselection~DocumentSelection#_overrideGravity}.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'document-selection-gravity-wrong-restore: Attempting to restore the selection gravity for an unknown UID.',\n\t\t\t\tthis,\n\t\t\t\t{ uid }\n\t\t\t);\n\t\t}\n\n\t\tthis._overriddenGravityRegister.delete( uid );\n\n\t\t// Restore gravity only when all overriding have been restored.\n\t\tif ( !this.isGravityOverridden ) {\n\t\t\tthis._updateAttributes( true );\n\t\t}\n\t}\n\n\t_popRange() {\n\t\tthis._ranges.pop().detach();\n\t}\n\n\t_pushRange( range ) {\n\t\tconst liveRange = this._prepareRange( range );\n\n\t\t// `undefined` is returned when given `range` is in graveyard root.\n\t\tif ( liveRange ) {\n\t\t\tthis._ranges.push( liveRange );\n\t\t}\n\t}\n\n\t// Prepares given range to be added to selection. Checks if it is correct,\n\t// converts it to {@link module:engine/model/liverange~LiveRange LiveRange}\n\t// and sets listeners listening to the range's change event.\n\t//\n\t// @private\n\t// @param {module:engine/model/range~Range} range\n\t_prepareRange( range ) {\n\t\tthis._checkRange( range );\n\n\t\tif ( range.root == this._document.graveyard ) {\n\t\t\t// @if CK_DEBUG // console.warn( 'Trying to add a Range that is in the graveyard root. Range rejected.' );\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst liveRange = LiveRange.fromRange( range );\n\n\t\tliveRange.on( 'change:range', ( evt, oldRange, data ) => {\n\t\t\tthis._hasChangedRange = true;\n\n\t\t\t// If `LiveRange` is in whole moved to the graveyard, save necessary data. It will be fixed on `Model#applyOperation` event.\n\t\t\tif ( liveRange.root == this._document.graveyard ) {\n\t\t\t\tthis._fixGraveyardRangesData.push( {\n\t\t\t\t\tliveRange,\n\t\t\t\t\tsourcePosition: data.deletionPosition\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\treturn liveRange;\n\t}\n\n\t_updateMarkers() {\n\t\tconst markers = [];\n\t\tlet changed = false;\n\n\t\tfor ( const marker of this._model.markers ) {\n\t\t\tconst markerRange = marker.getRange();\n\n\t\t\tfor ( const selectionRange of this.getRanges() ) {\n\t\t\t\tif ( markerRange.containsRange( selectionRange, !selectionRange.isCollapsed ) ) {\n\t\t\t\t\tmarkers.push( marker );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst oldMarkers = Array.from( this.markers );\n\n\t\tfor ( const marker of markers ) {\n\t\t\tif ( !this.markers.has( marker ) ) {\n\t\t\t\tthis.markers.add( marker );\n\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tfor ( const marker of Array.from( this.markers ) ) {\n\t\t\tif ( !markers.includes( marker ) ) {\n\t\t\t\tthis.markers.remove( marker );\n\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tif ( changed ) {\n\t\t\tthis.fire( 'change:marker', { oldMarkers, directChange: false } );\n\t\t}\n\t}\n\n\t// Updates this selection attributes according to its ranges and the {@link module:engine/model/document~Document model document}.\n\t//\n\t// @protected\n\t// @param {Boolean} clearAll\n\t// @fires change:attribute\n\t_updateAttributes( clearAll ) {\n\t\tconst newAttributes = toMap( this._getSurroundingAttributes() );\n\t\tconst oldAttributes = toMap( this.getAttributes() );\n\n\t\tif ( clearAll ) {\n\t\t\t// If `clearAll` remove all attributes and reset priorities.\n\t\t\tthis._attributePriority = new Map();\n\t\t\tthis._attrs = new Map();\n\t\t} else {\n\t\t\t// If not, remove only attributes added with `low` priority.\n\t\t\tfor ( const [ key, priority ] of this._attributePriority ) {\n\t\t\t\tif ( priority == 'low' ) {\n\t\t\t\t\tthis._attrs.delete( key );\n\t\t\t\t\tthis._attributePriority.delete( key );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis._setAttributesTo( newAttributes );\n\n\t\t// Let's evaluate which attributes really changed.\n\t\tconst changed = [];\n\n\t\t// First, loop through all attributes that are set on selection right now.\n\t\t// Check which of them are different than old attributes.\n\t\tfor ( const [ newKey, newValue ] of this.getAttributes() ) {\n\t\t\tif ( !oldAttributes.has( newKey ) || oldAttributes.get( newKey ) !== newValue ) {\n\t\t\t\tchanged.push( newKey );\n\t\t\t}\n\t\t}\n\n\t\t// Then, check which of old attributes got removed.\n\t\tfor ( const [ oldKey ] of oldAttributes ) {\n\t\t\tif ( !this.hasAttribute( oldKey ) ) {\n\t\t\t\tchanged.push( oldKey );\n\t\t\t}\n\t\t}\n\n\t\t// Fire event with exact data (fire only if anything changed).\n\t\tif ( changed.length > 0 ) {\n\t\t\tthis.fire( 'change:attribute', { attributeKeys: changed, directChange: false } );\n\t\t}\n\t}\n\n\t// Internal method for setting `LiveSelection` attribute. Supports attribute priorities (through `directChange`\n\t// parameter).\n\t//\n\t// @private\n\t// @param {String} key Attribute key.\n\t// @param {*} value Attribute value.\n\t// @param {Boolean} [directChange=true] `true` if the change is caused by `Selection` API, `false` if change\n\t// is caused by `Batch` API.\n\t// @returns {Boolean} Whether value has changed.\n\t_setAttribute( key, value, directChange = true ) {\n\t\tconst priority = directChange ? 'normal' : 'low';\n\n\t\tif ( priority == 'low' && this._attributePriority.get( key ) == 'normal' ) {\n\t\t\t// Priority too low.\n\t\t\treturn false;\n\t\t}\n\n\t\tconst oldValue = super.getAttribute( key );\n\n\t\t// Don't do anything if value has not changed.\n\t\tif ( oldValue === value ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis._attrs.set( key, value );\n\n\t\t// Update priorities map.\n\t\tthis._attributePriority.set( key, priority );\n\n\t\treturn true;\n\t}\n\n\t// Internal method for removing `LiveSelection` attribute. Supports attribute priorities (through `directChange`\n\t// parameter).\n\t//\n\t// NOTE: Even if attribute is not present in the selection but is provided to this method, it's priority will\n\t// be changed according to `directChange` parameter.\n\t//\n\t// @private\n\t// @param {String} key Attribute key.\n\t// @param {Boolean} [directChange=true] `true` if the change is caused by `Selection` API, `false` if change\n\t// is caused by `Batch` API.\n\t// @returns {Boolean} Whether attribute was removed. May not be true if such attributes didn't exist or the\n\t// existing attribute had higher priority.\n\t_removeAttribute( key, directChange = true ) {\n\t\tconst priority = directChange ? 'normal' : 'low';\n\n\t\tif ( priority == 'low' && this._attributePriority.get( key ) == 'normal' ) {\n\t\t\t// Priority too low.\n\t\t\treturn false;\n\t\t}\n\n\t\t// Update priorities map.\n\t\tthis._attributePriority.set( key, priority );\n\n\t\t// Don't do anything if value has not changed.\n\t\tif ( !super.hasAttribute( key ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis._attrs.delete( key );\n\n\t\treturn true;\n\t}\n\n\t// Internal method for setting multiple `LiveSelection` attributes. Supports attribute priorities (through\n\t// `directChange` parameter).\n\t//\n\t// @private\n\t// @param {Map.<String,*>} attrs Iterable object containing attributes to be set.\n\t// @returns {Set.<String>} Changed attribute keys.\n\t_setAttributesTo( attrs ) {\n\t\tconst changed = new Set();\n\n\t\tfor ( const [ oldKey, oldValue ] of this.getAttributes() ) {\n\t\t\t// Do not remove attribute if attribute with same key and value is about to be set.\n\t\t\tif ( attrs.get( oldKey ) === oldValue ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// All rest attributes will be removed so changed attributes won't change .\n\t\t\tthis._removeAttribute( oldKey, false );\n\t\t}\n\n\t\tfor ( const [ key, value ] of attrs ) {\n\t\t\t// Attribute may not be set because of attributes or because same key/value is already added.\n\t\t\tconst gotAdded = this._setAttribute( key, value, false );\n\n\t\t\tif ( gotAdded ) {\n\t\t\t\tchanged.add( key );\n\t\t\t}\n\t\t}\n\n\t\treturn changed;\n\t}\n\n\t// Returns an iterable that iterates through all selection attributes stored in current selection's parent.\n\t//\n\t// @protected\n\t// @returns {Iterable.<*>}\n\t* _getStoredAttributes() {\n\t\tconst selectionParent = this.getFirstPosition().parent;\n\n\t\tif ( this.isCollapsed && selectionParent.isEmpty ) {\n\t\t\tfor ( const key of selectionParent.getAttributeKeys() ) {\n\t\t\t\tif ( key.startsWith( storePrefix ) ) {\n\t\t\t\t\tconst realKey = key.substr( storePrefix.length );\n\n\t\t\t\t\tyield [ realKey, selectionParent.getAttribute( key ) ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Checks model text nodes that are closest to the selection's first position and returns attributes of first\n\t// found element. If there are no text nodes in selection's first position parent, it returns selection\n\t// attributes stored in that parent.\n\t//\n\t// @private\n\t// @returns {Iterable.<*>} Collection of attributes.\n\t_getSurroundingAttributes() {\n\t\tconst position = this.getFirstPosition();\n\t\tconst schema = this._model.schema;\n\n\t\tlet attrs = null;\n\n\t\tif ( !this.isCollapsed ) {\n\t\t\t// 1. If selection is a range...\n\t\t\tconst range = this.getFirstRange();\n\n\t\t\t// ...look for a first character node in that range and take attributes from it.\n\t\t\tfor ( const value of range ) {\n\t\t\t\t// If the item is an object, we don't want to get attributes from its children.\n\t\t\t\tif ( value.item.is( 'element' ) && schema.isObject( value.item ) ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( value.type == 'text' ) {\n\t\t\t\t\tattrs = value.item.getAttributes();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// 2. If the selection is a caret or the range does not contain a character node...\n\n\t\t\tconst nodeBefore = position.textNode ? position.textNode : position.nodeBefore;\n\t\t\tconst nodeAfter = position.textNode ? position.textNode : position.nodeAfter;\n\n\t\t\t// When gravity is overridden then don't take node before into consideration.\n\t\t\tif ( !this.isGravityOverridden ) {\n\t\t\t\t// ...look at the node before caret and take attributes from it if it is a character node.\n\t\t\t\tattrs = getAttrsIfCharacter( nodeBefore );\n\t\t\t}\n\n\t\t\t// 3. If not, look at the node after caret...\n\t\t\tif ( !attrs ) {\n\t\t\t\tattrs = getAttrsIfCharacter( nodeAfter );\n\t\t\t}\n\n\t\t\t// 4. If not, try to find the first character on the left, that is in the same node.\n\t\t\t// When gravity is overridden then don't take node before into consideration.\n\t\t\tif ( !this.isGravityOverridden && !attrs ) {\n\t\t\t\tlet node = nodeBefore;\n\n\t\t\t\twhile ( node && !attrs ) {\n\t\t\t\t\tnode = node.previousSibling;\n\t\t\t\t\tattrs = getAttrsIfCharacter( node );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 5. If not found, try to find the first character on the right, that is in the same node.\n\t\t\tif ( !attrs ) {\n\t\t\t\tlet node = nodeAfter;\n\n\t\t\t\twhile ( node && !attrs ) {\n\t\t\t\t\tnode = node.nextSibling;\n\t\t\t\t\tattrs = getAttrsIfCharacter( node );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 6. If not found, selection should retrieve attributes from parent.\n\t\t\tif ( !attrs ) {\n\t\t\t\tattrs = this._getStoredAttributes();\n\t\t\t}\n\t\t}\n\n\t\treturn attrs;\n\t}\n\n\t// Fixes a selection range after it ends up in graveyard root.\n\t//\n\t// @private\n\t// @param {module:engine/model/liverange~LiveRange} liveRange The range from selection, that ended up in the graveyard root.\n\t// @param {module:engine/model/position~Position} removedRangeStart Start position of a range which was removed.\n\t_fixGraveyardSelection( liveRange, removedRangeStart ) {\n\t\t// The start of the removed range is the closest position to the `liveRange` - the original selection range.\n\t\t// This is a good candidate for a fixed selection range.\n\t\tconst positionCandidate = removedRangeStart.clone();\n\n\t\t// Find a range that is a correct selection range and is closest to the start of removed range.\n\t\tconst selectionRange = this._model.schema.getNearestSelectionRange( positionCandidate );\n\n\t\t// Remove the old selection range before preparing and adding new selection range. This order is important,\n\t\t// because new range, in some cases, may intersect with old range (it depends on `getNearestSelectionRange()` result).\n\t\tconst index = this._ranges.indexOf( liveRange );\n\t\tthis._ranges.splice( index, 1 );\n\t\tliveRange.detach();\n\n\t\t// If nearest valid selection range has been found - add it in the place of old range.\n\t\tif ( selectionRange ) {\n\t\t\t// Check the range, convert it to live range, bind events, etc.\n\t\t\tconst newRange = this._prepareRange( selectionRange );\n\n\t\t\t// Add new range in the place of old range.\n\t\t\tthis._ranges.splice( index, 0, newRange );\n\t\t}\n\t\t// If nearest valid selection range cannot be found - just removing the old range is fine.\n\t}\n}\n\n// Helper function for {@link module:engine/model/liveselection~LiveSelection#_updateAttributes}.\n//\n// It takes model item, checks whether it is a text node (or text proxy) and, if so, returns it's attributes. If not, returns `null`.\n//\n// @param {module:engine/model/item~Item|null} node\n// @returns {Boolean}\nfunction getAttrsIfCharacter( node ) {\n\tif ( node instanceof TextProxy || node instanceof Text ) {\n\t\treturn node.getAttributes();\n\t}\n\n\treturn null;\n}\n\n// Removes selection attributes from element which is not empty anymore.\n//\n// @private\n// @param {module:engine/model/model~Model} model\n// @param {module:engine/model/batch~Batch} batch\nfunction clearAttributesStoredInElement( model, batch ) {\n\tconst differ = model.document.differ;\n\n\tfor ( const entry of differ.getChanges() ) {\n\t\tif ( entry.type != 'insert' ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst changeParent = entry.position.parent;\n\t\tconst isNoLongerEmpty = entry.length === changeParent.maxOffset;\n\n\t\tif ( isNoLongerEmpty ) {\n\t\t\tmodel.enqueueChange( batch, writer => {\n\t\t\t\tconst storedAttributes = Array.from( changeParent.getAttributeKeys() )\n\t\t\t\t\t.filter( key => key.startsWith( storePrefix ) );\n\n\t\t\t\tfor ( const key of storedAttributes ) {\n\t\t\t\t\twriter.removeAttribute( key, changeParent );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/conversion/conversionhelpers\n */\n\n/**\n * Base class for conversion helpers.\n */\nexport default class ConversionHelpers {\n\t/**\n\t * Creates a conversion helpers instance.\n\t *\n\t * @param {Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * module:engine/conversion/upcastdispatcher~UpcastDispatcher>} dispatchers\n\t */\n\tconstructor( dispatchers ) {\n\t\tthis._dispatchers = dispatchers;\n\t}\n\n\t/**\n\t * Registers a conversion helper.\n\t *\n\t * **Note**: See full usage example in the `{@link module:engine/conversion/conversion~Conversion#for conversion.for()}`\n\t * method description.\n\t *\n\t * @param {Function} conversionHelper The function to be called on event.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tadd( conversionHelper ) {\n\t\tfor ( const dispatcher of this._dispatchers ) {\n\t\t\tconversionHelper( dispatcher );\n\t\t}\n\n\t\treturn this;\n\t}\n}\n","import baseClone from './_baseClone.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n CLONE_SYMBOLS_FLAG = 4;\n\n/**\n * This method is like `_.clone` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 1.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @returns {*} Returns the deep cloned value.\n * @see _.clone\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var deep = _.cloneDeep(objects);\n * console.log(deep[0] === objects[0]);\n * // => false\n */\nfunction cloneDeep(value) {\n return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);\n}\n\nexport default cloneDeep;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * Contains downcast (model-to-view) converters for {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}.\n *\n * @module engine/conversion/downcasthelpers\n */\n\nimport ModelRange from '../model/range';\nimport ModelSelection from '../model/selection';\nimport ModelElement from '../model/element';\n\nimport ViewAttributeElement from '../view/attributeelement';\nimport DocumentSelection from '../model/documentselection';\nimport ConversionHelpers from './conversionhelpers';\n\nimport { cloneDeep } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Downcast conversion helper functions.\n *\n * @extends module:engine/conversion/conversionhelpers~ConversionHelpers\n */\nexport default class DowncastHelpers extends ConversionHelpers {\n\t/**\n\t * Model element to view element conversion helper.\n\t *\n\t * This conversion results in creating a view element. For example, model `<paragraph>Foo</paragraph>` becomes `<p>Foo</p>` in the view.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tview: 'p'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tview: 'div',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'fancyParagraph',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'fancy'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'heading',\n\t *\t\t\tview: ( modelElement, viewWriter ) => {\n\t *\t\t\t\treturn viewWriter.createContainerElement( 'h' + modelElement.getAttribute( 'level' ) )\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #elementToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model element to convert.\n\t * @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function\n\t * that takes the model element and {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer}\n\t * as parameters and returns a view container element.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\telementToElement( config ) {\n\t\treturn this.add( downcastElementToElement( config ) );\n\t}\n\n\t/**\n\t * Model attribute to view element conversion helper.\n\t *\n\t * This conversion results in wrapping view nodes with a view attribute element. For example, a model text node with\n\t * `\"Foo\"` as data and the `bold` attribute becomes `<strong>Foo</strong>` in the view.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: 'strong'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: 'b',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'invert',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: [ 'font-light', 'bg-dark' ]\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'fontSize',\n\t *\t\t\t\tvalues: [ 'big', 'small' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tbig: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '1.2em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tsmall: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '0.8em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: ( modelAttributeValue, viewWriter ) => {\n\t *\t\t\t\treturn viewWriter.createAttributeElement( 'span', {\n\t *\t\t\t\t\tstyle: 'font-weight:' + modelAttributeValue\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'color',\n\t *\t\t\t\tname: '$text'\n\t *\t\t\t},\n\t *\t\t\tview: ( modelAttributeValue, viewWriter ) => {\n\t *\t\t\t\treturn viewWriter.createAttributeElement( 'span', {\n\t *\t\t\t\t\tstyle: 'color:' + modelAttributeValue\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #attributeToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array\n\t * of `String`s with possible values if the model attribute is an enumerable.\n\t * @param {module:engine/view/elementdefinition~ElementDefinition|Function|Object} config.view A view element definition or a function\n\t * that takes the model attribute value and {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer}\n\t * as parameters and returns a view attribute element. If `config.model.values` is\n\t * given, `config.view` should be an object assigning values from `config.model.values` to view element definitions or functions.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tattributeToElement( config ) {\n\t\treturn this.add( downcastAttributeToElement( config ) );\n\t}\n\n\t/**\n\t * Model attribute to view attribute conversion helper.\n\t *\n\t * This conversion results in adding an attribute to a view node, basing on an attribute from a model node. For example,\n\t * `<image src='foo.jpg'></image>` is converted to `<img src='foo.jpg'></img>`.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'source',\n\t *\t\t\tview: 'src'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'source',\n\t *\t\t\tview: 'href',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'image',\n\t *\t\t\t\tkey: 'source'\n\t *\t\t\t},\n\t *\t\t\tview: 'src'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'styled',\n\t *\t\t\t\tvalues: [ 'dark', 'light' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tdark: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: [ 'styled', 'styled-dark' ]\n\t *\t\t\t\t},\n\t *\t\t\t\tlight: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: [ 'styled', 'styled-light' ]\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'styled',\n\t *\t\t\tview: modelAttributeValue => ( { key: 'class', value: 'styled-' + modelAttributeValue } )\n\t *\t\t} );\n\t *\n\t * **Note**: Downcasting to a style property requires providing `value` as an object:\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'lineHeight',\n\t *\t\t\tview: modelAttributeValue => ( {\n\t *\t\t\t\tkey: 'style',\n\t *\t\t\t\tvalue: {\n\t *\t\t\t\t\t'line-height': modelAttributeValue,\n\t *\t\t\t\t\t'border-bottom': '1px dotted #ba2'\n\t *\t\t\t\t}\n\t *\t\t\t} )\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #attributeToAttribute\n\t * @param {Object} config Conversion configuration.\n\t * @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing\n\t * the attribute key, possible values and, optionally, an element name to convert from.\n\t * @param {String|Object|Function} config.view A view attribute key, or a `{ key, value }` object or a function that takes\n\t * the model attribute value and returns a `{ key, value }` object. If `key` is `'class'`, `value` can be a `String` or an\n\t * array of `String`s. If `key` is `'style'`, `value` is an object with key-value pairs. In other cases, `value` is a `String`.\n\t * If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to\n\t * `{ key, value }` objects or a functions.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tattributeToAttribute( config ) {\n\t\treturn this.add( downcastAttributeToAttribute( config ) );\n\t}\n\n\t/**\n\t * Model marker to view element conversion helper.\n\t *\n\t * This conversion results in creating a view element on the boundaries of the converted marker. If the converted marker\n\t * is collapsed, only one element is created. For example, model marker set like this: `<paragraph>F[oo b]ar</paragraph>`\n\t * becomes `<p>F<span data-marker=\"search\"></span>oo b<span data-marker=\"search\"></span>ar</p>` in the view.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: 'marker-search'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: 'search-result',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tattributes: {\n\t *\t\t\t\t\t'data-marker': 'search'\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: ( markerData, viewWriter ) => {\n\t *\t\t\t\treturn viewWriter.createUIElement( 'span', {\n\t *\t\t\t\t\t'data-marker': 'search',\n\t *\t\t\t\t\t'data-start': markerData.isOpening\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * If a function is passed as the `config.view` parameter, it will be used to generate both boundary elements. The function\n\t * receives the `data` object as a parameter and should return an instance of the\n\t * {@link module:engine/view/uielement~UIElement view UI element}. The `data` object and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi `conversionApi`} are passed from\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}. Additionally,\n\t * the `data.isOpening` parameter is passed, which is set to `true` for the marker start boundary element, and `false` to\n\t * the marker end boundary element.\n\t *\n\t * This kind of conversion is useful for saving data into the database, so it should be used in the data conversion pipeline.\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #markerToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model marker (or model marker group) to convert.\n\t * @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function\n\t * that takes the model marker data as a parameter and returns a view UI element.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tmarkerToElement( config ) {\n\t\treturn this.add( downcastMarkerToElement( config ) );\n\t}\n\n\t/**\n\t * Model marker to highlight conversion helper.\n\t *\n\t * This conversion results in creating a highlight on view nodes. For this kind of conversion,\n\t * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor} should be provided.\n\t *\n\t * For text nodes, a `<span>` {@link module:engine/view/attributeelement~AttributeElement} is created and it wraps all text nodes\n\t * in the converted marker range. For example, a model marker set like this: `<paragraph>F[oo b]ar</paragraph>` becomes\n\t * `<p>F<span class=\"comment\">oo b</span>ar</p>` in the view.\n\t *\n\t * {@link module:engine/view/containerelement~ContainerElement} may provide a custom way of handling highlight. Most often,\n\t * the element itself is given classes and attributes described in the highlight descriptor (instead of being wrapped in `<span>`).\n\t * For example, a model marker set like this: `[<image src=\"foo.jpg\"></image>]` becomes `<img src=\"foo.jpg\" class=\"comment\"></img>`\n\t * in the view.\n\t *\n\t * For container elements, the conversion is two-step. While the converter processes the highlight descriptor and passes it\n\t * to a container element, it is the container element instance itself that applies values from the highlight descriptor.\n\t * So, in a sense, the converter takes care of stating what should be applied on what, while the element decides how to apply that.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToHighlight( { model: 'comment', view: { classes: 'comment' } } );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToHighlight( {\n\t *\t\t\tmodel: 'comment',\n\t *\t\t\tview: { classes: 'new-comment' },\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToHighlight( {\n\t *\t\t\tmodel: 'comment',\n\t *\t\t\tview: data => {\n\t *\t\t\t\t// Assuming that the marker name is in a form of comment:commentType.\n\t *\t\t\t\tconst commentType = data.markerName.split( ':' )[ 1 ];\n\t *\n\t *\t\t\t\treturn {\n\t *\t\t\t\t\tclasses: [ 'comment', 'comment-' + commentType ]\n\t *\t\t\t\t};\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * If a function is passed as the `config.view` parameter, it will be used to generate the highlight descriptor. The function\n\t * receives the `data` object as a parameter and should return a\n\t * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor}.\n\t * The `data` object properties are passed from {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}.\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #markerToHighlight\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model marker (or model marker group) to convert.\n\t * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} config.view A highlight descriptor\n\t * that will be used for highlighting or a function that takes the model marker data as a parameter and returns a highlight descriptor.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tmarkerToHighlight( config ) {\n\t\treturn this.add( downcastMarkerToHighlight( config ) );\n\t}\n}\n\n/**\n * Function factory that creates a default downcast converter for text insertion changes.\n *\n * The converter automatically consumes the corresponding value from the consumables list and stops the event (see\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).\n *\n *\t\tmodelDispatcher.on( 'insert:$text', insertText() );\n *\n * @returns {Function} Insert text event converter.\n */\nexport function insertText() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\t\tconst viewText = viewWriter.createText( data.item.data );\n\n\t\tviewWriter.insert( viewPosition, viewText );\n\t};\n}\n\n/**\n * Function factory that creates a default downcast converter for node remove changes.\n *\n *\t\tmodelDispatcher.on( 'remove', remove() );\n *\n * @returns {Function} Remove event converter.\n */\nexport function remove() {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Find view range start position by mapping model position at which the remove happened.\n\t\tconst viewStart = conversionApi.mapper.toViewPosition( data.position );\n\n\t\tconst modelEnd = data.position.getShiftedBy( data.length );\n\t\tconst viewEnd = conversionApi.mapper.toViewPosition( modelEnd, { isPhantom: true } );\n\n\t\tconst viewRange = conversionApi.writer.createRange( viewStart, viewEnd );\n\n\t\t// Trim the range to remove in case some UI elements are on the view range boundaries.\n\t\tconst removed = conversionApi.writer.remove( viewRange.getTrimmed() );\n\n\t\t// After the range is removed, unbind all view elements from the model.\n\t\t// Range inside view document fragment is used to unbind deeply.\n\t\tfor ( const child of conversionApi.writer.createRangeIn( removed ).getItems() ) {\n\t\t\tconversionApi.mapper.unbindViewElement( child );\n\t\t}\n\t};\n}\n\n/**\n * Creates a `<span>` {@link module:engine/view/attributeelement~AttributeElement view attribute element} from the information\n * provided by the {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor} object. If a priority\n * is not provided in the descriptor, the default priority will be used.\n *\n * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor\n * @returns {module:engine/view/attributeelement~AttributeElement}\n */\nexport function createViewElementFromHighlightDescriptor( descriptor ) {\n\tconst viewElement = new ViewAttributeElement( 'span', descriptor.attributes );\n\n\tif ( descriptor.classes ) {\n\t\tviewElement._addClass( descriptor.classes );\n\t}\n\n\tif ( descriptor.priority ) {\n\t\tviewElement._priority = descriptor.priority;\n\t}\n\n\tviewElement._id = descriptor.id;\n\n\treturn viewElement;\n}\n\n/**\n * Function factory that creates a converter which converts a non-collapsed {@link module:engine/model/selection~Selection model selection}\n * to a {@link module:engine/view/documentselection~DocumentSelection view selection}. The converter consumes appropriate\n * value from the `consumable` object and maps model positions from the selection to view positions.\n *\n *\t\tmodelDispatcher.on( 'selection', convertRangeSelection() );\n *\n * @returns {Function} Selection converter.\n */\nexport function convertRangeSelection() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst selection = data.selection;\n\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( selection, 'selection' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewRanges = [];\n\n\t\tfor ( const range of selection.getRanges() ) {\n\t\t\tconst viewRange = conversionApi.mapper.toViewRange( range );\n\t\t\tviewRanges.push( viewRange );\n\t\t}\n\n\t\tconversionApi.writer.setSelection( viewRanges, { backward: selection.isBackward } );\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts a collapsed {@link module:engine/model/selection~Selection model selection} to\n * a {@link module:engine/view/documentselection~DocumentSelection view selection}. The converter consumes appropriate\n * value from the `consumable` object, maps the model selection position to the view position and breaks\n * {@link module:engine/view/attributeelement~AttributeElement attribute elements} at the selection position.\n *\n *\t\tmodelDispatcher.on( 'selection', convertCollapsedSelection() );\n *\n * An example of the view state before and after converting the collapsed selection:\n *\n *\t\t <p><strong>f^oo<strong>bar</p>\n *\t\t-> <p><strong>f</strong>^<strong>oo</strong>bar</p>\n *\n * By breaking attribute elements like `<strong>`, the selection is in a correct element. Then, when the selection attribute is\n * converted, broken attributes might be merged again, or the position where the selection is may be wrapped\n * with different, appropriate attribute elements.\n *\n * See also {@link module:engine/conversion/downcasthelpers~clearAttributes} which does a clean-up\n * by merging attributes.\n *\n * @returns {Function} Selection converter.\n */\nexport function convertCollapsedSelection() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst selection = data.selection;\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( selection, 'selection' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst modelPosition = selection.getFirstPosition();\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( modelPosition );\n\t\tconst brokenPosition = viewWriter.breakAttributes( viewPosition );\n\n\t\tviewWriter.setSelection( brokenPosition );\n\t};\n}\n\n/**\n * Function factory that creates a converter which clears artifacts after the previous\n * {@link module:engine/model/selection~Selection model selection} conversion. It removes all empty\n * {@link module:engine/view/attributeelement~AttributeElement view attribute elements} and merges sibling attributes at all start and end\n * positions of all ranges.\n *\n *\t\t <p><strong>^</strong></p>\n *\t\t-> <p>^</p>\n *\n *\t\t <p><strong>foo</strong>^<strong>bar</strong>bar</p>\n *\t\t-> <p><strong>foo^bar<strong>bar</p>\n *\n *\t\t <p><strong>foo</strong><em>^</em><strong>bar</strong>bar</p>\n *\t\t-> <p><strong>foo^bar<strong>bar</p>\n *\n * This listener should be assigned before any converter for the new selection:\n *\n *\t\tmodelDispatcher.on( 'selection', clearAttributes() );\n *\n * See {@link module:engine/conversion/downcasthelpers~convertCollapsedSelection}\n * which does the opposite by breaking attributes in the selection position.\n *\n * @returns {Function} Selection converter.\n */\nexport function clearAttributes() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\tfor ( const range of viewSelection.getRanges() ) {\n\t\t\t// Not collapsed selection should not have artifacts.\n\t\t\tif ( range.isCollapsed ) {\n\t\t\t\t// Position might be in the node removed by the view writer.\n\t\t\t\tif ( range.end.parent.document ) {\n\t\t\t\t\tconversionApi.writer.mergeAttributes( range.start );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tviewWriter.setSelection( null );\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts set/change/remove attribute changes from the model to the view.\n * It can also be used to convert selection attributes. In that case, an empty attribute element will be created and the\n * selection will be put inside it.\n *\n * Attributes from the model are converted to a view element that will be wrapping these view nodes that are bound to\n * model elements having the given attribute. This is useful for attributes like `bold` that may be set on text nodes in the model\n * but are represented as an element in the view:\n *\n *\t\t[paragraph] MODEL ====> VIEW <p>\n *\t\t\t|- a {bold: true} |- <b>\n *\t\t\t|- b {bold: true} | |- ab\n *\t\t\t|- c |- c\n *\n * Passed `Function` will be provided with the attribute value and then all the parameters of the\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute` event}.\n * It is expected that the function returns an {@link module:engine/view/element~Element}.\n * The result of the function will be the wrapping element.\n * When the provided `Function` does not return any element, no conversion will take place.\n *\n * The converter automatically consumes the corresponding value from the consumables list and stops the event (see\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).\n *\n *\t\tmodelDispatcher.on( 'attribute:bold', wrap( ( modelAttributeValue, viewWriter ) => {\n *\t\t\treturn viewWriter.createAttributeElement( 'strong' );\n *\t\t} );\n *\n * @protected\n * @param {Function} elementCreator Function returning a view element that will be used for wrapping.\n * @returns {Function} Set/change attribute converter.\n */\nexport function wrap( elementCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Recreate current wrapping node. It will be used to unwrap view range if the attribute value has changed\n\t\t// or the attribute was removed.\n\t\tconst oldViewElement = elementCreator( data.attributeOldValue, conversionApi.writer );\n\n\t\t// Create node to wrap with.\n\t\tconst newViewElement = elementCreator( data.attributeNewValue, conversionApi.writer );\n\n\t\tif ( !oldViewElement && !newViewElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\tif ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {\n\t\t\t// Selection attribute conversion.\n\t\t\tviewWriter.wrap( viewSelection.getFirstRange(), newViewElement );\n\t\t} else {\n\t\t\t// Node attribute conversion.\n\t\t\tlet viewRange = conversionApi.mapper.toViewRange( data.range );\n\n\t\t\t// First, unwrap the range from current wrapper.\n\t\t\tif ( data.attributeOldValue !== null && oldViewElement ) {\n\t\t\t\tviewRange = viewWriter.unwrap( viewRange, oldViewElement );\n\t\t\t}\n\n\t\t\tif ( data.attributeNewValue !== null && newViewElement ) {\n\t\t\t\tviewWriter.wrap( viewRange, newViewElement );\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts node insertion changes from the model to the view.\n * The function passed will be provided with all the parameters of the dispatcher's\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert` event}.\n * It is expected that the function returns an {@link module:engine/view/element~Element}.\n * The result of the function will be inserted into the view.\n *\n * The converter automatically consumes the corresponding value from the consumables list, stops the event (see\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}) and binds the model and view elements.\n *\n *\t\tdowncastDispatcher.on(\n *\t\t\t'insert:myElem',\n *\t\t\tinsertElement( ( modelItem, viewWriter ) => {\n *\t\t\t\tconst text = viewWriter.createText( 'myText' );\n *\t\t\t\tconst myElem = viewWriter.createElement( 'myElem', { myAttr: 'my-' + modelItem.getAttribute( 'myAttr' ) }, text );\n *\n *\t\t\t\t// Do something fancy with `myElem` using `modelItem` or other parameters.\n *\n *\t\t\t\treturn myElem;\n *\t\t\t}\n *\t\t) );\n *\n * @protected\n * @param {Function} elementCreator Function returning a view element, which will be inserted.\n * @returns {Function} Insert element event converter.\n */\nexport function insertElement( elementCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewElement = elementCreator( data.item, conversionApi.writer );\n\n\t\tif ( !viewElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\n\t\tconversionApi.mapper.bindElements( data.item, viewElement );\n\t\tconversionApi.writer.insert( viewPosition, viewElement );\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts marker adding change to the\n * {@link module:engine/view/uielement~UIElement view UI element}.\n *\n * The view UI element that will be added to the view depends on the passed parameter. See {@link ~insertElement}.\n * In case of a non-collapsed range, the UI element will not wrap nodes but separate elements will be placed at the beginning\n * and at the end of the range.\n *\n * This converter binds created UI elements with the marker name using {@link module:engine/conversion/mapper~Mapper#bindElementToMarker}.\n *\n * @protected\n * @param {module:engine/view/uielement~UIElement|Function} elementCreator A view UI element or a function returning the view element\n * that will be inserted.\n * @returns {Function} Insert element event converter.\n */\nexport function insertUIElement( elementCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Create two view elements. One will be inserted at the beginning of marker, one at the end.\n\t\t// If marker is collapsed, only \"opening\" element will be inserted.\n\t\tdata.isOpening = true;\n\t\tconst viewStartElement = elementCreator( data, conversionApi.writer );\n\n\t\tdata.isOpening = false;\n\t\tconst viewEndElement = elementCreator( data, conversionApi.writer );\n\n\t\tif ( !viewStartElement || !viewEndElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst markerRange = data.markerRange;\n\n\t\t// Marker that is collapsed has consumable build differently that non-collapsed one.\n\t\t// For more information see `addMarker` event description.\n\t\t// If marker's range is collapsed - check if it can be consumed.\n\t\tif ( markerRange.isCollapsed && !conversionApi.consumable.consume( markerRange, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If marker's range is not collapsed - consume all items inside.\n\t\tfor ( const value of markerRange ) {\n\t\t\tif ( !conversionApi.consumable.consume( value.item, evt.name ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst mapper = conversionApi.mapper;\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// Add \"opening\" element.\n\t\tviewWriter.insert( mapper.toViewPosition( markerRange.start ), viewStartElement );\n\t\tconversionApi.mapper.bindElementToMarker( viewStartElement, data.markerName );\n\n\t\t// Add \"closing\" element only if range is not collapsed.\n\t\tif ( !markerRange.isCollapsed ) {\n\t\t\tviewWriter.insert( mapper.toViewPosition( markerRange.end ), viewEndElement );\n\t\t\tconversionApi.mapper.bindElementToMarker( viewEndElement, data.markerName );\n\t\t}\n\n\t\tevt.stop();\n\t};\n}\n\n// Function factory that returns a default downcast converter for removing a {@link module:engine/view/uielement~UIElement UI element}\n// basing on marker remove change.\n//\n// This converter unbinds elements from the marker name.\n//\n// @returns {Function} Removed UI element converter.\nfunction removeUIElement() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst elements = conversionApi.mapper.markerNameToElements( data.markerName );\n\n\t\tif ( !elements ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const element of elements ) {\n\t\t\tconversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );\n\t\t\tconversionApi.writer.clear( conversionApi.writer.createRangeOn( element ), element );\n\t\t}\n\n\t\tconversionApi.writer.clearClonedElementsGroup( data.markerName );\n\n\t\tevt.stop();\n\t};\n}\n\n// Function factory that creates a converter which converts set/change/remove attribute changes from the model to the view.\n//\n// Attributes from the model are converted to the view element attributes in the view. You may provide a custom function to generate\n// a key-value attribute pair to add/change/remove. If not provided, model attributes will be converted to view element\n// attributes on a one-to-one basis.\n//\n// *Note:** The provided attribute creator should always return the same `key` for a given attribute from the model.\n//\n// The converter automatically consumes the corresponding value from the consumables list and stops the event (see\n// {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).\n//\n//\t\tmodelDispatcher.on( 'attribute:customAttr:myElem', changeAttribute( ( value, data ) => {\n//\t\t\t// Change attribute key from `customAttr` to `class` in the view.\n//\t\t\tconst key = 'class';\n//\t\t\tlet value = data.attributeNewValue;\n//\n//\t\t\t// Force attribute value to 'empty' if the model element is empty.\n//\t\t\tif ( data.item.childCount === 0 ) {\n//\t\t\t\tvalue = 'empty';\n//\t\t\t}\n//\n//\t\t\t// Return the key-value pair.\n//\t\t\treturn { key, value };\n//\t\t} ) );\n//\n// @param {Function} [attributeCreator] Function returning an object with two properties: `key` and `value`, which\n// represent the attribute key and attribute value to be set on a {@link module:engine/view/element~Element view element}.\n// The function is passed the model attribute value as the first parameter and additional data about the change as the second parameter.\n// @returns {Function} Set/change attribute converter.\nfunction changeAttribute( attributeCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst oldAttribute = attributeCreator( data.attributeOldValue, data );\n\t\tconst newAttribute = attributeCreator( data.attributeNewValue, data );\n\n\t\tif ( !oldAttribute && !newAttribute ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// If model item cannot be mapped to a view element, it means item is not an `Element` instance but a `TextProxy` node.\n\t\t// Only elements can have attributes in a view so do not proceed for anything else (#1587).\n\t\tif ( !viewElement ) {\n\t\t\t/**\n\t\t\t * This error occurs when a {@link module:engine/model/textproxy~TextProxy text node's} attribute is to be downcasted\n\t\t\t * by {@link module:engine/conversion/conversion~Conversion#attributeToAttribute `Attribute to Attribute converter`}.\n\t\t\t * In most cases it is caused by converters misconfiguration when only \"generic\" converter is defined:\n\t\t\t *\n\t\t\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t\t\t *\t\t\tmodel: 'attribute-name',\n\t\t\t *\t\t\tview: 'attribute-name'\n\t\t\t *\t\t} ) );\n\t\t\t *\n\t\t\t * and given attribute is used on text node, for example:\n\t\t\t *\n\t\t\t *\t\tmodel.change( writer => {\n\t\t\t *\t\t\twriter.insertText( 'Foo', { 'attribute-name': 'bar' }, parent, 0 );\n\t\t\t *\t\t} );\n\t\t\t *\n\t\t\t * In such cases, to convert the same attribute for both {@link module:engine/model/element~Element}\n\t\t\t * and {@link module:engine/model/textproxy~TextProxy `Text`} nodes, text specific\n\t\t\t * {@link module:engine/conversion/conversion~Conversion#attributeToElement `Attribute to Element converter`}\n\t\t\t * with higher {@link module:utils/priorities~PriorityString priority} must also be defined:\n\t\t\t *\n\t\t\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\t *\t\t\tmodel: {\n\t\t\t *\t\t\t\tkey: 'attribute-name',\n\t\t\t *\t\t\t\tname: '$text'\n\t\t\t *\t\t\t},\n\t\t\t *\t\t\tview: ( value, writer ) => {\n\t\t\t *\t\t\t\treturn writer.createAttributeElement( 'span', { 'attribute-name': value } );\n\t\t\t *\t\t\t},\n\t\t\t *\t\t\tconverterPriority: 'high'\n\t\t\t *\t\t} ) );\n\t\t\t *\n\t\t\t * @error conversion-attribute-to-attribute-on-text\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'conversion-attribute-to-attribute-on-text: ' +\n\t\t\t\t'Trying to convert text node\\'s attribute with attribute-to-attribute converter.',\n\t\t\t\t[ data, conversionApi ]\n\t\t\t);\n\t\t}\n\n\t\t// First remove the old attribute if there was one.\n\t\tif ( data.attributeOldValue !== null && oldAttribute ) {\n\t\t\tif ( oldAttribute.key == 'class' ) {\n\t\t\t\tconst classes = Array.isArray( oldAttribute.value ) ? oldAttribute.value : [ oldAttribute.value ];\n\n\t\t\t\tfor ( const className of classes ) {\n\t\t\t\t\tviewWriter.removeClass( className, viewElement );\n\t\t\t\t}\n\t\t\t} else if ( oldAttribute.key == 'style' ) {\n\t\t\t\tconst keys = Object.keys( oldAttribute.value );\n\n\t\t\t\tfor ( const key of keys ) {\n\t\t\t\t\tviewWriter.removeStyle( key, viewElement );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tviewWriter.removeAttribute( oldAttribute.key, viewElement );\n\t\t\t}\n\t\t}\n\n\t\t// Then set the new attribute.\n\t\tif ( data.attributeNewValue !== null && newAttribute ) {\n\t\t\tif ( newAttribute.key == 'class' ) {\n\t\t\t\tconst classes = Array.isArray( newAttribute.value ) ? newAttribute.value : [ newAttribute.value ];\n\n\t\t\t\tfor ( const className of classes ) {\n\t\t\t\t\tviewWriter.addClass( className, viewElement );\n\t\t\t\t}\n\t\t\t} else if ( newAttribute.key == 'style' ) {\n\t\t\t\tconst keys = Object.keys( newAttribute.value );\n\n\t\t\t\tfor ( const key of keys ) {\n\t\t\t\t\tviewWriter.setStyle( key, newAttribute.value[ key ], viewElement );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tviewWriter.setAttribute( newAttribute.key, newAttribute.value, viewElement );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Function factory that creates a converter which converts the text inside marker's range. The converter wraps the text with\n// {@link module:engine/view/attributeelement~AttributeElement} created from the provided descriptor.\n// See {link module:engine/conversion/downcasthelpers~createViewElementFromHighlightDescriptor}.\n//\n// It can also be used to convert the selection that is inside a marker. In that case, an empty attribute element will be\n// created and the selection will be put inside it.\n//\n// If the highlight descriptor does not provide the `priority` property, `10` will be used.\n//\n// If the highlight descriptor does not provide the `id` property, the name of the marker will be used.\n//\n// This converter binds the created {@link module:engine/view/attributeelement~AttributeElement attribute elemens} with the marker name\n// using the {@link module:engine/conversion/mapper~Mapper#bindElementToMarker} method.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} highlightDescriptor\n// @returns {Function}\nfunction highlightText( highlightDescriptor ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !data.item ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) && !data.item.is( 'textProxy' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst descriptor = prepareDescriptor( highlightDescriptor, data, conversionApi );\n\n\t\tif ( !descriptor ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewElement = createViewElementFromHighlightDescriptor( descriptor );\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\tif ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {\n\t\t\tviewWriter.wrap( viewSelection.getFirstRange(), viewElement, viewSelection );\n\t\t} else {\n\t\t\tconst viewRange = conversionApi.mapper.toViewRange( data.range );\n\t\t\tconst rangeAfterWrap = viewWriter.wrap( viewRange, viewElement );\n\n\t\t\tfor ( const element of rangeAfterWrap.getItems() ) {\n\t\t\t\tif ( element.is( 'attributeElement' ) && element.isSimilar( viewElement ) ) {\n\t\t\t\t\tconversionApi.mapper.bindElementToMarker( element, data.markerName );\n\n\t\t\t\t\t// One attribute element is enough, because all of them are bound together by the view writer.\n\t\t\t\t\t// Mapper uses this binding to get all the elements no matter how many of them are registered in the mapper.\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Converter function factory. It creates a function which applies the marker's highlight to an element inside the marker's range.\n//\n// The converter checks if an element has the `addHighlight` function stored as a\n// {@link module:engine/view/element~Element#_setCustomProperty custom property} and, if so, uses it to apply the highlight.\n// In such case the converter will consume all element's children, assuming that they were handled by the element itself.\n//\n// When the `addHighlight` custom property is not present, the element is not converted in any special way.\n// This means that converters will proceed to convert the element's child nodes.\n//\n// If the highlight descriptor does not provide the `priority` property, `10` will be used.\n//\n// If the highlight descriptor does not provide the `id` property, the name of the marker will be used.\n//\n// This converter binds altered {@link module:engine/view/containerelement~ContainerElement container elements} with the marker name using\n// the {@link module:engine/conversion/mapper~Mapper#bindElementToMarker} method.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} highlightDescriptor\n// @returns {Function}\nfunction highlightElement( highlightDescriptor ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !data.item ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !( data.item instanceof ModelElement ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst descriptor = prepareDescriptor( highlightDescriptor, data, conversionApi );\n\n\t\tif ( !descriptor ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.test( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\n\t\tif ( viewElement && viewElement.getCustomProperty( 'addHighlight' ) ) {\n\t\t\t// Consume element itself.\n\t\t\tconversionApi.consumable.consume( data.item, evt.name );\n\n\t\t\t// Consume all children nodes.\n\t\t\tfor ( const value of ModelRange._createIn( data.item ) ) {\n\t\t\t\tconversionApi.consumable.consume( value.item, evt.name );\n\t\t\t}\n\n\t\t\tviewElement.getCustomProperty( 'addHighlight' )( viewElement, descriptor, conversionApi.writer );\n\n\t\t\tconversionApi.mapper.bindElementToMarker( viewElement, data.markerName );\n\t\t}\n\t};\n}\n\n// Function factory that creates a converter which converts the removing model marker to the view.\n//\n// Both text nodes and elements are handled by this converter but they are handled a bit differently.\n//\n// Text nodes are unwrapped using the {@link module:engine/view/attributeelement~AttributeElement attribute element} created from the\n// provided highlight descriptor. See {link module:engine/conversion/downcasthelpers~HighlightDescriptor}.\n//\n// For elements, the converter checks if an element has the `removeHighlight` function stored as a\n// {@link module:engine/view/element~Element#_setCustomProperty custom property}. If so, it uses it to remove the highlight.\n// In such case, the children of that element will not be converted.\n//\n// When `removeHighlight` is not present, the element is not converted in any special way.\n// The converter will proceed to convert the element's child nodes instead.\n//\n// If the highlight descriptor does not provide the `priority` property, `10` will be used.\n//\n// If the highlight descriptor does not provide the `id` property, the name of the marker will be used.\n//\n// This converter unbinds elements from the marker name.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} highlightDescriptor\n// @returns {Function}\nfunction removeHighlight( highlightDescriptor ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// This conversion makes sense only for non-collapsed range.\n\t\tif ( data.markerRange.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst descriptor = prepareDescriptor( highlightDescriptor, data, conversionApi );\n\n\t\tif ( !descriptor ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// View element that will be used to unwrap `AttributeElement`s.\n\t\tconst viewHighlightElement = createViewElementFromHighlightDescriptor( descriptor );\n\n\t\t// Get all elements bound with given marker name.\n\t\tconst elements = conversionApi.mapper.markerNameToElements( data.markerName );\n\n\t\tif ( !elements ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const element of elements ) {\n\t\t\tconversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );\n\n\t\t\tif ( element.is( 'attributeElement' ) ) {\n\t\t\t\tconversionApi.writer.unwrap( conversionApi.writer.createRangeOn( element ), viewHighlightElement );\n\t\t\t} else {\n\t\t\t\t// if element.is( 'containerElement' ).\n\t\t\t\telement.getCustomProperty( 'removeHighlight' )( element, descriptor.id, conversionApi.writer );\n\t\t\t}\n\t\t}\n\n\t\tconversionApi.writer.clearClonedElementsGroup( data.markerName );\n\n\t\tevt.stop();\n\t};\n}\n\n// Model element to view element conversion helper.\n//\n// See {@link ~DowncastHelpers#elementToElement `.elementToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String} config.model The name of the model element to convert.\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function\n// that takes the model element and {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer}\n// as parameters and returns a view container element.\n// @returns {Function} Conversion helper.\nfunction downcastElementToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconfig.view = normalizeToElementConfig( config.view, 'container' );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'insert:' + config.model, insertElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model attribute to view element conversion helper.\n//\n// See {@link ~DowncastHelpers#attributeToElement `.attributeToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array\n// of `String`s with possible values if the model attribute is an enumerable.\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function|Object} config.view A view element definition or a function\n// that takes the model attribute value and {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer}\n// as parameters and returns a view attribute element. If `config.model.values` is\n// given, `config.view` should be an object assigning values from `config.model.values` to view element definitions or functions.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastAttributeToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst modelKey = config.model.key ? config.model.key : config.model;\n\tlet eventName = 'attribute:' + modelKey;\n\n\tif ( config.model.name ) {\n\t\teventName += ':' + config.model.name;\n\t}\n\n\tif ( config.model.values ) {\n\t\tfor ( const modelValue of config.model.values ) {\n\t\t\tconfig.view[ modelValue ] = normalizeToElementConfig( config.view[ modelValue ], 'attribute' );\n\t\t}\n\t} else {\n\t\tconfig.view = normalizeToElementConfig( config.view, 'attribute' );\n\t}\n\n\tconst elementCreator = getFromAttributeCreator( config );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, wrap( elementCreator ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model attribute to view attribute conversion helper.\n//\n// See {@link ~DowncastHelpers#attributeToAttribute `.attributeToAttribute()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing\n// the attribute key, possible values and, optionally, an element name to convert from.\n// @param {String|Object|Function} config.view A view attribute key, or a `{ key, value }` object or a function that takes\n// the model attribute value and returns a `{ key, value }` object. If `key` is `'class'`, `value` can be a `String` or an\n// array of `String`s. If `key` is `'style'`, `value` is an object with key-value pairs. In other cases, `value` is a `String`.\n// If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to\n// `{ key, value }` objects or a functions.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastAttributeToAttribute( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst modelKey = config.model.key ? config.model.key : config.model;\n\tlet eventName = 'attribute:' + modelKey;\n\n\tif ( config.model.name ) {\n\t\teventName += ':' + config.model.name;\n\t}\n\n\tif ( config.model.values ) {\n\t\tfor ( const modelValue of config.model.values ) {\n\t\t\tconfig.view[ modelValue ] = normalizeToAttributeConfig( config.view[ modelValue ] );\n\t\t}\n\t} else {\n\t\tconfig.view = normalizeToAttributeConfig( config.view );\n\t}\n\n\tconst elementCreator = getFromAttributeCreator( config );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, changeAttribute( elementCreator ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model marker to view element conversion helper.\n//\n// See {@link ~DowncastHelpers#markerToElement `.markerToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String} config.model The name of the model marker (or model marker group) to convert.\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function\n// that takes the model marker data as a parameter and returns a view UI element.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastMarkerToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconfig.view = normalizeToElementConfig( config.view, 'ui' );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'addMarker:' + config.model, insertUIElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'removeMarker:' + config.model, removeUIElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model marker to highlight conversion helper.\n//\n// See {@link ~DowncastHelpers#markerToElement `.markerToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String} config.model The name of the model marker (or model marker group) to convert.\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} config.view A highlight descriptor\n// that will be used for highlighting or a function that takes the model marker data as a parameter and returns a highlight descriptor.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastMarkerToHighlight( config ) {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'addMarker:' + config.model, highlightText( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'addMarker:' + config.model, highlightElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'removeMarker:' + config.model, removeHighlight( config.view ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Takes `config.view`, and if it is an {@link module:engine/view/elementdefinition~ElementDefinition}, converts it\n// to a function (because lower level converters accept only element creator functions).\n//\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function} view View configuration.\n// @param {'container'|'attribute'|'ui'} viewElementType View element type to create.\n// @returns {Function} Element creator function to use in lower level converters.\nfunction normalizeToElementConfig( view, viewElementType ) {\n\tif ( typeof view == 'function' ) {\n\t\t// If `view` is already a function, don't do anything.\n\t\treturn view;\n\t}\n\n\treturn ( modelData, viewWriter ) => createViewElementFromDefinition( view, viewWriter, viewElementType );\n}\n\n// Creates a view element instance from the provided {@link module:engine/view/elementdefinition~ElementDefinition} and class.\n//\n// @param {module:engine/view/elementdefinition~ElementDefinition} viewElementDefinition\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @param {'container'|'attribute'|'ui'} viewElementType\n// @returns {module:engine/view/element~Element}\nfunction createViewElementFromDefinition( viewElementDefinition, viewWriter, viewElementType ) {\n\tif ( typeof viewElementDefinition == 'string' ) {\n\t\t// If `viewElementDefinition` is given as a `String`, normalize it to an object with `name` property.\n\t\tviewElementDefinition = { name: viewElementDefinition };\n\t}\n\n\tlet element;\n\tconst attributes = Object.assign( {}, viewElementDefinition.attributes );\n\n\tif ( viewElementType == 'container' ) {\n\t\telement = viewWriter.createContainerElement( viewElementDefinition.name, attributes );\n\t} else if ( viewElementType == 'attribute' ) {\n\t\tconst options = {\n\t\t\tpriority: viewElementDefinition.priority || ViewAttributeElement.DEFAULT_PRIORITY\n\t\t};\n\n\t\telement = viewWriter.createAttributeElement( viewElementDefinition.name, attributes, options );\n\t} else {\n\t\t// 'ui'.\n\t\telement = viewWriter.createUIElement( viewElementDefinition.name, attributes );\n\t}\n\n\tif ( viewElementDefinition.styles ) {\n\t\tconst keys = Object.keys( viewElementDefinition.styles );\n\n\t\tfor ( const key of keys ) {\n\t\t\tviewWriter.setStyle( key, viewElementDefinition.styles[ key ], element );\n\t\t}\n\t}\n\n\tif ( viewElementDefinition.classes ) {\n\t\tconst classes = viewElementDefinition.classes;\n\n\t\tif ( typeof classes == 'string' ) {\n\t\t\tviewWriter.addClass( classes, element );\n\t\t} else {\n\t\t\tfor ( const className of classes ) {\n\t\t\t\tviewWriter.addClass( className, element );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn element;\n}\n\nfunction getFromAttributeCreator( config ) {\n\tif ( config.model.values ) {\n\t\treturn ( modelAttributeValue, viewWriter ) => {\n\t\t\tconst view = config.view[ modelAttributeValue ];\n\n\t\t\tif ( view ) {\n\t\t\t\treturn view( modelAttributeValue, viewWriter );\n\t\t\t}\n\n\t\t\treturn null;\n\t\t};\n\t} else {\n\t\treturn config.view;\n\t}\n}\n\n// Takes the configuration, adds default parameters if they do not exist and normalizes other parameters to be used in downcast converters\n// for generating a view attribute.\n//\n// @param {Object} view View configuration.\nfunction normalizeToAttributeConfig( view ) {\n\tif ( typeof view == 'string' ) {\n\t\treturn modelAttributeValue => ( { key: view, value: modelAttributeValue } );\n\t} else if ( typeof view == 'object' ) {\n\t\t// { key, value, ... }\n\t\tif ( view.value ) {\n\t\t\treturn () => view;\n\t\t}\n\t\t// { key, ... }\n\t\telse {\n\t\t\treturn modelAttributeValue => ( { key: view.key, value: modelAttributeValue } );\n\t\t}\n\t} else {\n\t\t// function.\n\t\treturn view;\n\t}\n}\n\n// Helper function for `highlight`. Prepares the actual descriptor object using value passed to the converter.\nfunction prepareDescriptor( highlightDescriptor, data, conversionApi ) {\n\t// If passed descriptor is a creator function, call it. If not, just use passed value.\n\tconst descriptor = typeof highlightDescriptor == 'function' ?\n\t\thighlightDescriptor( data, conversionApi ) :\n\t\thighlightDescriptor;\n\n\tif ( !descriptor ) {\n\t\treturn null;\n\t}\n\n\t// Apply default descriptor priority.\n\tif ( !descriptor.priority ) {\n\t\tdescriptor.priority = 10;\n\t}\n\n\t// Default descriptor id is marker name.\n\tif ( !descriptor.id ) {\n\t\tdescriptor.id = data.markerName;\n\t}\n\n\treturn descriptor;\n}\n\n/**\n * An object describing how the marker highlight should be represented in the view.\n *\n * Each text node contained in a highlighted range will be wrapped in a `<span>`\n * {@link module:engine/view/attributeelement~AttributeElement view attribute element} with CSS class(es), attributes and a priority\n * described by this object.\n *\n * Additionally, each {@link module:engine/view/containerelement~ContainerElement container element} can handle displaying the highlight\n * separately by providing the `addHighlight` and `removeHighlight` custom properties. In this case:\n *\n * * The `HighlightDescriptor` object is passed to the `addHighlight` function upon conversion and should be used to apply the highlight to\n * the element.\n * * The descriptor `id` is passed to the `removeHighlight` function upon conversion and should be used to remove the highlight with the\n * given ID from the element.\n *\n * @typedef {Object} module:engine/conversion/downcasthelpers~HighlightDescriptor\n *\n * @property {String|Array.<String>} classes A CSS class or an array of classes to set. If the descriptor is used to\n * create an {@link module:engine/view/attributeelement~AttributeElement attribute element} over text nodes, these classes will be set\n * on that attribute element. If the descriptor is applied to an element, usually these classes will be set on that element, however,\n * this depends on how the element converts the descriptor.\n *\n * @property {String} [id] Descriptor identifier. If not provided, it defaults to the converted marker's name.\n *\n * @property {Number} [priority] Descriptor priority. If not provided, it defaults to `10`. If the descriptor is used to create\n * an {@link module:engine/view/attributeelement~AttributeElement attribute element}, it will be that element's\n * {@link module:engine/view/attributeelement~AttributeElement#priority priority}. If the descriptor is applied to an element,\n * the priority will be used to determine which descriptor is more important.\n *\n * @property {Object} [attributes] Attributes to set. If the descriptor is used to create\n * an {@link module:engine/view/attributeelement~AttributeElement attribute element} over text nodes, these attributes will be set on that\n * attribute element. If the descriptor is applied to an element, usually these attributes will be set on that element, however,\n * this depends on how the element converts the descriptor.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport Matcher from '../view/matcher';\nimport ModelRange from '../model/range';\nimport ConversionHelpers from './conversionhelpers';\n\nimport { cloneDeep } from 'lodash-es';\nimport ModelSelection from '../model/selection';\n\n/**\n * Contains {@link module:engine/view/view view} to {@link module:engine/model/model model} converters for\n * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher}.\n *\n * @module engine/conversion/upcasthelpers\n */\n\n/**\n * Upcast conversion helper functions.\n *\n * @extends module:engine/conversion/conversionhelpers~ConversionHelpers\n */\nexport default class UpcastHelpers extends ConversionHelpers {\n\t/**\n\t * View element to model element conversion helper.\n\t *\n\t * This conversion results in creating a model element. For example,\n\t * view `<p>Foo</p>` becomes `<paragraph>Foo</paragraph>` in the model.\n\t *\n\t * Keep in mind that the element will be inserted only if it is allowed\n\t * by {@link module:engine/model/schema~Schema schema} configuration.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t *\t\t\tview: 'p',\n\t *\t\t\tmodel: 'paragraph'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t *\t\t\tview: 'p',\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'fancy'\n\t *\t\t\t},\n\t *\t\t\tmodel: 'fancyParagraph'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t * \t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'heading'\n\t * \t\t\t},\n\t * \t\t\tmodel: ( viewElement, modelWriter ) => {\n\t * \t\t\t\treturn modelWriter.createElement( 'heading', { level: viewElement.getAttribute( 'data-level' ) } );\n\t * \t\t\t}\n\t * \t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #elementToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {module:engine/view/matcher~MatcherPattern} [config.view] Pattern matching all view elements which should be converted. If not\n\t * set, the converter will fire for every view element.\n\t * @param {String|module:engine/model/element~Element|Function} config.model Name of the model element, a model element\n\t * instance or a function that takes a view element and returns a model element. The model element will be inserted in the model.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\telementToElement( config ) {\n\t\treturn this.add( upcastElementToElement( config ) );\n\t}\n\n\t/**\n\t * View element to model attribute conversion helper.\n\t *\n\t * This conversion results in setting an attribute on a model node. For example, view `<strong>Foo</strong>` becomes\n\t * `Foo` {@link module:engine/model/text~Text model text node} with `bold` attribute set to `true`.\n\t *\n\t * This helper is meant to set a model attribute on all the elements that are inside the converted element:\n\t *\n\t *\t\t<strong>Foo</strong> --> <strong><p>Foo</p></strong> --> <paragraph><$text bold=\"true\">Foo</$text></paragraph>\n\t *\n\t * Above is a sample of HTML code, that goes through autoparagraphing (first step) and then is converted (second step).\n\t * Even though `<strong>` is over `<p>` element, `bold=\"true\"` was added to the text. See\n\t * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#attributeToAttribute} for comparison.\n\t *\n\t * Keep in mind that the attribute will be set only if it is allowed by {@link module:engine/model/schema~Schema schema} configuration.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: 'strong',\n\t *\t\t\tmodel: 'bold'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: 'strong',\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: 'bold'\n\t *\t\t\t},\n\t *\t\t\tmodel: 'bold'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: [ 'styled', 'styled-dark' ]\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'styled',\n\t *\t\t\t\tvalue: 'dark'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * \t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tstyles: {\n\t *\t\t\t\t\t'font-size': /[\\s\\S]+/\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'fontSize',\n\t *\t\t\t\tvalue: viewElement => {\n\t *\t\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\t\t\t\t\tconst value = fontSize.substr( 0, fontSize.length - 2 );\n\t *\n\t *\t\t\t\t\tif ( value <= 10 ) {\n\t *\t\t\t\t\t\treturn 'small';\n\t *\t\t\t\t\t} else if ( value > 12 ) {\n\t *\t\t\t\t\t\treturn 'big';\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #elementToAttribute\n\t * @param {Object} config Conversion configuration.\n\t * @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n\t * @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n\t * the model attribute. `value` property may be set as a function that takes a view element and returns the value.\n\t * If `String` is given, the model attribute value will be set to `true`.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\telementToAttribute( config ) {\n\t\treturn this.add( upcastElementToAttribute( config ) );\n\t}\n\n\t/**\n\t * View attribute to model attribute conversion helper.\n\t *\n\t * This conversion results in setting an attribute on a model node. For example, view `<img src=\"foo.jpg\"></img>` becomes\n\t * `<image source=\"foo.jpg\"></image>` in the model.\n\t *\n\t * This helper is meant to convert view attributes from view elements which got converted to the model, so the view attribute\n\t * is set only on the corresponding model node:\n\t *\n\t *\t\t<div class=\"dark\"><div>foo</div></div> --> <div dark=\"true\"><div>foo</div></div>\n\t *\n\t * Above, `class=\"dark\"` attribute is added only to the `<div>` elements that has it. This is in contrary to\n\t * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToAttribute} which sets attributes for\n\t * all the children in the model:\n\t *\n\t *\t\t<strong>Foo</strong> --> <strong><p>Foo</p></strong> --> <paragraph><$text bold=\"true\">Foo</$text></paragraph>\n\t *\n\t * Above is a sample of HTML code, that goes through autoparagraphing (first step) and then is converted (second step).\n\t * Even though `<strong>` is over `<p>` element, `bold=\"true\"` was added to the text.\n\t *\n\t * Keep in mind that the attribute will be set only if it is allowed by {@link module:engine/model/schema~Schema schema} configuration.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: 'src',\n\t *\t\t\tmodel: 'source'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: { key: 'src' },\n\t *\t\t\tmodel: 'source'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: { key: 'src' },\n\t *\t\t\tmodel: 'source',\n\t *\t\t\tconverterPriority: 'normal'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tkey: 'data-style',\n\t *\t\t\t\tvalue: /[\\s\\S]+/\n\t *\t\t\t},\n\t *\t\t\tmodel: 'styled'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'img',\n\t *\t\t\t\tkey: 'class',\n\t *\t\t\t\tvalue: 'styled-dark'\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'styled',\n\t *\t\t\t\tvalue: 'dark'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tkey: 'class',\n\t *\t\t\t\tvalue: /styled-[\\S]+/\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'styled'\n\t *\t\t\t\tvalue: viewElement => {\n\t *\t\t\t\t\tconst regexp = /styled-([\\S]+)/;\n\t *\t\t\t\t\tconst match = viewElement.getAttribute( 'class' ).match( regexp );\n\t *\n\t *\t\t\t\t\treturn match[ 1 ];\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Converting styles works a bit differently as it requires `view.styles` to be an object and by default\n\t * a model attribute will be set to `true` by such a converter. You can set the model attribute to any value by providing the `value`\n\t * callback that returns the desired value.\n\t *\n\t *\t\t// Default conversion of font-weight style will result in setting bold attribute to true.\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tstyles: {\n\t *\t\t\t\t\t'font-weight': 'bold'\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: 'bold'\n\t *\t\t} );\n\t *\n\t *\t\t// This converter will pass any style value to the `lineHeight` model attribute.\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tstyles: {\n\t *\t\t\t\t\t'line-height': /[\\s\\S]+/\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'lineHeight',\n\t *\t\t\t\tvalue: viewElement => viewElement.getStyle( 'line-height' )\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #attributeToAttribute\n\t * @param {Object} config Conversion configuration.\n\t * @param {String|Object} config.view Specifies which view attribute will be converted. If a `String` is passed,\n\t * attributes with given key will be converted. If an `Object` is passed, it must have a required `key` property,\n\t * specifying view attribute key, and may have an optional `value` property, specifying view attribute value and optional `name`\n\t * property specifying a view element name from/on which the attribute should be converted. `value` can be given as a `String`,\n\t * a `RegExp` or a function callback, that takes view attribute value as the only parameter and returns `Boolean`.\n\t * @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n\t * the model attribute. `value` property may be set as a function that takes a view element and returns the value.\n\t * If `String` is given, the model attribute value will be same as view attribute value.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tattributeToAttribute( config ) {\n\t\treturn this.add( upcastAttributeToAttribute( config ) );\n\t}\n\n\t/**\n\t * View element to model marker conversion helper.\n\t *\n\t * This conversion results in creating a model marker. For example, if the marker was stored in a view as an element:\n\t * `<p>Fo<span data-marker=\"comment\" data-comment-id=\"7\"></span>o</p><p>B<span data-marker=\"comment\" data-comment-id=\"7\"></span>ar</p>`,\n\t * after the conversion is done, the marker will be available in\n\t * {@link module:engine/model/model~Model#markers model document markers}.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: 'marker-search',\n\t *\t\t\tmodel: 'search'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: 'marker-search',\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: 'marker-search',\n\t *\t\t\tmodel: viewElement => 'comment:' + viewElement.getAttribute( 'data-comment-id' )\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tattributes: {\n\t *\t\t\t\t\t'data-marker': 'search'\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: 'search'\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #elementToMarker\n\t * @param {Object} config Conversion configuration.\n\t * @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n\t * @param {String|Function} config.model Name of the model marker, or a function that takes a view element and returns\n\t * a model marker name.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\telementToMarker( config ) {\n\t\treturn this.add( upcastElementToMarker( config ) );\n\t}\n}\n\n/**\n * Function factory, creates a converter that converts {@link module:engine/view/documentfragment~DocumentFragment view document fragment}\n * or all children of {@link module:engine/view/element~Element} into\n * {@link module:engine/model/documentfragment~DocumentFragment model document fragment}.\n * This is the \"entry-point\" converter for upcast (view to model conversion). This converter starts the conversion of all children\n * of passed view document fragment. Those children {@link module:engine/view/node~Node view nodes} are then handled by other converters.\n *\n * This also a \"default\", last resort converter for all view elements that has not been converted by other converters.\n * When a view element is being converted to the model but it does not have converter specified, that view element\n * will be converted to {@link module:engine/model/documentfragment~DocumentFragment model document fragment} and returned.\n *\n * @returns {Function} Universal converter for view {@link module:engine/view/documentfragment~DocumentFragment fragments} and\n * {@link module:engine/view/element~Element elements} that returns\n * {@link module:engine/model/documentfragment~DocumentFragment model fragment} with children of converted view item.\n */\nexport function convertToModelFragment() {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Second argument in `consumable.consume` is discarded for ViewDocumentFragment but is needed for ViewElement.\n\t\tif ( !data.modelRange && conversionApi.consumable.consume( data.viewItem, { name: true } ) ) {\n\t\t\tconst { modelRange, modelCursor } = conversionApi.convertChildren( data.viewItem, data.modelCursor );\n\n\t\t\tdata.modelRange = modelRange;\n\t\t\tdata.modelCursor = modelCursor;\n\t\t}\n\t};\n}\n\n/**\n * Function factory, creates a converter that converts {@link module:engine/view/text~Text} to {@link module:engine/model/text~Text}.\n *\n * @returns {Function} {@link module:engine/view/text~Text View text} converter.\n */\nexport function convertText() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( conversionApi.schema.checkChild( data.modelCursor, '$text' ) ) {\n\t\t\tif ( conversionApi.consumable.consume( data.viewItem ) ) {\n\t\t\t\tconst text = conversionApi.writer.createText( data.viewItem.data );\n\n\t\t\t\tconversionApi.writer.insert( text, data.modelCursor );\n\n\t\t\t\tdata.modelRange = ModelRange._createFromPositionAndShift( data.modelCursor, text.offsetSize );\n\t\t\t\tdata.modelCursor = data.modelRange.end;\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Function factory, creates a callback function which converts a {@link module:engine/view/selection~Selection\n * view selection} taken from the {@link module:engine/view/document~Document#event:selectionChange} event\n * and sets in on the {@link module:engine/model/document~Document#selection model}.\n *\n * **Note**: because there is no view selection change dispatcher nor any other advanced view selection to model\n * conversion mechanism, the callback should be set directly on view document.\n *\n *\t\tview.document.on( 'selectionChange', convertSelectionChange( modelDocument, mapper ) );\n *\n * @param {module:engine/model/model~Model} model Data model.\n * @param {module:engine/conversion/mapper~Mapper} mapper Conversion mapper.\n * @returns {Function} {@link module:engine/view/document~Document#event:selectionChange} callback function.\n */\nexport function convertSelectionChange( model, mapper ) {\n\treturn ( evt, data ) => {\n\t\tconst viewSelection = data.newSelection;\n\t\tconst modelSelection = new ModelSelection();\n\n\t\tconst ranges = [];\n\n\t\tfor ( const viewRange of viewSelection.getRanges() ) {\n\t\t\tranges.push( mapper.toModelRange( viewRange ) );\n\t\t}\n\n\t\tmodelSelection.setTo( ranges, { backward: viewSelection.isBackward } );\n\n\t\tif ( !modelSelection.isEqual( model.document.selection ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( modelSelection );\n\t\t\t} );\n\t\t}\n\t};\n}\n\n// View element to model element conversion helper.\n//\n// See {@link ~UpcastHelpers#elementToElement `.elementToElement()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {module:engine/view/matcher~MatcherPattern} [config.view] Pattern matching all view elements which should be converted. If not\n// set, the converter will fire for every view element.\n// @param {String|module:engine/model/element~Element|Function} config.model Name of the model element, a model element\n// instance or a function that takes a view element and returns a model element. The model element will be inserted in the model.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastElementToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst converter = prepareToElementConverter( config );\n\n\tconst elementName = getViewElementNameFromConfig( config.view );\n\tconst eventName = elementName ? 'element:' + elementName : 'element';\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, converter, { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// View element to model attribute conversion helper.\n//\n// See {@link ~UpcastHelpers#elementToAttribute `.elementToAttribute()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n// @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n// the model attribute. `value` property may be set as a function that takes a view element and returns the value.\n// If `String` is given, the model attribute value will be set to `true`.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastElementToAttribute( config ) {\n\tconfig = cloneDeep( config );\n\n\tnormalizeModelAttributeConfig( config );\n\n\tconst converter = prepareToAttributeConverter( config, false );\n\n\tconst elementName = getViewElementNameFromConfig( config.view );\n\tconst eventName = elementName ? 'element:' + elementName : 'element';\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, converter, { priority: config.converterPriority || 'low' } );\n\t};\n}\n\n// View attribute to model attribute conversion helper.\n//\n// See {@link ~UpcastHelpers#attributeToAttribute `.attributeToAttribute()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String|Object} config.view Specifies which view attribute will be converted. If a `String` is passed,\n// attributes with given key will be converted. If an `Object` is passed, it must have a required `key` property,\n// specifying view attribute key, and may have an optional `value` property, specifying view attribute value and optional `name`\n// property specifying a view element name from/on which the attribute should be converted. `value` can be given as a `String`,\n// a `RegExp` or a function callback, that takes view attribute value as the only parameter and returns `Boolean`.\n// @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n// the model attribute. `value` property may be set as a function that takes a view element and returns the value.\n// If `String` is given, the model attribute value will be same as view attribute value.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastAttributeToAttribute( config ) {\n\tconfig = cloneDeep( config );\n\n\tlet viewKey = null;\n\n\tif ( typeof config.view == 'string' || config.view.key ) {\n\t\tviewKey = normalizeViewAttributeKeyValueConfig( config );\n\t}\n\n\tnormalizeModelAttributeConfig( config, viewKey );\n\n\tconst converter = prepareToAttributeConverter( config, true );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element', converter, { priority: config.converterPriority || 'low' } );\n\t};\n}\n\n// View element to model marker conversion helper.\n//\n// See {@link ~UpcastHelpers#elementToMarker `.elementToMarker()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n// @param {String|Function} config.model Name of the model marker, or a function that takes a view element and returns\n// a model marker name.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastElementToMarker( config ) {\n\tconfig = cloneDeep( config );\n\n\tnormalizeToMarkerConfig( config );\n\n\treturn upcastElementToElement( config );\n}\n\n// Helper function for from-view-element conversion. Checks if `config.view` directly specifies converted view element's name\n// and if so, returns it.\n//\n// @param {Object} config Conversion view config.\n// @returns {String|null} View element name or `null` if name is not directly set.\nfunction getViewElementNameFromConfig( viewConfig ) {\n\tif ( typeof viewConfig == 'string' ) {\n\t\treturn viewConfig;\n\t}\n\n\tif ( typeof viewConfig == 'object' && typeof viewConfig.name == 'string' ) {\n\t\treturn viewConfig.name;\n\t}\n\n\treturn null;\n}\n\n// Helper for to-model-element conversion. Takes a config object and returns a proper converter function.\n//\n// @param {Object} config Conversion configuration.\n// @returns {Function} View to model converter.\nfunction prepareToElementConverter( config ) {\n\tconst matcher = config.view ? new Matcher( config.view ) : null;\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tlet match = {};\n\n\t\t// If `config.view` has not been passed do not try matching. In this case, the converter should fire for all elements.\n\t\tif ( matcher ) {\n\t\t\t// This will be usually just one pattern but we support matchers with many patterns too.\n\t\t\tconst matcherResult = matcher.match( data.viewItem );\n\n\t\t\t// If there is no match, this callback should not do anything.\n\t\t\tif ( !matcherResult ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmatch = matcherResult.match;\n\t\t}\n\n\t\t// Force consuming element's name.\n\t\tmatch.name = true;\n\n\t\t// Create model element basing on config.\n\t\tconst modelElement = getModelElement( config.model, data.viewItem, conversionApi.writer );\n\n\t\t// Do not convert if element building function returned falsy value.\n\t\tif ( !modelElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// When element was already consumed then skip it.\n\t\tif ( !conversionApi.consumable.test( data.viewItem, match ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Find allowed parent for element that we are going to insert.\n\t\t// If current parent does not allow to insert element but one of the ancestors does\n\t\t// then split nodes to allowed parent.\n\t\tconst splitResult = conversionApi.splitToAllowedParent( modelElement, data.modelCursor );\n\n\t\t// When there is no split result it means that we can't insert element to model tree, so let's skip it.\n\t\tif ( !splitResult ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Insert element on allowed position.\n\t\tconversionApi.writer.insert( modelElement, splitResult.position );\n\n\t\t// Convert children and insert to element.\n\t\tconversionApi.convertChildren( data.viewItem, conversionApi.writer.createPositionAt( modelElement, 0 ) );\n\n\t\t// Consume appropriate value from consumable values list.\n\t\tconversionApi.consumable.consume( data.viewItem, match );\n\n\t\tconst parts = conversionApi.getSplitParts( modelElement );\n\n\t\t// Set conversion result range.\n\t\tdata.modelRange = new ModelRange(\n\t\t\tconversionApi.writer.createPositionBefore( modelElement ),\n\t\t\tconversionApi.writer.createPositionAfter( parts[ parts.length - 1 ] )\n\t\t);\n\n\t\t// Now we need to check where the `modelCursor` should be.\n\t\tif ( splitResult.cursorParent ) {\n\t\t\t// If we split parent to insert our element then we want to continue conversion in the new part of the split parent.\n\t\t\t//\n\t\t\t// before: <allowed><notAllowed>foo[]</notAllowed></allowed>\n\t\t\t// after: <allowed><notAllowed>foo</notAllowed><converted></converted><notAllowed>[]</notAllowed></allowed>\n\n\t\t\tdata.modelCursor = conversionApi.writer.createPositionAt( splitResult.cursorParent, 0 );\n\t\t} else {\n\t\t\t// Otherwise just continue after inserted element.\n\n\t\t\tdata.modelCursor = data.modelRange.end;\n\t\t}\n\t};\n}\n\n// Helper function for upcasting-to-element converter. Takes the model configuration, the converted view element\n// and a writer instance and returns a model element instance to be inserted in the model.\n//\n// @param {String|Function|module:engine/model/element~Element} model Model conversion configuration.\n// @param {module:engine/view/node~Node} input The converted view node.\n// @param {module:engine/model/writer~Writer} writer A writer instance to use to create the model element.\nfunction getModelElement( model, input, writer ) {\n\tif ( model instanceof Function ) {\n\t\treturn model( input, writer );\n\t} else {\n\t\treturn writer.createElement( model );\n\t}\n}\n\n// Helper function view-attribute-to-model-attribute helper. Normalizes `config.view` which was set as `String` or\n// as an `Object` with `key`, `value` and `name` properties. Normalized `config.view` has is compatible with\n// {@link module:engine/view/matcher~MatcherPattern}.\n//\n// @param {Object} config Conversion config.\n// @returns {String} Key of the converted view attribute.\nfunction normalizeViewAttributeKeyValueConfig( config ) {\n\tif ( typeof config.view == 'string' ) {\n\t\tconfig.view = { key: config.view };\n\t}\n\n\tconst key = config.view.key;\n\tlet normalized;\n\n\tif ( key == 'class' || key == 'style' ) {\n\t\tconst keyName = key == 'class' ? 'classes' : 'styles';\n\n\t\tnormalized = {\n\t\t\t[ keyName ]: config.view.value\n\t\t};\n\t} else {\n\t\tconst value = typeof config.view.value == 'undefined' ? /[\\s\\S]*/ : config.view.value;\n\n\t\tnormalized = {\n\t\t\tattributes: {\n\t\t\t\t[ key ]: value\n\t\t\t}\n\t\t};\n\t}\n\n\tif ( config.view.name ) {\n\t\tnormalized.name = config.view.name;\n\t}\n\n\tconfig.view = normalized;\n\n\treturn key;\n}\n\n// Helper function that normalizes `config.model` in from-model-attribute conversion. `config.model` can be set\n// as a `String`, an `Object` with only `key` property or an `Object` with `key` and `value` properties. Normalized\n// `config.model` is an `Object` with `key` and `value` properties.\n//\n// @param {Object} config Conversion config.\n// @param {String} viewAttributeKeyToCopy Key of the converted view attribute. If it is set, model attribute value\n// will be equal to view attribute value.\nfunction normalizeModelAttributeConfig( config, viewAttributeKeyToCopy = null ) {\n\tconst defaultModelValue = viewAttributeKeyToCopy === null ? true : viewElement => viewElement.getAttribute( viewAttributeKeyToCopy );\n\n\tconst key = typeof config.model != 'object' ? config.model : config.model.key;\n\tconst value = typeof config.model != 'object' || typeof config.model.value == 'undefined' ? defaultModelValue : config.model.value;\n\n\tconfig.model = { key, value };\n}\n\n// Helper for to-model-attribute conversion. Takes the model attribute name and conversion configuration and returns\n// a proper converter function.\n//\n// @param {String} modelAttributeKey The key of the model attribute to set on a model node.\n// @param {Object|Array.<Object>} config Conversion configuration. It is possible to provide multiple configurations in an array.\n// @param {Boolean} shallow If set to `true` the attribute will be set only on top-level nodes. Otherwise, it will be set\n// on all elements in the range.\nfunction prepareToAttributeConverter( config, shallow ) {\n\tconst matcher = new Matcher( config.view );\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst match = matcher.match( data.viewItem );\n\n\t\t// If there is no match, this callback should not do anything.\n\t\tif ( !match ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelKey = config.model.key;\n\t\tconst modelValue = typeof config.model.value == 'function' ? config.model.value( data.viewItem ) : config.model.value;\n\n\t\t// Do not convert if attribute building function returned falsy value.\n\t\tif ( modelValue === null ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( onlyViewNameIsDefined( config.view, data.viewItem ) ) {\n\t\t\tmatch.match.name = true;\n\t\t} else {\n\t\t\t// Do not test or consume `name` consumable.\n\t\t\tdelete match.match.name;\n\t\t}\n\n\t\t// Try to consume appropriate values from consumable values list.\n\t\tif ( !conversionApi.consumable.test( data.viewItem, match.match ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Since we are converting to attribute we need an range on which we will set the attribute.\n\t\t// If the range is not created yet, we will create it.\n\t\tif ( !data.modelRange ) {\n\t\t\t// Convert children and set conversion result as a current data.\n\t\t\tdata = Object.assign( data, conversionApi.convertChildren( data.viewItem, data.modelCursor ) );\n\t\t}\n\n\t\t// Set attribute on current `output`. `Schema` is checked inside this helper function.\n\t\tconst attributeWasSet = setAttributeOn( data.modelRange, { key: modelKey, value: modelValue }, shallow, conversionApi );\n\n\t\tif ( attributeWasSet ) {\n\t\t\tconversionApi.consumable.consume( data.viewItem, match.match );\n\t\t}\n\t};\n}\n\n// Helper function that checks if element name should be consumed in attribute converters.\n//\n// @param {Object} config Conversion view config.\n// @returns {Boolean}\nfunction onlyViewNameIsDefined( viewConfig, viewItem ) {\n\t// https://github.com/ckeditor/ckeditor5-engine/issues/1786\n\tconst configToTest = typeof viewConfig == 'function' ? viewConfig( viewItem ) : viewConfig;\n\n\tif ( typeof configToTest == 'object' && !getViewElementNameFromConfig( configToTest ) ) {\n\t\treturn false;\n\t}\n\n\treturn !configToTest.classes && !configToTest.attributes && !configToTest.styles;\n}\n\n// Helper function for to-model-attribute converter. Sets model attribute on given range. Checks {@link module:engine/model/schema~Schema}\n// to ensure proper model structure.\n//\n// @param {module:engine/model/range~Range} modelRange Model range on which attribute should be set.\n// @param {Object} modelAttribute Model attribute to set.\n// @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion API.\n// @param {Boolean} shallow If set to `true` the attribute will be set only on top-level nodes. Otherwise, it will be set\n// on all elements in the range.\n// @returns {Boolean} `true` if attribute was set on at least one node from given `modelRange`.\nfunction setAttributeOn( modelRange, modelAttribute, shallow, conversionApi ) {\n\tlet result = false;\n\n\t// Set attribute on each item in range according to Schema.\n\tfor ( const node of Array.from( modelRange.getItems( { shallow } ) ) ) {\n\t\tif ( conversionApi.schema.checkAttribute( node, modelAttribute.key ) ) {\n\t\t\tconversionApi.writer.setAttribute( modelAttribute.key, modelAttribute.value, node );\n\n\t\t\tresult = true;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n// Helper function for upcasting-to-marker conversion. Takes the config in a format requested by `upcastElementToMarker()`\n// function and converts it to a format that is supported by `_upcastElementToElement()` function.\n//\n// @param {Object} config Conversion configuration.\nfunction normalizeToMarkerConfig( config ) {\n\tconst oldModel = config.model;\n\n\tconfig.model = ( viewElement, modelWriter ) => {\n\t\tconst markerName = typeof oldModel == 'string' ? oldModel : oldModel( viewElement );\n\n\t\treturn modelWriter.createElement( '$marker', { 'data-name': markerName } );\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/controller/editingcontroller\n */\n\nimport RootEditableElement from '../view/rooteditableelement';\nimport View from '../view/view';\nimport Mapper from '../conversion/mapper';\nimport DowncastDispatcher from '../conversion/downcastdispatcher';\nimport { clearAttributes, convertCollapsedSelection, convertRangeSelection, insertText, remove } from '../conversion/downcasthelpers';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { convertSelectionChange } from '../conversion/upcasthelpers';\n\n// @if CK_DEBUG_ENGINE // const { dumpTrees, initDocumentDumping } = require( '../dev-utils/utils' );\n\n/**\n * Controller for the editing pipeline. The editing pipeline controls {@link ~EditingController#model model} rendering,\n * including selection handling. It also creates the {@link ~EditingController#view view} which builds a\n * browser-independent virtualization over the DOM elements. The editing controller also attaches default converters.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class EditingController {\n\t/**\n\t * Creates an editing controller instance.\n\t *\n\t * @param {module:engine/model/model~Model} model Editing model.\n\t */\n\tconstructor( model ) {\n\t\t/**\n\t\t * Editor 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 * Editing view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/view~View}\n\t\t */\n\t\tthis.view = new View();\n\n\t\t/**\n\t\t * Mapper which describes the model-view binding.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/mapper~Mapper}\n\t\t */\n\t\tthis.mapper = new Mapper();\n\n\t\t/**\n\t\t * Downcast dispatcher that converts changes from the model to {@link #view the editing view}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/downcastdispatcher~DowncastDispatcher} #downcastDispatcher\n\t\t */\n\t\tthis.downcastDispatcher = new DowncastDispatcher( {\n\t\t\tmapper: this.mapper\n\t\t} );\n\n\t\tconst doc = this.model.document;\n\t\tconst selection = doc.selection;\n\t\tconst markers = this.model.markers;\n\n\t\t// When plugins listen on model changes (on selection change, post fixers, etc) and change the view as a result of\n\t\t// model's change, they might trigger view rendering before the conversion is completed (e.g. before the selection\n\t\t// is converted). We disable rendering for the length of the outermost model change() block to prevent that.\n\t\t//\n\t\t// See https://github.com/ckeditor/ckeditor5-engine/issues/1528\n\t\tthis.listenTo( this.model, '_beforeChanges', () => {\n\t\t\tthis.view._disableRendering( true );\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.listenTo( this.model, '_afterChanges', () => {\n\t\t\tthis.view._disableRendering( false );\n\t\t}, { priority: 'lowest' } );\n\n\t\t// Whenever model document is changed, convert those changes to the view (using model.Document#differ).\n\t\t// Do it on 'low' priority, so changes are converted after other listeners did their job.\n\t\t// Also convert model selection.\n\t\tthis.listenTo( doc, 'change', () => {\n\t\t\tthis.view.change( writer => {\n\t\t\t\tthis.downcastDispatcher.convertChanges( doc.differ, markers, writer );\n\t\t\t\tthis.downcastDispatcher.convertSelection( selection, markers, writer );\n\t\t\t} );\n\t\t}, { priority: 'low' } );\n\n\t\t// Convert selection from the view to the model when it changes in the view.\n\t\tthis.listenTo( this.view.document, 'selectionChange', convertSelectionChange( this.model, this.mapper ) );\n\n\t\t// Attach default model converters.\n\t\tthis.downcastDispatcher.on( 'insert:$text', insertText(), { priority: 'lowest' } );\n\t\tthis.downcastDispatcher.on( 'remove', remove(), { priority: 'low' } );\n\n\t\t// Attach default model selection converters.\n\t\tthis.downcastDispatcher.on( 'selection', clearAttributes(), { priority: 'low' } );\n\t\tthis.downcastDispatcher.on( 'selection', convertRangeSelection(), { priority: 'low' } );\n\t\tthis.downcastDispatcher.on( 'selection', convertCollapsedSelection(), { priority: 'low' } );\n\n\t\t// Binds {@link module:engine/view/document~Document#roots view roots collection} to\n\t\t// {@link module:engine/model/document~Document#roots model roots collection} so creating\n\t\t// model root automatically creates corresponding view root.\n\t\tthis.view.document.roots.bindTo( this.model.document.roots ).using( root => {\n\t\t\t// $graveyard is a special root that has no reflection in the view.\n\t\t\tif ( root.rootName == '$graveyard' ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst viewRoot = new RootEditableElement( root.name );\n\n\t\t\tviewRoot.rootName = root.rootName;\n\t\t\tviewRoot._document = this.view.document;\n\t\t\tthis.mapper.bindElements( root, viewRoot );\n\n\t\t\treturn viewRoot;\n\t\t} );\n\n\t\t// @if CK_DEBUG_ENGINE // initDocumentDumping( this.model.document );\n\t\t// @if CK_DEBUG_ENGINE // initDocumentDumping( this.view.document );\n\n\t\t// @if CK_DEBUG_ENGINE // dumpTrees( this.model.document, this.model.document.version );\n\t\t// @if CK_DEBUG_ENGINE // dumpTrees( this.view.document, this.model.document.version );\n\n\t\t// @if CK_DEBUG_ENGINE // this.model.document.on( 'change', () => {\n\t\t// @if CK_DEBUG_ENGINE //\tdumpTrees( this.view.document, this.model.document.version );\n\t\t// @if CK_DEBUG_ENGINE // }, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Removes all event listeners attached to the `EditingController`. Destroys all objects created\n\t * by `EditingController` that need to be destroyed.\n\t */\n\tdestroy() {\n\t\tthis.view.destroy();\n\t\tthis.stopListening();\n\t}\n}\n\nmix( EditingController, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 core/commandcollection\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Collection of commands. Its instance is available in {@link module:core/editor/editor~Editor#commands `editor.commands`}.\n */\nexport default class CommandCollection {\n\t/**\n\t * Creates collection instance.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Command map.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._commands = new Map();\n\t}\n\n\t/**\n\t * Registers a new command.\n\t *\n\t * @param {String} commandName The name of the command.\n\t * @param {module:core/command~Command} command\n\t */\n\tadd( commandName, command ) {\n\t\tthis._commands.set( commandName, command );\n\t}\n\n\t/**\n\t * Retrieves a command from the collection.\n\t *\n\t * @param {String} commandName The name of the command.\n\t * @returns {module:core/command~Command}\n\t */\n\tget( commandName ) {\n\t\treturn this._commands.get( commandName );\n\t}\n\n\t/**\n\t * Executes a command.\n\t *\n\t * @param {String} commandName The name of the command.\n\t * @param {*} [...commandParams] Command parameters.\n\t */\n\texecute( commandName, ...args ) {\n\t\tconst command = this.get( commandName );\n\n\t\tif ( !command ) {\n\t\t\t/**\n\t\t\t * Command does not exist.\n\t\t\t *\n\t\t\t * @error commandcollection-command-not-found\n\t\t\t * @param {String} commandName Name of the command.\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'commandcollection-command-not-found: Command does not exist.', this, { commandName } );\n\t\t}\n\n\t\tcommand.execute( ...args );\n\t}\n\n\t/**\n\t * Returns iterator of command names.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\t* names() {\n\t\tyield* this._commands.keys();\n\t}\n\n\t/**\n\t * Returns iterator of command instances.\n\t *\n\t * @returns {Iterable.<module:core/command~Command>}\n\t */\n\t* commands() {\n\t\tyield* this._commands.values();\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Returns `[ commandName, commandInstance ]` pairs.\n\t *\n\t * @returns {Iterable.<Array>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._commands[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Destroys all collection commands.\n\t */\n\tdestroy() {\n\t\tfor ( const command of this.commands() ) {\n\t\t\tcommand.destroy();\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/conversion/viewconsumable\n */\n\nimport { isArray } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport StylesMap from '../view/stylesmap';\n\n/**\n * Class used for handling consumption of view {@link module:engine/view/element~Element elements},\n * {@link module:engine/view/text~Text text nodes} and {@link module:engine/view/documentfragment~DocumentFragment document fragments}.\n * Element's name and its parts (attributes, classes and styles) can be consumed separately. Consuming an element's name\n * does not consume its attributes, classes and styles.\n * To add items for consumption use {@link module:engine/conversion/viewconsumable~ViewConsumable#add add method}.\n * To test items use {@link module:engine/conversion/viewconsumable~ViewConsumable#test test method}.\n * To consume items use {@link module:engine/conversion/viewconsumable~ViewConsumable#consume consume method}.\n * To revert already consumed items use {@link module:engine/conversion/viewconsumable~ViewConsumable#revert revert method}.\n *\n *\t\tviewConsumable.add( element, { name: true } ); // Adds element's name as ready to be consumed.\n *\t\tviewConsumable.add( textNode ); // Adds text node for consumption.\n *\t\tviewConsumable.add( docFragment ); // Adds document fragment for consumption.\n *\t\tviewConsumable.test( element, { name: true } ); // Tests if element's name can be consumed.\n *\t\tviewConsumable.test( textNode ); // Tests if text node can be consumed.\n *\t\tviewConsumable.test( docFragment ); // Tests if document fragment can be consumed.\n *\t\tviewConsumable.consume( element, { name: true } ); // Consume element's name.\n *\t\tviewConsumable.consume( textNode ); // Consume text node.\n *\t\tviewConsumable.consume( docFragment ); // Consume document fragment.\n *\t\tviewConsumable.revert( element, { name: true } ); // Revert already consumed element's name.\n *\t\tviewConsumable.revert( textNode ); // Revert already consumed text node.\n *\t\tviewConsumable.revert( docFragment ); // Revert already consumed document fragment.\n */\nexport default class ViewConsumable {\n\t/**\n\t * Creates new ViewConsumable.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Map of consumable elements. If {@link module:engine/view/element~Element element} is used as a key,\n\t\t * {@link module:engine/conversion/viewconsumable~ViewElementConsumables ViewElementConsumables} instance is stored as value.\n\t\t * For {@link module:engine/view/text~Text text nodes} and\n\t\t * {@link module:engine/view/documentfragment~DocumentFragment document fragments} boolean value is stored as value.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map.<module:engine/conversion/viewconsumable~ViewElementConsumables|Boolean>}\n\t\t*/\n\t\tthis._consumables = new Map();\n\t}\n\n\t/**\n\t * Adds {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment} as ready to be consumed.\n\t *\n\t *\t\tviewConsumable.add( p, { name: true } ); // Adds element's name to consume.\n\t *\t\tviewConsumable.add( p, { attributes: 'name' } ); // Adds element's attribute.\n\t *\t\tviewConsumable.add( p, { classes: 'foobar' } ); // Adds element's class.\n\t *\t\tviewConsumable.add( p, { styles: 'color' } ); // Adds element's style\n\t *\t\tviewConsumable.add( p, { attributes: 'name', styles: 'color' } ); // Adds attribute and style.\n\t *\t\tviewConsumable.add( p, { classes: [ 'baz', 'bar' ] } ); // Multiple consumables can be provided.\n\t *\t\tviewConsumable.add( textNode ); // Adds text node to consume.\n\t *\t\tviewConsumable.add( docFragment ); // Adds document fragment to consume.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`\n\t * attribute is provided - it should be handled separately by providing actual style/class.\n\t *\n\t *\t\tviewConsumable.add( p, { attributes: 'style' } ); // This call will throw an exception.\n\t *\t\tviewConsumable.add( p, { styles: 'color' } ); // This is properly handled style.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/text~Text|module:engine/view/documentfragment~DocumentFragment} element\n\t * @param {Object} [consumables] Used only if first parameter is {@link module:engine/view/element~Element view element} instance.\n\t * @param {Boolean} consumables.name If set to true element's name will be included.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names.\n\t */\n\tadd( element, consumables ) {\n\t\tlet elementConsumables;\n\n\t\t// For text nodes and document fragments just mark them as consumable.\n\t\tif ( element.is( 'text' ) || element.is( 'documentFragment' ) ) {\n\t\t\tthis._consumables.set( element, true );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// For elements create new ViewElementConsumables or update already existing one.\n\t\tif ( !this._consumables.has( element ) ) {\n\t\t\telementConsumables = new ViewElementConsumables();\n\t\t\tthis._consumables.set( element, elementConsumables );\n\t\t} else {\n\t\t\telementConsumables = this._consumables.get( element );\n\t\t}\n\n\t\telementConsumables.add( consumables );\n\t}\n\n\t/**\n\t * Tests if {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment} can be consumed.\n\t * It returns `true` when all items included in method's call can be consumed. Returns `false` when\n\t * first already consumed item is found and `null` when first non-consumable item is found.\n\t *\n\t *\t\tviewConsumable.test( p, { name: true } ); // Tests element's name.\n\t *\t\tviewConsumable.test( p, { attributes: 'name' } ); // Tests attribute.\n\t *\t\tviewConsumable.test( p, { classes: 'foobar' } ); // Tests class.\n\t *\t\tviewConsumable.test( p, { styles: 'color' } ); // Tests style.\n\t *\t\tviewConsumable.test( p, { attributes: 'name', styles: 'color' } ); // Tests attribute and style.\n\t *\t\tviewConsumable.test( p, { classes: [ 'baz', 'bar' ] } ); // Multiple consumables can be tested.\n\t *\t\tviewConsumable.test( textNode ); // Tests text node.\n\t *\t\tviewConsumable.test( docFragment ); // Tests document fragment.\n\t *\n\t * Testing classes and styles as attribute will test if all added classes/styles can be consumed.\n\t *\n\t *\t\tviewConsumable.test( p, { attributes: 'class' } ); // Tests if all added classes can be consumed.\n\t *\t\tviewConsumable.test( p, { attributes: 'style' } ); // Tests if all added styles can be consumed.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/text~Text|module:engine/view/documentfragment~DocumentFragment} element\n\t * @param {Object} [consumables] Used only if first parameter is {@link module:engine/view/element~Element view element} instance.\n\t * @param {Boolean} consumables.name If set to true element's name will be included.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names.\n\t * @returns {Boolean|null} Returns `true` when all items included in method's call can be consumed. Returns `false`\n\t * when first already consumed item is found and `null` when first non-consumable item is found.\n\t */\n\ttest( element, consumables ) {\n\t\tconst elementConsumables = this._consumables.get( element );\n\n\t\tif ( elementConsumables === undefined ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// For text nodes and document fragments return stored boolean value.\n\t\tif ( element.is( 'text' ) || element.is( 'documentFragment' ) ) {\n\t\t\treturn elementConsumables;\n\t\t}\n\n\t\t// For elements test consumables object.\n\t\treturn elementConsumables.test( consumables );\n\t}\n\n\t/**\n\t * Consumes {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment}.\n\t * It returns `true` when all items included in method's call can be consumed, otherwise returns `false`.\n\t *\n\t *\t\tviewConsumable.consume( p, { name: true } ); // Consumes element's name.\n\t *\t\tviewConsumable.consume( p, { attributes: 'name' } ); // Consumes element's attribute.\n\t *\t\tviewConsumable.consume( p, { classes: 'foobar' } ); // Consumes element's class.\n\t *\t\tviewConsumable.consume( p, { styles: 'color' } ); // Consumes element's style.\n\t *\t\tviewConsumable.consume( p, { attributes: 'name', styles: 'color' } ); // Consumes attribute and style.\n\t *\t\tviewConsumable.consume( p, { classes: [ 'baz', 'bar' ] } ); // Multiple consumables can be consumed.\n\t *\t\tviewConsumable.consume( textNode ); // Consumes text node.\n\t *\t\tviewConsumable.consume( docFragment ); // Consumes document fragment.\n\t *\n\t * Consuming classes and styles as attribute will test if all added classes/styles can be consumed.\n\t *\n\t *\t\tviewConsumable.consume( p, { attributes: 'class' } ); // Consume only if all added classes can be consumed.\n\t *\t\tviewConsumable.consume( p, { attributes: 'style' } ); // Consume only if all added styles can be consumed.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/text~Text|module:engine/view/documentfragment~DocumentFragment} element\n\t * @param {Object} [consumables] Used only if first parameter is {@link module:engine/view/element~Element view element} instance.\n\t * @param {Boolean} consumables.name If set to true element's name will be included.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names.\n\t * @returns {Boolean} Returns `true` when all items included in method's call can be consumed,\n\t * otherwise returns `false`.\n\t */\n\tconsume( element, consumables ) {\n\t\tif ( this.test( element, consumables ) ) {\n\t\t\tif ( element.is( 'text' ) || element.is( 'documentFragment' ) ) {\n\t\t\t\t// For text nodes and document fragments set value to false.\n\t\t\t\tthis._consumables.set( element, false );\n\t\t\t} else {\n\t\t\t\t// For elements - consume consumables object.\n\t\t\t\tthis._consumables.get( element ).consume( consumables );\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Reverts {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment} so they can be consumed once again.\n\t * Method does not revert items that were never previously added for consumption, even if they are included in\n\t * method's call.\n\t *\n\t *\t\tviewConsumable.revert( p, { name: true } ); // Reverts element's name.\n\t *\t\tviewConsumable.revert( p, { attributes: 'name' } ); // Reverts element's attribute.\n\t *\t\tviewConsumable.revert( p, { classes: 'foobar' } ); // Reverts element's class.\n\t *\t\tviewConsumable.revert( p, { styles: 'color' } ); // Reverts element's style.\n\t *\t\tviewConsumable.revert( p, { attributes: 'name', styles: 'color' } ); // Reverts attribute and style.\n\t *\t\tviewConsumable.revert( p, { classes: [ 'baz', 'bar' ] } ); // Multiple names can be reverted.\n\t *\t\tviewConsumable.revert( textNode ); // Reverts text node.\n\t *\t\tviewConsumable.revert( docFragment ); // Reverts document fragment.\n\t *\n\t * Reverting classes and styles as attribute will revert all classes/styles that were previously added for\n\t * consumption.\n\t *\n\t *\t\tviewConsumable.revert( p, { attributes: 'class' } ); // Reverts all classes added for consumption.\n\t *\t\tviewConsumable.revert( p, { attributes: 'style' } ); // Reverts all styles added for consumption.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/text~Text|module:engine/view/documentfragment~DocumentFragment} element\n\t * @param {Object} [consumables] Used only if first parameter is {@link module:engine/view/element~Element view element} instance.\n\t * @param {Boolean} consumables.name If set to true element's name will be included.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names.\n\t */\n\trevert( element, consumables ) {\n\t\tconst elementConsumables = this._consumables.get( element );\n\n\t\tif ( elementConsumables !== undefined ) {\n\t\t\tif ( element.is( 'text' ) || element.is( 'documentFragment' ) ) {\n\t\t\t\t// For text nodes and document fragments - set consumable to true.\n\t\t\t\tthis._consumables.set( element, true );\n\t\t\t} else {\n\t\t\t\t// For elements - revert items from consumables object.\n\t\t\t\telementConsumables.revert( consumables );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates consumable object from {@link module:engine/view/element~Element view element}. Consumable object will include\n\t * element's name and all its attributes, classes and styles.\n\t *\n\t * @static\n\t * @param {module:engine/view/element~Element} element\n\t * @returns {Object} consumables\n\t */\n\tstatic consumablesFromElement( element ) {\n\t\tconst consumables = {\n\t\t\tname: true,\n\t\t\tattributes: [],\n\t\t\tclasses: [],\n\t\t\tstyles: []\n\t\t};\n\n\t\tconst attributes = element.getAttributeKeys();\n\n\t\tfor ( const attribute of attributes ) {\n\t\t\t// Skip classes and styles - will be added separately.\n\t\t\tif ( attribute == 'style' || attribute == 'class' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconsumables.attributes.push( attribute );\n\t\t}\n\n\t\tconst classes = element.getClassNames();\n\n\t\tfor ( const className of classes ) {\n\t\t\tconsumables.classes.push( className );\n\t\t}\n\n\t\tconst styles = element.getStyleNames();\n\n\t\tfor ( const style of styles ) {\n\t\t\tconsumables.styles.push( style );\n\t\t}\n\n\t\treturn consumables;\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/viewconsumable~ViewConsumable ViewConsumable} instance from\n\t * {@link module:engine/view/node~Node node} or {@link module:engine/view/documentfragment~DocumentFragment document fragment}.\n\t * Instance will contain all elements, child nodes, attributes, styles and classes added for consumption.\n\t *\n\t * @static\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} from View node or document fragment\n\t * from which `ViewConsumable` will be created.\n\t * @param {module:engine/conversion/viewconsumable~ViewConsumable} [instance] If provided, given `ViewConsumable` instance will be used\n\t * to add all consumables. It will be returned instead of a new instance.\n\t */\n\tstatic createFrom( from, instance ) {\n\t\tif ( !instance ) {\n\t\t\tinstance = new ViewConsumable();\n\t\t}\n\n\t\tif ( from.is( 'text' ) ) {\n\t\t\tinstance.add( from );\n\n\t\t\treturn instance;\n\t\t}\n\n\t\t// Add `from` itself, if it is an element.\n\t\tif ( from.is( 'element' ) ) {\n\t\t\tinstance.add( from, ViewConsumable.consumablesFromElement( from ) );\n\t\t}\n\n\t\tif ( from.is( 'documentFragment' ) ) {\n\t\t\tinstance.add( from );\n\t\t}\n\n\t\tfor ( const child of from.getChildren() ) {\n\t\t\tinstance = ViewConsumable.createFrom( child, instance );\n\t\t}\n\n\t\treturn instance;\n\t}\n}\n\n/**\n * This is a private helper-class for {@link module:engine/conversion/viewconsumable~ViewConsumable}.\n * It represents and manipulates consumable parts of a single {@link module:engine/view/element~Element}.\n *\n * @private\n */\nclass ViewElementConsumables {\n\t/**\n\t * Creates ViewElementConsumables instance.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Flag indicating if name of the element can be consumed.\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._canConsumeName = null;\n\n\t\t/**\n\t\t * Contains maps of element's consumables: attributes, classes and styles.\n\t\t *\n\t\t * @private\n\t\t * @member {Object}\n\t\t */\n\t\tthis._consumables = {\n\t\t\tattributes: new Map(),\n\t\t\tstyles: new Map(),\n\t\t\tclasses: new Map()\n\t\t};\n\t}\n\n\t/**\n\t * Adds consumable parts of the {@link module:engine/view/element~Element view element}.\n\t * Element's name itself can be marked to be consumed (when element's name is consumed its attributes, classes and\n\t * styles still could be consumed):\n\t *\n\t *\t\tconsumables.add( { name: true } );\n\t *\n\t * Attributes classes and styles:\n\t *\n\t *\t\tconsumables.add( { attributes: 'title', classes: 'foo', styles: 'color' } );\n\t *\t\tconsumables.add( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`\n\t * attribute is provided - it should be handled separately by providing `style` and `class` in consumables object.\n\t *\n\t * @param {Object} consumables Object describing which parts of the element can be consumed.\n\t * @param {Boolean} consumables.name If set to `true` element's name will be added as consumable.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names to add as consumable.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names to add as consumable.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names to add as consumable.\n\t */\n\tadd( consumables ) {\n\t\tif ( consumables.name ) {\n\t\t\tthis._canConsumeName = true;\n\t\t}\n\n\t\tfor ( const type in this._consumables ) {\n\t\t\tif ( type in consumables ) {\n\t\t\t\tthis._add( type, consumables[ type ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Tests if parts of the {@link module:engine/view/node~Node view node} can be consumed.\n\t *\n\t * Element's name can be tested:\n\t *\n\t *\t\tconsumables.test( { name: true } );\n\t *\n\t * Attributes classes and styles:\n\t *\n\t *\t\tconsumables.test( { attributes: 'title', classes: 'foo', styles: 'color' } );\n\t *\t\tconsumables.test( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );\n\t *\n\t * @param {Object} consumables Object describing which parts of the element should be tested.\n\t * @param {Boolean} consumables.name If set to `true` element's name will be tested.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names to test.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names to test.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names to test.\n\t * @returns {Boolean|null} `true` when all tested items can be consumed, `null` when even one of the items\n\t * was never marked for consumption and `false` when even one of the items was already consumed.\n\t */\n\ttest( consumables ) {\n\t\t// Check if name can be consumed.\n\t\tif ( consumables.name && !this._canConsumeName ) {\n\t\t\treturn this._canConsumeName;\n\t\t}\n\n\t\tfor ( const type in this._consumables ) {\n\t\t\tif ( type in consumables ) {\n\t\t\t\tconst value = this._test( type, consumables[ type ] );\n\n\t\t\t\tif ( value !== true ) {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Return true only if all can be consumed.\n\t\treturn true;\n\t}\n\n\t/**\n\t * Consumes parts of {@link module:engine/view/element~Element view element}. This function does not check if consumable item\n\t * is already consumed - it consumes all consumable items provided.\n\t * Element's name can be consumed:\n\t *\n\t *\t\tconsumables.consume( { name: true } );\n\t *\n\t * Attributes classes and styles:\n\t *\n\t *\t\tconsumables.consume( { attributes: 'title', classes: 'foo', styles: 'color' } );\n\t *\t\tconsumables.consume( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );\n\t *\n\t * @param {Object} consumables Object describing which parts of the element should be consumed.\n\t * @param {Boolean} consumables.name If set to `true` element's name will be consumed.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names to consume.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names to consume.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names to consume.\n\t */\n\tconsume( consumables ) {\n\t\tif ( consumables.name ) {\n\t\t\tthis._canConsumeName = false;\n\t\t}\n\n\t\tfor ( const type in this._consumables ) {\n\t\t\tif ( type in consumables ) {\n\t\t\t\tthis._consume( type, consumables[ type ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Revert already consumed parts of {@link module:engine/view/element~Element view Element}, so they can be consumed once again.\n\t * Element's name can be reverted:\n\t *\n\t *\t\tconsumables.revert( { name: true } );\n\t *\n\t * Attributes classes and styles:\n\t *\n\t *\t\tconsumables.revert( { attributes: 'title', classes: 'foo', styles: 'color' } );\n\t *\t\tconsumables.revert( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );\n\t *\n\t * @param {Object} consumables Object describing which parts of the element should be reverted.\n\t * @param {Boolean} consumables.name If set to `true` element's name will be reverted.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names to revert.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names to revert.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names to revert.\n\t */\n\trevert( consumables ) {\n\t\tif ( consumables.name ) {\n\t\t\tthis._canConsumeName = true;\n\t\t}\n\n\t\tfor ( const type in this._consumables ) {\n\t\t\tif ( type in consumables ) {\n\t\t\t\tthis._revert( type, consumables[ type ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Helper method that adds consumables of a given type: attribute, class or style.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`\n\t * type is provided - it should be handled separately by providing actual style/class type.\n\t *\n\t * @private\n\t * @param {String} type Type of the consumable item: `attributes`, `classes` or `styles`.\n\t * @param {String|Array.<String>} item Consumable item or array of items.\n\t */\n\t_add( type, item ) {\n\t\tconst items = isArray( item ) ? item : [ item ];\n\t\tconst consumables = this._consumables[ type ];\n\n\t\tfor ( const name of items ) {\n\t\t\tif ( type === 'attributes' && ( name === 'class' || name === 'style' ) ) {\n\t\t\t\t/**\n\t\t\t\t * Class and style attributes should be handled separately in\n\t\t\t\t * {@link module:engine/conversion/viewconsumable~ViewConsumable#add `ViewConsumable#add()`}.\n\t\t\t\t *\n\t\t\t\t * What you have done is trying to use:\n\t\t\t\t *\n\t\t\t\t *\t\tconsumables.add( { attributes: [ 'class', 'style' ] } );\n\t\t\t\t *\n\t\t\t\t * While each class and style should be registered separately:\n\t\t\t\t *\n\t\t\t\t *\t\tconsumables.add( { classes: 'some-class', styles: 'font-weight' } );\n\t\t\t\t *\n\t\t\t\t * @error viewconsumable-invalid-attribute\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'viewconsumable-invalid-attribute: Classes and styles should be handled separately.', this );\n\t\t\t}\n\n\t\t\tconsumables.set( name, true );\n\n\t\t\tif ( type === 'styles' ) {\n\t\t\t\tfor ( const alsoName of StylesMap.getRelatedStyles( name ) ) {\n\t\t\t\t\tconsumables.set( alsoName, true );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Helper method that tests consumables of a given type: attribute, class or style.\n\t *\n\t * @private\n\t * @param {String} type Type of the consumable item: `attributes`, `classes` or `styles`.\n\t * @param {String|Array.<String>} item Consumable item or array of items.\n\t * @returns {Boolean|null} Returns `true` if all items can be consumed, `null` when one of the items cannot be\n\t * consumed and `false` when one of the items is already consumed.\n\t */\n\t_test( type, item ) {\n\t\tconst items = isArray( item ) ? item : [ item ];\n\t\tconst consumables = this._consumables[ type ];\n\n\t\tfor ( const name of items ) {\n\t\t\tif ( type === 'attributes' && ( name === 'class' || name === 'style' ) ) {\n\t\t\t\tconst consumableName = name == 'class' ? 'classes' : 'styles';\n\n\t\t\t\t// Check all classes/styles if class/style attribute is tested.\n\t\t\t\tconst value = this._test( consumableName, [ ...this._consumables[ consumableName ].keys() ] );\n\n\t\t\t\tif ( value !== true ) {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst value = consumables.get( name );\n\t\t\t\t// Return null if attribute is not found.\n\t\t\t\tif ( value === undefined ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tif ( !value ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Helper method that consumes items of a given type: attribute, class or style.\n\t *\n\t * @private\n\t * @param {String} type Type of the consumable item: `attributes`, `classes` or `styles`.\n\t * @param {String|Array.<String>} item Consumable item or array of items.\n\t */\n\t_consume( type, item ) {\n\t\tconst items = isArray( item ) ? item : [ item ];\n\t\tconst consumables = this._consumables[ type ];\n\n\t\tfor ( const name of items ) {\n\t\t\tif ( type === 'attributes' && ( name === 'class' || name === 'style' ) ) {\n\t\t\t\tconst consumableName = name == 'class' ? 'classes' : 'styles';\n\n\t\t\t\t// If class or style is provided for consumption - consume them all.\n\t\t\t\tthis._consume( consumableName, [ ...this._consumables[ consumableName ].keys() ] );\n\t\t\t} else {\n\t\t\t\tconsumables.set( name, false );\n\n\t\t\t\tif ( type == 'styles' ) {\n\t\t\t\t\tfor ( const toConsume of StylesMap.getRelatedStyles( name ) ) {\n\t\t\t\t\t\tconsumables.set( toConsume, false );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Helper method that reverts items of a given type: attribute, class or style.\n\t *\n\t * @private\n\t * @param {String} type Type of the consumable item: `attributes`, `classes` or , `styles`.\n\t * @param {String|Array.<String>} item Consumable item or array of items.\n\t */\n\t_revert( type, item ) {\n\t\tconst items = isArray( item ) ? item : [ item ];\n\t\tconst consumables = this._consumables[ type ];\n\n\t\tfor ( const name of items ) {\n\t\t\tif ( type === 'attributes' && ( name === 'class' || name === 'style' ) ) {\n\t\t\t\tconst consumableName = name == 'class' ? 'classes' : 'styles';\n\n\t\t\t\t// If class or style is provided for reverting - revert them all.\n\t\t\t\tthis._revert( consumableName, [ ...this._consumables[ consumableName ].keys() ] );\n\t\t\t} else {\n\t\t\t\tconst value = consumables.get( name );\n\n\t\t\t\tif ( value === false ) {\n\t\t\t\t\tconsumables.set( name, true );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/schema\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\nimport Range from './range';\nimport Position from './position';\nimport Element from './element';\nimport Text from './text';\nimport TreeWalker from './treewalker';\n\n/**\n * The model's schema. It defines allowed and disallowed structures of nodes as well as nodes' attributes.\n * The schema is usually defined by features and based on them the editing framework and features\n * make decisions how to change and process the model.\n *\n * The instance of schema is available in {@link module:engine/model/model~Model#schema `editor.model.schema`}.\n *\n * Read more about the schema in:\n *\n * * {@glink framework/guides/architecture/editing-engine#schema \"Schema\"} section of the\n * {@glink framework/guides/architecture/editing-engine Introduction to the \"Editing engine architecture\"}.\n * * {@glink framework/guides/deep-dive/schema \"Schema\" deep dive} guide.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Schema {\n\t/**\n\t * Creates schema instance.\n\t */\n\tconstructor() {\n\t\tthis._sourceDefinitions = {};\n\n\t\t/**\n\t\t * A dictionary containing attribute properties.\n\t\t *\n\t\t * @private\n\t\t * @member {Object.<String,String>}\n\t\t */\n\t\tthis._attributeProperties = {};\n\n\t\tthis.decorate( 'checkChild' );\n\t\tthis.decorate( 'checkAttribute' );\n\n\t\tthis.on( 'checkAttribute', ( evt, args ) => {\n\t\t\targs[ 0 ] = new SchemaContext( args[ 0 ] );\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.on( 'checkChild', ( evt, args ) => {\n\t\t\targs[ 0 ] = new SchemaContext( args[ 0 ] );\n\t\t\targs[ 1 ] = this.getDefinition( args[ 1 ] );\n\t\t}, { priority: 'highest' } );\n\t}\n\n\t/**\n\t * Registers schema item. Can only be called once for every item name.\n\t *\n\t *\t\tschema.register( 'paragraph', {\n\t *\t\t\tinheritAllFrom: '$block'\n\t *\t\t} );\n\t *\n\t * @param {String} itemName\n\t * @param {module:engine/model/schema~SchemaItemDefinition} definition\n\t */\n\tregister( itemName, definition ) {\n\t\tif ( this._sourceDefinitions[ itemName ] ) {\n\t\t\t/**\n\t\t\t * A single item cannot be registered twice in the schema.\n\t\t\t *\n\t\t\t * This situation may happen when:\n\t\t\t *\n\t\t\t * * Two or more plugins called {@link #register `register()`} with the same name. This will usually mean that\n\t\t\t * there is a collision between plugins which try to use the same element in the model. Unfortunately,\n\t\t\t * the only way to solve this is by modifying one of these plugins to use a unique model element name.\n\t\t\t * * A single plugin was loaded twice. This happens when it is installed by npm/yarn in two versions\n\t\t\t * and usually means one or more of the following issues:\n\t\t\t * * a version mismatch (two of your dependencies require two different versions of this plugin),\n\t\t\t * * incorrect imports (this plugin is somehow imported twice in a way which confuses webpack),\n\t\t\t * * mess in `node_modules/` (`rm -rf node_modules/` may help).\n\t\t\t *\n\t\t\t * **Note:** Check the logged `itemName` to better understand which plugin was duplicated/conflicting.\n\t\t\t *\n\t\t\t * @param itemName The name of the model element that is being registered twice.\n\t\t\t * @error schema-cannot-register-item-twice\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'schema-cannot-register-item-twice: A single item cannot be registered twice in the schema.',\n\t\t\t\tthis,\n\t\t\t\t{\n\t\t\t\t\titemName\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tthis._sourceDefinitions[ itemName ] = [\n\t\t\tObject.assign( {}, definition )\n\t\t];\n\n\t\tthis._clearCache();\n\t}\n\n\t/**\n\t * Extends a {@link #register registered} item's definition.\n\t *\n\t * Extending properties such as `allowIn` will add more items to the existing properties,\n\t * while redefining properties such as `isBlock` will override the previously defined ones.\n\t *\n\t *\t\tschema.register( 'foo', {\n\t *\t\t\tallowIn: '$root',\n\t *\t\t\tisBlock: true;\n\t *\t\t} );\n\t *\t\tschema.extend( 'foo', {\n\t *\t\t\tallowIn: 'blockQuote',\n\t *\t\t\tisBlock: false\n\t *\t\t} );\n\t *\n\t *\t\tschema.getDefinition( 'foo' );\n\t *\t\t//\t{\n\t *\t\t//\t\tallowIn: [ '$root', 'blockQuote' ],\n\t *\t\t// \t\tisBlock: false\n\t *\t\t//\t}\n\t *\n\t * @param {String} itemName\n\t * @param {module:engine/model/schema~SchemaItemDefinition} definition\n\t */\n\textend( itemName, definition ) {\n\t\tif ( !this._sourceDefinitions[ itemName ] ) {\n\t\t\t/**\n\t\t\t * Cannot extend an item which was not registered yet.\n\t\t\t *\n\t\t\t * This error happens when a plugin tries to extend the schema definition of an item which was not\n\t\t\t * {@link #register registered} yet.\n\t\t\t *\n\t\t\t * @param itemName The name of the model element which is being extended.\n\t\t\t * @error schema-cannot-extend-missing-item\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'schema-cannot-extend-missing-item: Cannot extend an item which was not registered yet.', this, {\n\t\t\t\titemName\n\t\t\t} );\n\t\t}\n\n\t\tthis._sourceDefinitions[ itemName ].push( Object.assign( {}, definition ) );\n\n\t\tthis._clearCache();\n\t}\n\n\t/**\n\t * Returns all registered items.\n\t *\n\t * @returns {Object.<String,module:engine/model/schema~SchemaCompiledItemDefinition>}\n\t */\n\tgetDefinitions() {\n\t\tif ( !this._compiledDefinitions ) {\n\t\t\tthis._compile();\n\t\t}\n\n\t\treturn this._compiledDefinitions;\n\t}\n\n\t/**\n\t * Returns a definition of the given item or `undefined` if item is not registered.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t * @returns {module:engine/model/schema~SchemaCompiledItemDefinition}\n\t */\n\tgetDefinition( item ) {\n\t\tlet itemName;\n\n\t\tif ( typeof item == 'string' ) {\n\t\t\titemName = item;\n\t\t} else if ( item.is && ( item.is( 'text' ) || item.is( 'textProxy' ) ) ) {\n\t\t\titemName = '$text';\n\t\t}\n\t\t// Element or module:engine/model/schema~SchemaContextItem.\n\t\telse {\n\t\t\titemName = item.name;\n\t\t}\n\n\t\treturn this.getDefinitions()[ itemName ];\n\t}\n\n\t/**\n\t * Returns `true` if the given item is registered in the schema.\n\t *\n\t *\t\tschema.isRegistered( 'paragraph' ); // -> true\n\t *\t\tschema.isRegistered( editor.model.document.getRoot() ); // -> true\n\t *\t\tschema.isRegistered( 'foo' ); // -> false\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisRegistered( item ) {\n\t\treturn !!this.getDefinition( item );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * a block by {@link module:engine/model/schema~SchemaItemDefinition}'s `isBlock` property.\n\t *\n\t *\t\tschema.isBlock( 'paragraph' ); // -> true\n\t *\t\tschema.isBlock( '$root' ); // -> false\n\t *\n\t *\t\tconst paragraphElement = writer.createElement( 'paragraph' );\n\t *\t\tschema.isBlock( paragraphElement ); // -> true\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisBlock( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\treturn !!( def && def.isBlock );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * a limit element by {@link module:engine/model/schema~SchemaItemDefinition}'s `isLimit` or `isObject` property\n\t * (all objects are also limits).\n\t *\n\t *\t\tschema.isLimit( 'paragraph' ); // -> false\n\t *\t\tschema.isLimit( '$root' ); // -> true\n\t *\t\tschema.isLimit( editor.model.document.getRoot() ); // -> true\n\t *\t\tschema.isLimit( 'image' ); // -> true\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisLimit( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !!( def.isLimit || def.isObject );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * an object element by {@link module:engine/model/schema~SchemaItemDefinition}'s `isObject` property.\n\t *\n\t *\t\tschema.isObject( 'paragraph' ); // -> false\n\t *\t\tschema.isObject( 'image' ); // -> true\n\t *\n\t *\t\tconst imageElement = writer.createElement( 'image' );\n\t *\t\tschema.isObject( imageElement ); // -> true\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisObject( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\treturn !!( def && def.isObject );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * an inline element by {@link module:engine/model/schema~SchemaItemDefinition}'s `isInline` property.\n\t *\n\t *\t\tschema.isInline( 'paragraph' ); // -> false\n\t *\t\tschema.isInline( 'softBreak' ); // -> true\n\t *\n\t *\t\tconst text = writer.createText('foo' );\n\t *\t\tschema.isInline( text ); // -> true\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisInline( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\treturn !!( def && def.isInline );\n\t}\n\n\t/**\n\t * Checks whether the given node (`child`) can be a child of the given context.\n\t *\n\t *\t\tschema.checkChild( model.document.getRoot(), paragraph ); // -> false\n\t *\n\t *\t\tschema.register( 'paragraph', {\n\t *\t\t\tallowIn: '$root'\n\t *\t\t} );\n\t *\t\tschema.checkChild( model.document.getRoot(), paragraph ); // -> true\n\t *\n\t * Note: When verifying whether the given node can be a child of the given context, the\n\t * schema also verifies the entire context — from its root to its last element. Therefore, it is possible\n\t * for `checkChild()` to return `false` even though the context's last element can contain the checked child.\n\t * It happens if one of the context's elements does not allow its child.\n\t *\n\t * @fires checkChild\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context The context in which the child will be checked.\n\t * @param {module:engine/model/node~Node|String} def The child to check.\n\t */\n\tcheckChild( context, def ) {\n\t\t// Note: context and child are already normalized here to a SchemaContext and SchemaCompiledItemDefinition.\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this._checkContextMatch( def, context );\n\t}\n\n\t/**\n\t * Checks whether the given attribute can be applied in the given context (on the last\n\t * item of the context).\n\t *\n\t *\t\tschema.checkAttribute( textNode, 'bold' ); // -> false\n\t *\n\t *\t\tschema.extend( '$text', {\n\t *\t\t\tallowAttributes: 'bold'\n\t *\t\t} );\n\t *\t\tschema.checkAttribute( textNode, 'bold' ); // -> true\n\t *\n\t * @fires checkAttribute\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context The context in which the attribute will be checked.\n\t * @param {String} attributeName\n\t */\n\tcheckAttribute( context, attributeName ) {\n\t\tconst def = this.getDefinition( context.last );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn def.allowAttributes.includes( attributeName );\n\t}\n\n\t/**\n\t * Checks whether the given element (`elementToMerge`) can be merged with the specified base element (`positionOrBaseElement`).\n\t *\n\t * In other words — whether `elementToMerge`'s children {@link #checkChild are allowed} in the `positionOrBaseElement`.\n\t *\n\t * This check ensures that elements merged with {@link module:engine/model/writer~Writer#merge `Writer#merge()`}\n\t * will be valid.\n\t *\n\t * Instead of elements, you can pass the instance of the {@link module:engine/model/position~Position} class as the\n\t * `positionOrBaseElement`. It means that the elements before and after the position will be checked whether they can be merged.\n\t *\n\t * @param {module:engine/model/position~Position|module:engine/model/element~Element} positionOrBaseElement The position or base\n\t * element to which the `elementToMerge` will be merged.\n\t * @param {module:engine/model/element~Element} elementToMerge The element to merge. Required if `positionOrBaseElement` is an element.\n\t * @returns {Boolean}\n\t */\n\tcheckMerge( positionOrBaseElement, elementToMerge = null ) {\n\t\tif ( positionOrBaseElement instanceof Position ) {\n\t\t\tconst nodeBefore = positionOrBaseElement.nodeBefore;\n\t\t\tconst nodeAfter = positionOrBaseElement.nodeAfter;\n\n\t\t\tif ( !( nodeBefore instanceof Element ) ) {\n\t\t\t\t/**\n\t\t\t\t * The node before the merge position must be an element.\n\t\t\t\t *\n\t\t\t\t * @error schema-check-merge-no-element-before\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'schema-check-merge-no-element-before: The node before the merge position must be an element.',\n\t\t\t\t\tthis\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( !( nodeAfter instanceof Element ) ) {\n\t\t\t\t/**\n\t\t\t\t * The node after the merge position must be an element.\n\t\t\t\t *\n\t\t\t\t * @error schema-check-merge-no-element-after\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'schema-check-merge-no-element-after: The node after the merge position must be an element.',\n\t\t\t\t\tthis\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn this.checkMerge( nodeBefore, nodeAfter );\n\t\t}\n\n\t\tfor ( const child of elementToMerge.getChildren() ) {\n\t\t\tif ( !this.checkChild( positionOrBaseElement, child ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Allows registering a callback to the {@link #checkChild} method calls.\n\t *\n\t * Callbacks allow you to implement rules which are not otherwise possible to achieve\n\t * by using the declarative API of {@link module:engine/model/schema~SchemaItemDefinition}.\n\t * For example, by using this method you can disallow elements in specific contexts.\n\t *\n\t * This method is a shorthand for using the {@link #event:checkChild} event. For even better control,\n\t * you can use that event instead.\n\t *\n\t * Example:\n\t *\n\t *\t\t// Disallow heading1 directly inside a blockQuote.\n\t *\t\tschema.addChildCheck( ( context, childDefinition ) => {\n\t *\t\t\tif ( context.endsWith( 'blockQuote' ) && childDefinition.name == 'heading1' ) {\n\t *\t\t\t\treturn false;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Which translates to:\n\t *\n\t *\t\tschema.on( 'checkChild', ( evt, args ) => {\n\t *\t\t\tconst context = args[ 0 ];\n\t *\t\t\tconst childDefinition = args[ 1 ];\n\t *\n\t *\t\t\tif ( context.endsWith( 'blockQuote' ) && childDefinition && childDefinition.name == 'heading1' ) {\n\t *\t\t\t\t// Prevent next listeners from being called.\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t\t// Set the checkChild()'s return value.\n\t *\t\t\t\tevt.return = false;\n\t *\t\t\t}\n\t *\t\t}, { priority: 'high' } );\n\t *\n\t * @param {Function} callback The callback to be called. It is called with two parameters:\n\t * {@link module:engine/model/schema~SchemaContext} (context) instance and\n\t * {@link module:engine/model/schema~SchemaCompiledItemDefinition} (child-to-check definition).\n\t * The callback may return `true/false` to override `checkChild()`'s return value. If it does not return\n\t * a boolean value, the default algorithm (or other callbacks) will define `checkChild()`'s return value.\n\t */\n\taddChildCheck( callback ) {\n\t\tthis.on( 'checkChild', ( evt, [ ctx, childDef ] ) => {\n\t\t\t// checkChild() was called with a non-registered child.\n\t\t\t// In 99% cases such check should return false, so not to overcomplicate all callbacks\n\t\t\t// don't even execute them.\n\t\t\tif ( !childDef ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst retValue = callback( ctx, childDef );\n\n\t\t\tif ( typeof retValue == 'boolean' ) {\n\t\t\t\tevt.stop();\n\t\t\t\tevt.return = retValue;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Allows registering a callback to the {@link #checkAttribute} method calls.\n\t *\n\t * Callbacks allow you to implement rules which are not otherwise possible to achieve\n\t * by using the declarative API of {@link module:engine/model/schema~SchemaItemDefinition}.\n\t * For example, by using this method you can disallow attribute if node to which it is applied\n\t * is contained within some other element (e.g. you want to disallow `bold` on `$text` within `heading1`).\n\t *\n\t * This method is a shorthand for using the {@link #event:checkAttribute} event. For even better control,\n\t * you can use that event instead.\n\t *\n\t * Example:\n\t *\n\t *\t\t// Disallow bold on $text inside heading1.\n\t *\t\tschema.addAttributeCheck( ( context, attributeName ) => {\n\t *\t\t\tif ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {\n\t *\t\t\t\treturn false;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Which translates to:\n\t *\n\t *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n\t *\t\t\tconst context = args[ 0 ];\n\t *\t\t\tconst attributeName = args[ 1 ];\n\t *\n\t *\t\t\tif ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {\n\t *\t\t\t\t// Prevent next listeners from being called.\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t\t// Set the checkAttribute()'s return value.\n\t *\t\t\t\tevt.return = false;\n\t *\t\t\t}\n\t *\t\t}, { priority: 'high' } );\n\t *\n\t * @param {Function} callback The callback to be called. It is called with two parameters:\n\t * {@link module:engine/model/schema~SchemaContext} (context) instance and attribute name.\n\t * The callback may return `true/false` to override `checkAttribute()`'s return value. If it does not return\n\t * a boolean value, the default algorithm (or other callbacks) will define `checkAttribute()`'s return value.\n\t */\n\taddAttributeCheck( callback ) {\n\t\tthis.on( 'checkAttribute', ( evt, [ ctx, attributeName ] ) => {\n\t\t\tconst retValue = callback( ctx, attributeName );\n\n\t\t\tif ( typeof retValue == 'boolean' ) {\n\t\t\t\tevt.stop();\n\t\t\t\tevt.return = retValue;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * This method allows assigning additional metadata to the model attributes. For example,\n\t * {@link module:engine/model/schema~AttributeProperties `AttributeProperties#isFormatting` property} is\n\t * used to mark formatting attributes (like `bold` or `italic`).\n\t *\n\t *\t\t// Mark bold as a formatting attribute.\n\t *\t\tschema.setAttributeProperties( 'bold', {\n\t *\t\t\tisFormatting: true\n\t *\t\t} );\n\t *\n\t *\t\t// Override code not to be considered a formatting markup.\n\t *\t\tschema.setAttributeProperties( 'code', {\n\t *\t\t\tisFormatting: false\n\t *\t\t} );\n\t *\n\t * Properties are not limited to members defined in the\n\t * {@link module:engine/model/schema~AttributeProperties `AttributeProperties` type} and you can also use custom properties:\n\t *\n\t *\t\tschema.setAttributeProperties( 'blockQuote', {\n\t *\t\t\tcustomProperty: 'value'\n\t *\t\t} );\n\t *\n\t * Subsequent calls with the same attribute will extend its custom properties:\n\t *\n\t *\t\tschema.setAttributeProperties( 'blockQuote', {\n\t *\t\t\tone: 1\n\t *\t\t} );\n\t *\n\t *\t\tschema.setAttributeProperties( 'blockQuote', {\n\t *\t\t\ttwo: 2\n\t *\t\t} );\n\t *\n\t *\t\tconsole.log( schema.getAttributeProperties( 'blockQuote' ) );\n\t *\t\t// Logs: { one: 1, two: 2 }\n\t *\n\t * @param {String} attributeName A name of the attribute to receive the properties.\n\t * @param {module:engine/model/schema~AttributeProperties} properties A dictionary of properties.\n\t */\n\tsetAttributeProperties( attributeName, properties ) {\n\t\tthis._attributeProperties[ attributeName ] = Object.assign( this.getAttributeProperties( attributeName ), properties );\n\t}\n\n\t/**\n\t * Returns properties associated with a given model attribute. See {@link #setAttributeProperties `setAttributeProperties()`}.\n\t *\n\t * @param {String} attributeName A name of the attribute.\n\t * @returns {module:engine/model/schema~AttributeProperties}\n\t */\n\tgetAttributeProperties( attributeName ) {\n\t\treturn this._attributeProperties[ attributeName ] || {};\n\t}\n\n\t/**\n\t * Returns the lowest {@link module:engine/model/schema~Schema#isLimit limit element} containing the entire\n\t * selection/range/position or the root otherwise.\n\t *\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|\n\t * module:engine/model/range~Range|module:engine/model/position~Position} selectionOrRangeOrPosition\n\t * The selection/range/position to check.\n\t * @returns {module:engine/model/element~Element} The lowest limit element containing\n\t * the entire `selectionOrRangeOrPosition`.\n\t */\n\tgetLimitElement( selectionOrRangeOrPosition ) {\n\t\tlet element;\n\n\t\tif ( selectionOrRangeOrPosition instanceof Position ) {\n\t\t\telement = selectionOrRangeOrPosition.parent;\n\t\t} else {\n\t\t\tconst ranges = selectionOrRangeOrPosition instanceof Range ?\n\t\t\t\t[ selectionOrRangeOrPosition ] :\n\t\t\t\tArray.from( selectionOrRangeOrPosition.getRanges() );\n\n\t\t\t// Find the common ancestor for all selection's ranges.\n\t\t\telement = ranges\n\t\t\t\t.reduce( ( element, range ) => {\n\t\t\t\t\tconst rangeCommonAncestor = range.getCommonAncestor();\n\n\t\t\t\t\tif ( !element ) {\n\t\t\t\t\t\treturn rangeCommonAncestor;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn element.getCommonAncestor( rangeCommonAncestor, { includeSelf: true } );\n\t\t\t\t}, null );\n\t\t}\n\n\t\twhile ( !this.isLimit( element ) ) {\n\t\t\tif ( element.parent ) {\n\t\t\t\telement = element.parent;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn element;\n\t}\n\n\t/**\n\t * Checks whether the attribute is allowed in selection:\n\t *\n\t * * if the selection is not collapsed, then checks if the attribute is allowed on any of nodes in that range,\n\t * * if the selection is collapsed, then checks if on the selection position there's a text with the\n\t * specified attribute allowed.\n\t *\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * Selection which will be checked.\n\t * @param {String} attribute The name of the attribute to check.\n\t * @returns {Boolean}\n\t */\n\tcheckAttributeInSelection( selection, attribute ) {\n\t\tif ( selection.isCollapsed ) {\n\t\t\tconst firstPosition = selection.getFirstPosition();\n\t\t\tconst context = [\n\t\t\t\t...firstPosition.getAncestors(),\n\t\t\t\tnew Text( '', selection.getAttributes() )\n\t\t\t];\n\n\t\t\t// Check whether schema allows for a text with the attribute in the selection.\n\t\t\treturn this.checkAttribute( context, attribute );\n\t\t} else {\n\t\t\tconst ranges = selection.getRanges();\n\n\t\t\t// For all ranges, check nodes in them until you find a node that is allowed to have the attribute.\n\t\t\tfor ( const range of ranges ) {\n\t\t\t\tfor ( const value of range ) {\n\t\t\t\t\tif ( this.checkAttribute( value.item, attribute ) ) {\n\t\t\t\t\t\t// If we found a node that is allowed to have the attribute, return true.\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If we haven't found such node, return false.\n\t\treturn false;\n\t}\n\n\t/**\n\t * Transforms the given set of ranges into a set of ranges where the given attribute is allowed (and can be applied).\n\t *\n\t * @param {Array.<module:engine/model/range~Range>} ranges Ranges to be validated.\n\t * @param {String} attribute The name of the attribute to check.\n\t * @returns {Iterable.<module:engine/model/range~Range>} Ranges in which the attribute is allowed.\n\t */\n\t* getValidRanges( ranges, attribute ) {\n\t\tranges = convertToMinimalFlatRanges( ranges );\n\n\t\tfor ( const range of ranges ) {\n\t\t\tyield* this._getValidRangesForRange( range, attribute );\n\t\t}\n\t}\n\n\t/**\n\t * Basing on given `position`, finds and returns a {@link module:engine/model/range~Range range} which is\n\t * nearest to that `position` and is a correct range for selection.\n\t *\n\t * The correct selection range might be collapsed when it is located in a position where the text node can be placed.\n\t * Non-collapsed range is returned when selection can be placed around element marked as an \"object\" in\n\t * the {@link module:engine/model/schema~Schema schema}.\n\t *\n\t * Direction of searching for the nearest correct selection range can be specified as:\n\t *\n\t * * `both` - searching will be performed in both ways,\n\t * * `forward` - searching will be performed only forward,\n\t * * `backward` - searching will be performed only backward.\n\t *\n\t * When valid selection range cannot be found, `null` is returned.\n\t *\n\t * @param {module:engine/model/position~Position} position Reference position where new selection range should be looked for.\n\t * @param {'both'|'forward'|'backward'} [direction='both'] Search direction.\n\t * @returns {module:engine/model/range~Range|null} Nearest selection range or `null` if one cannot be found.\n\t */\n\tgetNearestSelectionRange( position, direction = 'both' ) {\n\t\t// Return collapsed range if provided position is valid.\n\t\tif ( this.checkChild( position, '$text' ) ) {\n\t\t\treturn new Range( position );\n\t\t}\n\n\t\tlet backwardWalker, forwardWalker;\n\n\t\tif ( direction == 'both' || direction == 'backward' ) {\n\t\t\tbackwardWalker = new TreeWalker( { startPosition: position, direction: 'backward' } );\n\t\t}\n\n\t\tif ( direction == 'both' || direction == 'forward' ) {\n\t\t\tforwardWalker = new TreeWalker( { startPosition: position } );\n\t\t}\n\n\t\tfor ( const data of combineWalkers( backwardWalker, forwardWalker ) ) {\n\t\t\tconst type = ( data.walker == backwardWalker ? 'elementEnd' : 'elementStart' );\n\t\t\tconst value = data.value;\n\n\t\t\tif ( value.type == type && this.isObject( value.item ) ) {\n\t\t\t\treturn Range._createOn( value.item );\n\t\t\t}\n\n\t\t\tif ( this.checkChild( value.nextPosition, '$text' ) ) {\n\t\t\t\treturn new Range( value.nextPosition );\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Tries to find position ancestors that allows to insert given node.\n\t * It starts searching from the given position and goes node by node to the top of the model tree\n\t * as long as {@link module:engine/model/schema~Schema#isLimit limit element},\n\t * {@link module:engine/model/schema~Schema#isObject object element} or top-most ancestor won't be reached.\n\t *\n\t * @params {module:engine/model/position~Position} position Position from searching will start.\n\t * @params {module:engine/model/node~Node|String} node Node for which allowed parent should be found or its name.\n\t * @returns {module:engine/model/element~Element|null} element Allowed parent or null if nothing was found.\n\t */\n\tfindAllowedParent( position, node ) {\n\t\tlet parent = position.parent;\n\n\t\twhile ( parent ) {\n\t\t\tif ( this.checkChild( parent, node ) ) {\n\t\t\t\treturn parent;\n\t\t\t}\n\n\t\t\t// Do not split limit elements.\n\t\t\tif ( this.isLimit( parent ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Removes attributes disallowed by the schema.\n\t *\n\t * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes that will be filtered.\n\t * @param {module:engine/model/writer~Writer} writer\n\t */\n\tremoveDisallowedAttributes( nodes, writer ) {\n\t\tfor ( const node of nodes ) {\n\t\t\t// When node is a `Text` it has no children, so just filter it out.\n\t\t\tif ( node.is( 'text' ) ) {\n\t\t\t\tremoveDisallowedAttributeFromNode( this, node, writer );\n\t\t\t}\n\t\t\t// In a case of `Element` iterates through positions between nodes inside this element\n\t\t\t// and filter out node before the current position, or position parent when position\n\t\t\t// is at start of an element. Using positions prevent from omitting merged nodes\n\t\t\t// see https://github.com/ckeditor/ckeditor5-engine/issues/1789.\n\t\t\telse {\n\t\t\t\tconst rangeInNode = Range._createIn( node );\n\t\t\t\tconst positionsInRange = rangeInNode.getPositions();\n\n\t\t\t\tfor ( const position of positionsInRange ) {\n\t\t\t\t\tconst item = position.nodeBefore || position.parent;\n\n\t\t\t\t\tremoveDisallowedAttributeFromNode( this, item, writer );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates an instance of the schema context.\n\t *\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context\n\t * @returns {module:engine/model/schema~SchemaContext}\n\t */\n\tcreateContext( context ) {\n\t\treturn new SchemaContext( context );\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_clearCache() {\n\t\tthis._compiledDefinitions = null;\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_compile() {\n\t\tconst compiledDefinitions = {};\n\t\tconst sourceRules = this._sourceDefinitions;\n\t\tconst itemNames = Object.keys( sourceRules );\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompiledDefinitions[ itemName ] = compileBaseItemRule( sourceRules[ itemName ], itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompileAllowContentOf( compiledDefinitions, itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompileAllowWhere( compiledDefinitions, itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompileAllowAttributesOf( compiledDefinitions, itemName );\n\t\t\tcompileInheritPropertiesFrom( compiledDefinitions, itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcleanUpAllowIn( compiledDefinitions, itemName );\n\t\t\tcleanUpAllowAttributes( compiledDefinitions, itemName );\n\t\t}\n\n\t\tthis._compiledDefinitions = compiledDefinitions;\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/schema~SchemaCompiledItemDefinition} def\n\t * @param {module:engine/model/schema~SchemaContext} context\n\t * @param {Number} contextItemIndex\n\t */\n\t_checkContextMatch( def, context, contextItemIndex = context.length - 1 ) {\n\t\tconst contextItem = context.getItem( contextItemIndex );\n\n\t\tif ( def.allowIn.includes( contextItem.name ) ) {\n\t\t\tif ( contextItemIndex == 0 ) {\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\tconst parentRule = this.getDefinition( contextItem );\n\n\t\t\t\treturn this._checkContextMatch( parentRule, context, contextItemIndex - 1 );\n\t\t\t}\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Takes a flat range and an attribute name. Traverses the range recursively and deeply to find and return all ranges\n\t * inside the given range on which the attribute can be applied.\n\t *\n\t * This is a helper function for {@link ~Schema#getValidRanges}.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range Range to process.\n\t * @param {String} attribute The name of the attribute to check.\n\t * @returns {Iterable.<module:engine/model/range~Range>} Ranges in which the attribute is allowed.\n\t */\n\t* _getValidRangesForRange( range, attribute ) {\n\t\tlet start = range.start;\n\t\tlet end = range.start;\n\n\t\tfor ( const item of range.getItems( { shallow: true } ) ) {\n\t\t\tif ( item.is( 'element' ) ) {\n\t\t\t\tyield* this._getValidRangesForRange( Range._createIn( item ), attribute );\n\t\t\t}\n\n\t\t\tif ( !this.checkAttribute( item, attribute ) ) {\n\t\t\t\tif ( !start.isEqual( end ) ) {\n\t\t\t\t\tyield new Range( start, end );\n\t\t\t\t}\n\n\t\t\t\tstart = Position._createAfter( item );\n\t\t\t}\n\n\t\t\tend = Position._createAfter( item );\n\t\t}\n\n\t\tif ( !start.isEqual( end ) ) {\n\t\t\tyield new Range( start, end );\n\t\t}\n\t}\n}\n\nmix( Schema, ObservableMixin );\n\n/**\n * Event fired when the {@link #checkChild} method is called. It allows plugging in\n * additional behavior – e.g. implementing rules which cannot be defined using the declarative\n * {@link module:engine/model/schema~SchemaItemDefinition} interface.\n *\n * **Note:** The {@link #addChildCheck} method is a more handy way to register callbacks. Internally,\n * it registers a listener to this event but comes with a simpler API and it is the recommended choice\n * in most of the cases.\n *\n * The {@link #checkChild} method fires an event because it is\n * {@link module:utils/observablemixin~ObservableMixin#decorate decorated} with it. Thanks to that you can\n * use this event in a various way, but the most important use case is overriding standard behaviour of the\n * `checkChild()` method. Let's see a typical listener template:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst childDefinition = args[ 1 ];\n *\t\t}, { priority: 'high' } );\n *\n * The listener is added with a `high` priority to be executed before the default method is really called. The `args` callback\n * parameter contains arguments passed to `checkChild( context, child )`. However, the `context` parameter is already\n * normalized to a {@link module:engine/model/schema~SchemaContext} instance and `child` to a\n * {@link module:engine/model/schema~SchemaCompiledItemDefinition} instance, so you don't have to worry about\n * the various ways how `context` and `child` may be passed to `checkChild()`.\n *\n * **Note:** `childDefinition` may be `undefined` if `checkChild()` was called with a non-registered element.\n *\n * So, in order to implement a rule \"disallow `heading1` in `blockQuote`\" you can add such a listener:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst childDefinition = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'blockQuote' ) && childDefinition && childDefinition.name == 'heading1' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkChild()'s return value.\n *\t\t\t\tevt.return = false;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * Allowing elements in specific contexts will be a far less common use case, because it's normally handled by\n * `allowIn` rule from {@link module:engine/model/schema~SchemaItemDefinition} but if you have a complex scenario\n * where `listItem` should be allowed only in element `foo` which must be in element `bar`, then this would be the way:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst childDefinition = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'bar foo' ) && childDefinition.name == 'listItem' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkChild()'s return value.\n *\t\t\t\tevt.return = true;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * @event checkChild\n * @param {Array} args The `checkChild()`'s arguments.\n */\n\n/**\n * Event fired when the {@link #checkAttribute} method is called. It allows plugging in\n * additional behavior – e.g. implementing rules which cannot be defined using the declarative\n * {@link module:engine/model/schema~SchemaItemDefinition} interface.\n *\n * **Note:** The {@link #addAttributeCheck} method is a more handy way to register callbacks. Internally,\n * it registers a listener to this event but comes with a simpler API and it is the recommended choice\n * in most of the cases.\n *\n * The {@link #checkAttribute} method fires an event because it's\n * {@link module:utils/observablemixin~ObservableMixin#decorate decorated} with it. Thanks to that you can\n * use this event in a various way, but the most important use case is overriding standard behaviour of the\n * `checkAttribute()` method. Let's see a typical listener template:\n *\n *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst attributeName = args[ 1 ];\n *\t\t}, { priority: 'high' } );\n *\n * The listener is added with a `high` priority to be executed before the default method is really called. The `args` callback\n * parameter contains arguments passed to `checkAttribute( context, attributeName )`. However, the `context` parameter is already\n * normalized to a {@link module:engine/model/schema~SchemaContext} instance, so you don't have to worry about\n * the various ways how `context` may be passed to `checkAttribute()`.\n *\n * So, in order to implement a rule \"disallow `bold` in a text which is in a `heading1` you can add such a listener:\n *\n *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst atributeName = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkAttribute()'s return value.\n *\t\t\t\tevt.return = false;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * Allowing attributes in specific contexts will be a far less common use case, because it's normally handled by\n * `allowAttributes` rule from {@link module:engine/model/schema~SchemaItemDefinition} but if you have a complex scenario\n * where `bold` should be allowed only in element `foo` which must be in element `bar`, then this would be the way:\n *\n *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst atributeName = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'bar foo $text' ) && attributeName == 'bold' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkAttribute()'s return value.\n *\t\t\t\tevt.return = true;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * @event checkAttribute\n * @param {Array} args The `checkAttribute()`'s arguments.\n */\n\n/**\n * A definition of a {@link module:engine/model/schema~Schema schema} item.\n *\n * You can define the following rules:\n *\n * * `allowIn` – A string or an array of strings. Defines in which other items this item will be allowed.\n * * `allowAttributes` – A string or an array of strings. Defines allowed attributes of the given item.\n * * `allowContentOf` – A string or an array of strings. Inherits \"allowed children\" from other items.\n * * `allowWhere` – A string or an array of strings. Inherits \"allowed in\" from other items.\n * * `allowAttributesOf` – A string or an array of strings. Inherits attributes from other items.\n * * `inheritTypesFrom` – A string or an array of strings. Inherits `is*` properties of other items.\n * * `inheritAllFrom` – A string. A shorthand for `allowContentOf`, `allowWhere`, `allowAttributesOf`, `inheritTypesFrom`.\n * * Additionally, you can define the following `is*` properties: `isBlock`, `isLimit`, `isObject`, `isInline`. Read about them below.\n *\n * # The is* properties\n *\n * There are 3 commonly used `is*` properties. Their role is to assign additional semantics to schema items.\n * You can define more properties but you will also need to implement support for them in the existing editor features.\n *\n * * `isBlock` – Whether this item is paragraph-like. Generally speaking, content is usually made out of blocks\n * like paragraphs, list items, images, headings, etc. All these elements are marked as blocks. A block\n * should not allow another block inside. Note: There is also the `$block` generic item which has `isBlock` set to `true`.\n * Most block type items will inherit from `$block` (through `inheritAllFrom`).\n * * `isLimit` – It can be understood as whether this element should not be split by <kbd>Enter</kbd>.\n * Examples of limit elements: `$root`, table cell, image caption, etc. In other words, all actions that happen inside\n * a limit element are limited to its content. **Note:** All objects (`isObject`) are treated as limit elements, too.\n * * `isObject` – Whether an item is \"self-contained\" and should be treated as a whole. Examples of object elements:\n * `image`, `table`, `video`, etc. **Note:** An object is also a limit, so\n * {@link module:engine/model/schema~Schema#isLimit `isLimit()`} returns `true` for object elements automatically.\n * * `isInline` – Whether an item is \"text-like\" and should be treated as an inline node. Examples of inline elements:\n * `$text`, `softBreak` (`<br>`), etc.\n *\n * # Generic items\n *\n * There are three basic generic items: `$root`, `$block` and `$text`.\n * They are defined as follows:\n *\n *\t\tthis.schema.register( '$root', {\n *\t\t\tisLimit: true\n *\t\t} );\n *\t\tthis.schema.register( '$block', {\n *\t\t\tallowIn: '$root',\n *\t\t\tisBlock: true\n *\t\t} );\n *\t\tthis.schema.register( '$text', {\n *\t\t\tallowIn: '$block',\n *\t\t\tisInline: true\n *\t\t} );\n *\n * They reflect typical editor content that is contained within one root, consists of several blocks\n * (paragraphs, lists items, headings, images) which, in turn, may contain text inside.\n *\n * By inheriting from the generic items you can define new items which will get extended by other editor features.\n * Read more about generic types in the {@glink framework/guides/deep-dive/schema Defining schema} guide.\n *\n * # Example definitions\n *\n * Allow `paragraph` in roots and block quotes:\n *\n *\t\tschema.register( 'paragraph', {\n *\t\t\tallowIn: [ '$root', 'blockQuote' ],\n *\t\t\tisBlock: true\n *\t\t} );\n *\n * Allow `paragraph` everywhere where `$block` is allowed (i.e. in `$root`):\n *\n *\t\tschema.register( 'paragraph', {\n *\t\t\tallowWhere: '$block',\n *\t\t\tisBlock: true\n *\t\t} );\n *\n * Make `image` a block object, which is allowed everywhere where `$block` is.\n * Also, allow `src` and `alt` attributes in it:\n *\n *\t\tschema.register( 'image', {\n *\t\t\tallowWhere: '$block',\n *\t\t\tallowAttributes: [ 'src', 'alt' ],\n *\t\t\tisBlock: true,\n *\t\t\tisObject: true\n *\t\t} );\n *\n * Make `caption` allowed in `image` and make it allow all the content of `$block`s (usually, `$text`).\n * Also, mark it as a limit element so it cannot be split:\n *\n *\t\tschema.register( 'caption', {\n *\t\t\tallowIn: 'image',\n *\t\t\tallowContentOf: '$block',\n *\t\t\tisLimit: true\n *\t\t} );\n *\n * Make `listItem` inherit all from `$block` but also allow additional attributes:\n *\n *\t\tschema.register( 'listItem', {\n *\t\t\tinheritAllFrom: '$block',\n *\t\t\tallowAttributes: [ 'listType', 'listIndent' ]\n *\t\t} );\n *\n * Which translates to:\n *\n *\t\tschema.register( 'listItem', {\n *\t\t\tallowWhere: '$block',\n *\t\t\tallowContentOf: '$block',\n *\t\t\tallowAttributesOf: '$block',\n *\t\t\tinheritTypesFrom: '$block',\n *\t\t\tallowAttributes: [ 'listType', 'listIndent' ]\n *\t\t} );\n *\n * # Tips\n *\n * * Check schema definitions of existing features to see how they are defined.\n * * If you want to publish your feature so other developers can use it, try to use\n * generic items as much as possible.\n * * Keep your model clean. Limit it to the actual data and store information in a normalized way.\n * * Remember about definining the `is*` properties. They do not affect the allowed structures, but they can\n * affect how the editor features treat your elements.\n *\n * @typedef {Object} module:engine/model/schema~SchemaItemDefinition\n */\n\n/**\n * A simplified version of {@link module:engine/model/schema~SchemaItemDefinition} after\n * compilation by the {@link module:engine/model/schema~Schema schema}.\n * Rules fed to the schema by {@link module:engine/model/schema~Schema#register}\n * and {@link module:engine/model/schema~Schema#extend} methods are defined in the\n * {@link module:engine/model/schema~SchemaItemDefinition} format.\n * Later on, they are compiled to `SchemaCompiledItemDefition` so when you use e.g.\n * the {@link module:engine/model/schema~Schema#getDefinition} method you get the compiled version.\n *\n * The compiled version contains only the following properties:\n *\n * * The `name` property,\n * * The `is*` properties,\n * * The `allowIn` array,\n * * The `allowAttributes` array.\n *\n * @typedef {Object} module:engine/model/schema~SchemaCompiledItemDefinition\n */\n\n/**\n * A schema context — a list of ancestors of a given position in the document.\n *\n * Considering such position:\n *\n *\t\t<$root>\n *\t\t\t<blockQuote>\n *\t\t\t\t<paragraph>\n *\t\t\t\t\t^\n *\t\t\t\t</paragraph>\n *\t\t\t</blockQuote>\n *\t\t</$root>\n *\n * The context of this position is its {@link module:engine/model/position~Position#getAncestors lists of ancestors}:\n *\n *\t\t[ rootElement, blockQuoteElement, paragraphElement ]\n *\n * Contexts are used in the {@link module:engine/model/schema~Schema#event:checkChild `Schema#checkChild`} and\n * {@link module:engine/model/schema~Schema#event:checkAttribute `Schema#checkAttribute`} events as a definition\n * of a place in the document where the check occurs. The context instances are created based on the first arguments\n * of the {@link module:engine/model/schema~Schema#checkChild `Schema#checkChild()`} and\n * {@link module:engine/model/schema~Schema#checkAttribute `Schema#checkAttribute()`} methods so when\n * using these methods you need to use {@link module:engine/model/schema~SchemaContextDefinition}s.\n */\nexport class SchemaContext {\n\t/**\n\t * Creates an instance of the context.\n\t *\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context\n\t */\n\tconstructor( context ) {\n\t\tif ( context instanceof SchemaContext ) {\n\t\t\treturn context;\n\t\t}\n\n\t\tif ( typeof context == 'string' ) {\n\t\t\tcontext = [ context ];\n\t\t} else if ( !Array.isArray( context ) ) {\n\t\t\t// `context` is item or position.\n\t\t\t// Position#getAncestors() doesn't accept any parameters but it works just fine here.\n\t\t\tcontext = context.getAncestors( { includeSelf: true } );\n\t\t}\n\n\t\tif ( context[ 0 ] && typeof context[ 0 ] != 'string' && context[ 0 ].is( 'documentFragment' ) ) {\n\t\t\tcontext.shift();\n\t\t}\n\n\t\tthis._items = context.map( mapContextItem );\n\t}\n\n\t/**\n\t * The number of items.\n\t *\n\t * @type {Number}\n\t */\n\tget length() {\n\t\treturn this._items.length;\n\t}\n\n\t/**\n\t * The last item (the lowest node).\n\t *\n\t * @type {module:engine/model/schema~SchemaContextItem}\n\t */\n\tget last() {\n\t\treturn this._items[ this._items.length - 1 ];\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all context items.\n\t *\n\t * @returns {Iterable.<module:engine/model/schema~SchemaContextItem>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._items[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns a new schema context instance with an additional item.\n\t *\n\t * Item can be added as:\n\t *\n\t * \t\tconst context = new SchemaContext( [ '$root' ] );\n\t *\n\t * \t\t// An element.\n\t * \t\tconst fooElement = writer.createElement( 'fooElement' );\n\t * \t\tconst newContext = context.push( fooElement ); // [ '$root', 'fooElement' ]\n\t *\n\t * \t\t// A text node.\n\t * \t\tconst text = writer.createText( 'foobar' );\n\t * \t\tconst newContext = context.push( text ); // [ '$root', '$text' ]\n\t *\n\t * \t\t// A string (element name).\n\t * \t\tconst newContext = context.push( 'barElement' ); // [ '$root', 'barElement' ]\n\t *\n\t * **Note** {@link module:engine/model/node~Node} that is already in the model tree will be added as the only item\n\t * (without ancestors).\n\t *\n\t * @param {String|module:engine/model/node~Node|Array<String|module:engine/model/node~Node>} item An item that will be added\n\t * to the current context.\n\t * @returns {module:engine/model/schema~SchemaContext} A new schema context instance with an additional item.\n\t */\n\tpush( item ) {\n\t\tconst ctx = new SchemaContext( [ item ] );\n\n\t\tctx._items = [ ...this._items, ...ctx._items ];\n\n\t\treturn ctx;\n\t}\n\n\t/**\n\t * Gets an item on the given index.\n\t *\n\t * @returns {module:engine/model/schema~SchemaContextItem}\n\t */\n\tgetItem( index ) {\n\t\treturn this._items[ index ];\n\t}\n\n\t/**\n\t * Returns the names of items.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\t* getNames() {\n\t\tyield* this._items.map( item => item.name );\n\t}\n\n\t/**\n\t * Checks whether the context ends with the given nodes.\n\t *\n\t *\t\tconst ctx = new SchemaContext( [ rootElement, paragraphElement, textNode ] );\n\t *\n\t *\t\tctx.endsWith( '$text' ); // -> true\n\t *\t\tctx.endsWith( 'paragraph $text' ); // -> true\n\t *\t\tctx.endsWith( '$root' ); // -> false\n\t *\t\tctx.endsWith( 'paragraph' ); // -> false\n\t *\n\t * @param {String} query\n\t * @returns {Boolean}\n\t */\n\tendsWith( query ) {\n\t\treturn Array.from( this.getNames() ).join( ' ' ).endsWith( query );\n\t}\n\n\t/**\n\t * Checks whether the context starts with the given nodes.\n\t *\n\t *\t\tconst ctx = new SchemaContext( [ rootElement, paragraphElement, textNode ] );\n\t *\n\t *\t\tctx.endsWith( '$root' ); // -> true\n\t *\t\tctx.endsWith( '$root paragraph' ); // -> true\n\t *\t\tctx.endsWith( '$text' ); // -> false\n\t *\t\tctx.endsWith( 'paragraph' ); // -> false\n\t *\n\t * @param {String} query\n\t * @returns {Boolean}\n\t */\n\tstartsWith( query ) {\n\t\treturn Array.from( this.getNames() ).join( ' ' ).startsWith( query );\n\t}\n}\n\n/**\n * The definition of a {@link module:engine/model/schema~SchemaContext schema context}.\n *\n * Contexts can be created in multiple ways:\n *\n * * By defining a **node** – in this cases this node and all its ancestors will be used.\n * * By defining a **position** in the document – in this case all its ancestors will be used.\n * * By defining an **array of nodes** – in this case this array defines the entire context.\n * * By defining a **name of node** - in this case node will be \"mocked\". It is not recommended because context\n * will be unrealistic (e.g. attributes of these nodes are not specified). However, at times this may be the only\n * way to define the context (e.g. when checking some hypothetical situation).\n * * By defining an **array of node names** (potentially, mixed with real nodes) – The same as **name of node**\n * but it is possible to create a path.\n * * By defining a {@link module:engine/model/schema~SchemaContext} instance - in this case the same instance as provided\n * will be return.\n *\n * Examples of context definitions passed to the {@link module:engine/model/schema~Schema#checkChild `Schema#checkChild()`}\n * method:\n *\n *\t\t// Assuming that we have a $root > blockQuote > paragraph structure, the following code\n *\t\t// will check node 'foo' in the following context:\n *\t\t// [ rootElement, blockQuoteElement, paragraphElement ]\n *\t\tconst contextDefinition = paragraphElement;\n * \t\tconst childToCheck = 'foo';\n *\t\tschema.checkChild( contextDefinition, childToCheck );\n *\n *\t\t// Also check in [ rootElement, blockQuoteElement, paragraphElement ].\n *\t\tschema.checkChild( model.createPositionAt( paragraphElement, 0 ), 'foo' );\n *\n *\t\t// Check in [ rootElement, paragraphElement ].\n *\t\tschema.checkChild( [ rootElement, paragraphElement ], 'foo' );\n *\n *\t\t// Check only fakeParagraphElement.\n *\t\tschema.checkChild( 'paragraph', 'foo' );\n *\n *\t\t// Check in [ fakeRootElement, fakeBarElement, paragraphElement ].\n *\t\tschema.checkChild( [ '$root', 'bar', paragraphElement ], 'foo' );\n *\n * All these `checkChild()` calls will fire {@link module:engine/model/schema~Schema#event:checkChild `Schema#checkChild`}\n * events in which `args[ 0 ]` is an instance of the context. Therefore, you can write a listener like this:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst ctx = args[ 0 ];\n *\n *\t\t\tconsole.log( Array.from( ctx.getNames() ) );\n *\t\t} );\n *\n * Which will log the following:\n *\n *\t\t[ '$root', 'blockQuote', 'paragraph' ]\n *\t\t[ '$root', 'paragraph' ]\n *\t\t[ '$root', 'bar', 'paragraph' ]\n *\n * Note: When using the {@link module:engine/model/schema~Schema#checkAttribute `Schema#checkAttribute()`} method\n * you may want to check whether a text node may have an attribute. A {@link module:engine/model/text~Text} is a\n * correct way to define a context so you can do this:\n *\n *\t\tschema.checkAttribute( textNode, 'bold' );\n *\n * But sometimes you want to check whether a text at a given position might've had some attribute,\n * in which case you can create a context by mising an array of elements with a `'$text'` string:\n *\n *\t\t// Check in [ rootElement, paragraphElement, textNode ].\n *\t\tschema.checkChild( [ ...positionInParagraph.getAncestors(), '$text' ], 'bold' );\n *\n * @typedef {module:engine/model/node~Node|module:engine/model/position~Position|module:engine/model/schema~SchemaContext|\n * String|Array.<String|module:engine/model/node~Node>} module:engine/model/schema~SchemaContextDefinition\n */\n\n/**\n * An item of the {@link module:engine/model/schema~SchemaContext schema context}.\n *\n * It contains 3 properties:\n *\n * * `name` – the name of this item,\n * * `* getAttributeKeys()` – a generator of keys of item attributes,\n * * `getAttribute( keyName )` – a method to get attribute values.\n *\n * The context item interface is a highly simplified version of {@link module:engine/model/node~Node} and its role\n * is to expose only the information which schema checks are able to provide (which is the name of the node and\n * node's attributes).\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst ctx = args[ 0 ];\n *\t\t\tconst firstItem = ctx.getItem( 0 );\n *\n *\t\t\tconsole.log( firstItem.name ); // -> '$root'\n *\t\t\tconsole.log( firstItem.getAttribute( 'foo' ) ); // -> 'bar'\n *\t\t\tconsole.log( Array.from( firstItem.getAttributeKeys() ) ); // -> [ 'foo', 'faa' ]\n *\t\t} );\n *\n * @typedef {Object} module:engine/model/schema~SchemaContextItem\n */\n\n/**\n * A structure containing additional metadata describing the attribute.\n *\n * See {@link module:engine/model/schema~Schema#setAttributeProperties `Schema#setAttributeProperties()`} for usage examples.\n *\n * @typedef {Object} module:engine/model/schema~AttributeProperties\n * @property {Boolean} [isFormatting] Indicates that the attribute should be considered as a visual formatting, like `bold`, `italic` or\n * `fontSize` rather than semantic attribute (such as `src`, `listType`, etc.). For example, it is used by the \"Remove format\" feature.\n * @property {Boolean} [copyOnEnter] Indicates that given text attribute should be copied to the next block when enter is pressed.\n */\n\nfunction compileBaseItemRule( sourceItemRules, itemName ) {\n\tconst itemRule = {\n\t\tname: itemName,\n\n\t\tallowIn: [],\n\t\tallowContentOf: [],\n\t\tallowWhere: [],\n\n\t\tallowAttributes: [],\n\t\tallowAttributesOf: [],\n\n\t\tinheritTypesFrom: []\n\t};\n\n\tcopyTypes( sourceItemRules, itemRule );\n\n\tcopyProperty( sourceItemRules, itemRule, 'allowIn' );\n\tcopyProperty( sourceItemRules, itemRule, 'allowContentOf' );\n\tcopyProperty( sourceItemRules, itemRule, 'allowWhere' );\n\n\tcopyProperty( sourceItemRules, itemRule, 'allowAttributes' );\n\tcopyProperty( sourceItemRules, itemRule, 'allowAttributesOf' );\n\n\tcopyProperty( sourceItemRules, itemRule, 'inheritTypesFrom' );\n\n\tmakeInheritAllWork( sourceItemRules, itemRule );\n\n\treturn itemRule;\n}\n\nfunction compileAllowContentOf( compiledDefinitions, itemName ) {\n\tfor ( const allowContentOfItemName of compiledDefinitions[ itemName ].allowContentOf ) {\n\t\t// The allowContentOf property may point to an unregistered element.\n\t\tif ( compiledDefinitions[ allowContentOfItemName ] ) {\n\t\t\tconst allowedChildren = getAllowedChildren( compiledDefinitions, allowContentOfItemName );\n\n\t\t\tallowedChildren.forEach( allowedItem => {\n\t\t\t\tallowedItem.allowIn.push( itemName );\n\t\t\t} );\n\t\t}\n\t}\n\n\tdelete compiledDefinitions[ itemName ].allowContentOf;\n}\n\nfunction compileAllowWhere( compiledDefinitions, itemName ) {\n\tfor ( const allowWhereItemName of compiledDefinitions[ itemName ].allowWhere ) {\n\t\tconst inheritFrom = compiledDefinitions[ allowWhereItemName ];\n\n\t\t// The allowWhere property may point to an unregistered element.\n\t\tif ( inheritFrom ) {\n\t\t\tconst allowedIn = inheritFrom.allowIn;\n\n\t\t\tcompiledDefinitions[ itemName ].allowIn.push( ...allowedIn );\n\t\t}\n\t}\n\n\tdelete compiledDefinitions[ itemName ].allowWhere;\n}\n\nfunction compileAllowAttributesOf( compiledDefinitions, itemName ) {\n\tfor ( const allowAttributeOfItem of compiledDefinitions[ itemName ].allowAttributesOf ) {\n\t\tconst inheritFrom = compiledDefinitions[ allowAttributeOfItem ];\n\n\t\tif ( inheritFrom ) {\n\t\t\tconst inheritAttributes = inheritFrom.allowAttributes;\n\n\t\t\tcompiledDefinitions[ itemName ].allowAttributes.push( ...inheritAttributes );\n\t\t}\n\t}\n\n\tdelete compiledDefinitions[ itemName ].allowAttributesOf;\n}\n\nfunction compileInheritPropertiesFrom( compiledDefinitions, itemName ) {\n\tconst item = compiledDefinitions[ itemName ];\n\n\tfor ( const inheritPropertiesOfItem of item.inheritTypesFrom ) {\n\t\tconst inheritFrom = compiledDefinitions[ inheritPropertiesOfItem ];\n\n\t\tif ( inheritFrom ) {\n\t\t\tconst typeNames = Object.keys( inheritFrom ).filter( name => name.startsWith( 'is' ) );\n\n\t\t\tfor ( const name of typeNames ) {\n\t\t\t\tif ( !( name in item ) ) {\n\t\t\t\t\titem[ name ] = inheritFrom[ name ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdelete item.inheritTypesFrom;\n}\n\n// Remove items which weren't registered (because it may break some checks or we'd need to complicate them).\n// Make sure allowIn doesn't contain repeated values.\nfunction cleanUpAllowIn( compiledDefinitions, itemName ) {\n\tconst itemRule = compiledDefinitions[ itemName ];\n\tconst existingItems = itemRule.allowIn.filter( itemToCheck => compiledDefinitions[ itemToCheck ] );\n\n\titemRule.allowIn = Array.from( new Set( existingItems ) );\n}\n\nfunction cleanUpAllowAttributes( compiledDefinitions, itemName ) {\n\tconst itemRule = compiledDefinitions[ itemName ];\n\n\titemRule.allowAttributes = Array.from( new Set( itemRule.allowAttributes ) );\n}\n\nfunction copyTypes( sourceItemRules, itemRule ) {\n\tfor ( const sourceItemRule of sourceItemRules ) {\n\t\tconst typeNames = Object.keys( sourceItemRule ).filter( name => name.startsWith( 'is' ) );\n\n\t\tfor ( const name of typeNames ) {\n\t\t\titemRule[ name ] = sourceItemRule[ name ];\n\t\t}\n\t}\n}\n\nfunction copyProperty( sourceItemRules, itemRule, propertyName ) {\n\tfor ( const sourceItemRule of sourceItemRules ) {\n\t\tif ( typeof sourceItemRule[ propertyName ] == 'string' ) {\n\t\t\titemRule[ propertyName ].push( sourceItemRule[ propertyName ] );\n\t\t} else if ( Array.isArray( sourceItemRule[ propertyName ] ) ) {\n\t\t\titemRule[ propertyName ].push( ...sourceItemRule[ propertyName ] );\n\t\t}\n\t}\n}\n\nfunction makeInheritAllWork( sourceItemRules, itemRule ) {\n\tfor ( const sourceItemRule of sourceItemRules ) {\n\t\tconst inheritFrom = sourceItemRule.inheritAllFrom;\n\n\t\tif ( inheritFrom ) {\n\t\t\titemRule.allowContentOf.push( inheritFrom );\n\t\t\titemRule.allowWhere.push( inheritFrom );\n\t\t\titemRule.allowAttributesOf.push( inheritFrom );\n\t\t\titemRule.inheritTypesFrom.push( inheritFrom );\n\t\t}\n\t}\n}\n\nfunction getAllowedChildren( compiledDefinitions, itemName ) {\n\tconst itemRule = compiledDefinitions[ itemName ];\n\n\treturn getValues( compiledDefinitions ).filter( def => def.allowIn.includes( itemRule.name ) );\n}\n\nfunction getValues( obj ) {\n\treturn Object.keys( obj ).map( key => obj[ key ] );\n}\n\nfunction mapContextItem( ctxItem ) {\n\tif ( typeof ctxItem == 'string' ) {\n\t\treturn {\n\t\t\tname: ctxItem,\n\n\t\t\t* getAttributeKeys() {},\n\n\t\t\tgetAttribute() {}\n\t\t};\n\t} else {\n\t\treturn {\n\t\t\t// '$text' means text nodes and text proxies.\n\t\t\tname: ctxItem.is( 'element' ) ? ctxItem.name : '$text',\n\n\t\t\t* getAttributeKeys() {\n\t\t\t\tyield* ctxItem.getAttributeKeys();\n\t\t\t},\n\n\t\t\tgetAttribute( key ) {\n\t\t\t\treturn ctxItem.getAttribute( key );\n\t\t\t}\n\t\t};\n\t}\n}\n\n// Generator function returning values from provided walkers, switching between them at each iteration. If only one walker\n// is provided it will return data only from that walker.\n//\n// @param {module:engine/module/treewalker~TreeWalker} [backward] Walker iterating in backward direction.\n// @param {module:engine/module/treewalker~TreeWalker} [forward] Walker iterating in forward direction.\n// @returns {Iterable.<Object>} Object returned at each iteration contains `value` and `walker` (informing which walker returned\n// given value) fields.\nfunction* combineWalkers( backward, forward ) {\n\tlet done = false;\n\n\twhile ( !done ) {\n\t\tdone = true;\n\n\t\tif ( backward ) {\n\t\t\tconst step = backward.next();\n\n\t\t\tif ( !step.done ) {\n\t\t\t\tdone = false;\n\t\t\t\tyield {\n\t\t\t\t\twalker: backward,\n\t\t\t\t\tvalue: step.value\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( forward ) {\n\t\t\tconst step = forward.next();\n\n\t\t\tif ( !step.done ) {\n\t\t\t\tdone = false;\n\t\t\t\tyield {\n\t\t\t\t\twalker: forward,\n\t\t\t\t\tvalue: step.value\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Takes an array of non-intersecting ranges. For each of them gets minimal flat ranges covering that range and returns\n// all those minimal flat ranges.\n//\n// @param {Array.<module:engine/model/range~Range>} ranges Ranges to process.\n// @returns {Iterable.<module:engine/model/range~Range>} Minimal flat ranges of given `ranges`.\nfunction* convertToMinimalFlatRanges( ranges ) {\n\tfor ( const range of ranges ) {\n\t\tyield* range.getMinimalFlatRanges();\n\t}\n}\n\nfunction removeDisallowedAttributeFromNode( schema, node, writer ) {\n\tfor ( const attribute of node.getAttributeKeys() ) {\n\t\tif ( !schema.checkAttribute( node, attribute ) ) {\n\t\t\twriter.removeAttribute( attribute, node );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/conversion/upcastdispatcher\n */\n\nimport ViewConsumable from './viewconsumable';\nimport ModelRange from '../model/range';\nimport ModelPosition from '../model/position';\nimport { SchemaContext } from '../model/schema';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * `UpcastDispatcher` is a central point of {@link module:engine/view/view view} conversion, which is a process of\n * converting given {@link module:engine/view/documentfragment~DocumentFragment view document fragment} or\n * {@link module:engine/view/element~Element} into another structure.\n * In default application, {@link module:engine/view/view view} is converted to {@link module:engine/model/model}.\n *\n * During conversion process, for all {@link module:engine/view/node~Node view nodes} from the converted view document fragment,\n * `UpcastDispatcher` fires corresponding events. Special callbacks called \"converters\" should listen to\n * `UpcastDispatcher` for those events.\n *\n * Each callback, as the second argument, is passed a special object `data` that has `viewItem`, `modelCursor` and\n * `modelRange` properties. `viewItem` property contains {@link module:engine/view/node~Node view node} or\n * {@link module:engine/view/documentfragment~DocumentFragment view document fragment}\n * that is converted at the moment and might be handled by the callback. `modelRange` property should be used to save the result\n * of conversion and is always a {@link module:engine/model/range~Range} when conversion result is correct.\n * `modelCursor` property is a {@link module:engine/model/position~Position position} on which conversion result will be inserted\n * and is a context according to {@link module:engine/model/schema~Schema schema} will be checked before the conversion.\n * See also {@link ~UpcastDispatcher#convert}. It is also shared by reference by all callbacks listening to given event.\n *\n * The third parameter passed to a callback is an instance of {@link ~UpcastDispatcher}\n * which provides additional tools for converters.\n *\n * Examples of providing callbacks for `UpcastDispatcher`:\n *\n *\t\t// Converter for links (<a>).\n *\t\teditor.data.upcastDispatcher.on( 'element:a', ( evt, data, conversionApi ) => {\n *\t\t\tif ( conversionApi.consumable.consume( data.viewItem, { name: true, attributes: [ 'href' ] } ) ) {\n *\t\t\t\t// <a> element is inline and is represented by an attribute in the model.\n *\t\t\t\t// This is why we need to convert only children.\n *\t\t\t\tconst { modelRange } = conversionApi.convertChildren( data.viewItem, data.modelCursor );\n *\n *\t\t\t\tfor ( let item of modelRange.getItems() ) {\n *\t\t\t\t\tif ( conversionApi.schema.checkAttribute( item, 'linkHref' ) ) {\n *\t\t\t\t\t\tconversionApi.writer.setAttribute( 'linkHref', data.viewItem.getAttribute( 'href' ), item );\n *\t\t\t\t\t}\n *\t\t\t\t}\n *\t\t\t}\n *\t\t} );\n *\n *\t\t// Convert <p>'s font-size style.\n *\t\t// Note: You should use a low-priority observer in order to ensure that\n *\t\t// it's executed after the element-to-element converter.\n *\t\teditor.data.upcastDispatcher.on( 'element:p', ( evt, data, conversionApi ) => {\n *\t\t\tconst { consumable, schema, writer } = conversionApi;\n *\n *\t\t\tif ( !consumable.consume( data.viewItem, { style: 'font-size' } ) ) {\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\tconst fontSize = data.viewItem.getStyle( 'font-size' );\n *\n *\t\t\t// Don't go for the model element after data.modelCursor because it might happen\n *\t\t\t// that a single view element was converted to multiple model elements. Get all of them.\n *\t\t\tfor ( const item of data.modelRange.getItems( { shallow: true } ) ) {\n *\t\t\t\tif ( schema.checkAttribute( item, 'fontSize' ) ) {\n *\t\t\t\t\twriter.setAttribute( 'fontSize', fontSize, item );\n *\t\t\t\t}\n *\t\t\t}\n *\t\t}, { priority: 'low' } );\n *\n *\t\t// Convert all elements which have no custom converter into paragraph (autoparagraphing).\n * \teditor.data.upcastDispatcher.on( 'element', ( evt, data, conversionApi ) => {\n * \t \t// When element is already consumed by higher priority converters then do nothing.\n * \t \tif ( conversionApi.consumable.test( data.viewItem, { name: data.viewItem.name } ) ) {\n * \t \t\t\tconst paragraph = conversionApi.writer.createElement( 'paragraph' );\n *\n * \t \t\t\t// Find allowed parent for paragraph that we are going to insert. If current parent does not allow\n * \t \t\t\t// to insert paragraph but one of the ancestors does then split nodes to allowed parent.\n * \t \t\t\tconst splitResult = conversionApi.splitToAllowedParent( paragraph, data.modelCursor );\n *\n * \t \t\t\t// When there is no split result it means that we can't insert paragraph in this position.\n * \t \t\t\tif ( splitResult ) {\n * \t \t\t\t\t// Insert paragraph in allowed position.\n * \t \t\t\t\tconversionApi.writer.insert( paragraph, splitResult.position );\n *\n * \t \t\t\t\t// Convert children to paragraph.\n * \t \t\t\t\tconst { modelRange } = conversionApi.convertChildren(\n * \t \t\t\t\t\tdata.viewItem,\n * \t \t\t\t\t\tconversionApi.writer.createPositionAt( paragraph, 0 )\n * \t \t\t\t\t);\n *\n * \t\t\t\t\t\t// Set as conversion result, attribute converters may use this property.\n * \t \t\t\t\tdata.modelRange = conversionApi.writer.createRange(\n * \t \t\t\t\t\tconversionApi.writer.createPositionBefore( paragraph ),\n * \t \t\t\t\t\tmodelRange.end\n * \t \t\t\t\t);\n *\n * \t \t\t\t\t// Continue conversion inside paragraph.\n * \t \t\t\t\tdata.modelCursor = data.modelRange.end;\n * \t \t\t\t}\n * \t \t\t}\n * \t \t}\n * \t }, { priority: 'low' } );\n *\n * Before each conversion process, `UpcastDispatcher` fires {@link ~UpcastDispatcher#event:viewCleanup}\n * event which can be used to prepare tree view for conversion.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n * @fires viewCleanup\n * @fires element\n * @fires text\n * @fires documentFragment\n */\nexport default class UpcastDispatcher {\n\t/**\n\t * Creates a `UpcastDispatcher` that operates using passed API.\n\t *\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi\n\t * @param {Object} [conversionApi] Additional properties for interface that will be passed to events fired\n\t * by `UpcastDispatcher`.\n\t */\n\tconstructor( conversionApi = {} ) {\n\t\t/**\n\t\t * List of the elements that were created during splitting.\n\t\t *\n\t\t * After conversion process the list is cleared.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<module:engine/model/element~Element,Array.<module:engine/model/element~Element>>}\n\t\t */\n\t\tthis._splitParts = new Map();\n\n\t\t/**\n\t\t * Position in the temporary structure where the converted content is inserted. The structure reflect the context of\n\t\t * the target position where the content will be inserted. This property is build based on the context parameter of the\n\t\t * convert method.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/position~Position|null}\n\t\t */\n\t\tthis._modelCursor = null;\n\n\t\t/**\n\t\t * Interface passed by dispatcher to the events callbacks.\n\t\t *\n\t\t * @member {module:engine/conversion/upcastdispatcher~UpcastConversionApi}\n\t\t */\n\t\tthis.conversionApi = Object.assign( {}, conversionApi );\n\n\t\t// `convertItem`, `convertChildren` and `splitToAllowedParent` are bound to this `UpcastDispatcher`\n\t\t// instance and set on `conversionApi`. This way only a part of `UpcastDispatcher` API is exposed.\n\t\tthis.conversionApi.convertItem = this._convertItem.bind( this );\n\t\tthis.conversionApi.convertChildren = this._convertChildren.bind( this );\n\t\tthis.conversionApi.splitToAllowedParent = this._splitToAllowedParent.bind( this );\n\t\tthis.conversionApi.getSplitParts = this._getSplitParts.bind( this );\n\t}\n\n\t/**\n\t * Starts the conversion process. The entry point for the conversion.\n\t *\n\t * @fires element\n\t * @fires text\n\t * @fires documentFragment\n\t * @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/element~Element} viewItem\n\t * Part of the view to be converted.\n\t * @param {module:engine/model/writer~Writer} writer Instance of model writer.\n\t * @param {module:engine/model/schema~SchemaContextDefinition} [context=['$root']] Elements will be converted according to this context.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Model data that is a result of the conversion process\n\t * wrapped in `DocumentFragment`. Converted marker elements will be set as that document fragment's\n\t * {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.\n\t */\n\tconvert( viewItem, writer, context = [ '$root' ] ) {\n\t\tthis.fire( 'viewCleanup', viewItem );\n\n\t\t// Create context tree and set position in the top element.\n\t\t// Items will be converted according to this position.\n\t\tthis._modelCursor = createContextTree( context, writer );\n\n\t\t// Store writer in conversion as a conversion API\n\t\t// to be sure that conversion process will use the same batch.\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create consumable values list for conversion process.\n\t\tthis.conversionApi.consumable = ViewConsumable.createFrom( viewItem );\n\n\t\t// Custom data stored by converter for conversion process.\n\t\tthis.conversionApi.store = {};\n\n\t\t// Do the conversion.\n\t\tconst { modelRange } = this._convertItem( viewItem, this._modelCursor );\n\n\t\t// Conversion result is always a document fragment so let's create it.\n\t\tconst documentFragment = writer.createDocumentFragment();\n\n\t\t// When there is a conversion result.\n\t\tif ( modelRange ) {\n\t\t\t// Remove all empty elements that were create while splitting.\n\t\t\tthis._removeEmptyElements();\n\n\t\t\t// Move all items that were converted in context tree to the document fragment.\n\t\t\tfor ( const item of Array.from( this._modelCursor.parent.getChildren() ) ) {\n\t\t\t\twriter.append( item, documentFragment );\n\t\t\t}\n\n\t\t\t// Extract temporary markers elements from model and set as static markers collection.\n\t\t\tdocumentFragment.markers = extractMarkersFromModelFragment( documentFragment, writer );\n\t\t}\n\n\t\t// Clear context position.\n\t\tthis._modelCursor = null;\n\n\t\t// Clear split elements lists.\n\t\tthis._splitParts.clear();\n\n\t\t// Clear conversion API.\n\t\tthis.conversionApi.writer = null;\n\t\tthis.conversionApi.store = null;\n\n\t\t// Return fragment as conversion result.\n\t\treturn documentFragment;\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#convertItem\n\t */\n\t_convertItem( viewItem, modelCursor ) {\n\t\tconst data = Object.assign( { viewItem, modelCursor, modelRange: null } );\n\n\t\tif ( viewItem.is( 'element' ) ) {\n\t\t\tthis.fire( 'element:' + viewItem.name, data, this.conversionApi );\n\t\t} else if ( viewItem.is( 'text' ) ) {\n\t\t\tthis.fire( 'text', data, this.conversionApi );\n\t\t} else {\n\t\t\tthis.fire( 'documentFragment', data, this.conversionApi );\n\t\t}\n\n\t\t// Handle incorrect conversion result.\n\t\tif ( data.modelRange && !( data.modelRange instanceof ModelRange ) ) {\n\t\t\t/**\n\t\t\t * Incorrect conversion result was dropped.\n\t\t\t *\n\t\t\t * {@link module:engine/model/range~Range Model range} should be a conversion result.\n\t\t\t *\n\t\t\t * @error view-conversion-dispatcher-incorrect-result\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-conversion-dispatcher-incorrect-result: Incorrect conversion result was dropped.', this );\n\t\t}\n\n\t\treturn { modelRange: data.modelRange, modelCursor: data.modelCursor };\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#convertChildren\n\t */\n\t_convertChildren( viewItem, modelCursor ) {\n\t\tconst modelRange = new ModelRange( modelCursor );\n\t\tlet nextModelCursor = modelCursor;\n\n\t\tfor ( const viewChild of Array.from( viewItem.getChildren() ) ) {\n\t\t\tconst result = this._convertItem( viewChild, nextModelCursor );\n\n\t\t\tif ( result.modelRange instanceof ModelRange ) {\n\t\t\t\tmodelRange.end = result.modelRange.end;\n\t\t\t\tnextModelCursor = result.modelCursor;\n\t\t\t}\n\t\t}\n\n\t\treturn { modelRange, modelCursor: nextModelCursor };\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#splitToAllowedParent\n\t */\n\t_splitToAllowedParent( node, modelCursor ) {\n\t\t// Try to find allowed parent.\n\t\tconst allowedParent = this.conversionApi.schema.findAllowedParent( modelCursor, node );\n\n\t\t// When there is no parent that allows to insert node then return `null`.\n\t\tif ( !allowedParent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// When current position parent allows to insert node then return this position.\n\t\tif ( allowedParent === modelCursor.parent ) {\n\t\t\treturn { position: modelCursor };\n\t\t}\n\n\t\t// When allowed parent is in context tree.\n\t\tif ( this._modelCursor.parent.getAncestors().includes( allowedParent ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Split element to allowed parent.\n\t\tconst splitResult = this.conversionApi.writer.split( modelCursor, allowedParent );\n\n\t\t// Using the range returned by `model.Writer#split`, we will pair original elements with their split parts.\n\t\t//\n\t\t// The range returned from the writer spans \"over the split\" or, precisely saying, from the end of the original element (the one\n\t\t// that got split) to the beginning of the other part of that element:\n\t\t//\n\t\t// <limit><a><b><c>X[]Y</c></b><a></limit> ->\n\t\t// <limit><a><b><c>X[</c></b></a><a><b><c>]Y</c></b></a>\n\t\t//\n\t\t// After the split there cannot be any full node between the positions in `splitRange`. The positions are touching.\n\t\t// Also, because of how splitting works, it is easy to notice, that \"closing tags\" are in the reverse order than \"opening tags\".\n\t\t// Also, since we split all those elements, each of them has to have the other part.\n\t\t//\n\t\t// With those observations in mind, we will pair the original elements with their split parts by saving \"closing tags\" and matching\n\t\t// them with \"opening tags\" in the reverse order. For that we can use a stack.\n\t\tconst stack = [];\n\n\t\tfor ( const treeWalkerValue of splitResult.range.getWalker() ) {\n\t\t\tif ( treeWalkerValue.type == 'elementEnd' ) {\n\t\t\t\tstack.push( treeWalkerValue.item );\n\t\t\t} else {\n\t\t\t\t// There should not be any text nodes after the element is split, so the only other value is `elementStart`.\n\t\t\t\tconst originalPart = stack.pop();\n\t\t\t\tconst splitPart = treeWalkerValue.item;\n\n\t\t\t\tthis._registerSplitPair( originalPart, splitPart );\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tposition: splitResult.position,\n\t\t\tcursorParent: splitResult.range.end.parent\n\t\t};\n\t}\n\n\t/**\n\t * Registers that `splitPart` element is a split part of the `originalPart` element.\n\t *\n\t * Data set by this method is used by {@link #_getSplitParts} and {@link #_removeEmptyElements}.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} originalPart\n\t * @param {module:engine/model/element~Element} splitPart\n\t */\n\t_registerSplitPair( originalPart, splitPart ) {\n\t\tif ( !this._splitParts.has( originalPart ) ) {\n\t\t\tthis._splitParts.set( originalPart, [ originalPart ] );\n\t\t}\n\n\t\tconst list = this._splitParts.get( originalPart );\n\n\t\tthis._splitParts.set( splitPart, list );\n\t\tlist.push( splitPart );\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#getSplitParts\n\t */\n\t_getSplitParts( element ) {\n\t\tlet parts;\n\n\t\tif ( !this._splitParts.has( element ) ) {\n\t\t\tparts = [ element ];\n\t\t} else {\n\t\t\tparts = this._splitParts.get( element );\n\t\t}\n\n\t\treturn parts;\n\t}\n\n\t/**\n\t * Checks if there are any empty elements created while splitting and removes them.\n\t *\n\t * This method works recursively to re-check empty elements again after at least one element was removed in the initial call,\n\t * as some elements might have become empty after other empty elements were removed from them.\n\t *\n\t * @private\n\t */\n\t_removeEmptyElements() {\n\t\tlet anyRemoved = false;\n\n\t\tfor ( const element of this._splitParts.keys() ) {\n\t\t\tif ( element.isEmpty ) {\n\t\t\t\tthis.conversionApi.writer.remove( element );\n\t\t\t\tthis._splitParts.delete( element );\n\n\t\t\t\tanyRemoved = true;\n\t\t\t}\n\t\t}\n\n\t\tif ( anyRemoved ) {\n\t\t\tthis._removeEmptyElements();\n\t\t}\n\t}\n\n\t/**\n\t * Fired before the first conversion event, at the beginning of upcast (view to model conversion) process.\n\t *\n\t * @event viewCleanup\n\t * @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/element~Element}\n\t * viewItem Part of the view to be converted.\n\t */\n\n\t/**\n\t * Fired when {@link module:engine/view/element~Element} is converted.\n\t *\n\t * `element` is a namespace event for a class of events. Names of actually called events follow this pattern:\n\t * `element:<elementName>` where `elementName` is the name of converted element. This way listeners may listen to\n\t * all elements conversion or to conversion of specific elements.\n\t *\n\t * @event element\n\t * @param {Object} data Conversion data. Keep in mind that this object is shared by reference between all\n\t * callbacks that will be called. This means that callbacks can override values if needed, and those values will\n\t * be available in other callbacks.\n\t * @param {module:engine/view/item~Item} data.viewItem Converted item.\n\t * @param {module:engine/model/position~Position} data.modelCursor Position where a converter should start changes.\n\t * Change this value for the next converter to tell where the conversion should continue.\n\t * @param {module:engine/model/range~Range} data.modelRange The current state of conversion result. Every change to\n\t * converted element should be reflected by setting or modifying this property.\n\t * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion utilities to be used by callback.\n\t */\n\n\t/**\n\t * Fired when {@link module:engine/view/text~Text} is converted.\n\t *\n\t * @event text\n\t * @see #event:element\n\t */\n\n\t/**\n\t * Fired when {@link module:engine/view/documentfragment~DocumentFragment} is converted.\n\t *\n\t * @event documentFragment\n\t * @see #event:element\n\t */\n}\n\nmix( UpcastDispatcher, EmitterMixin );\n\n// Traverses given model item and searches elements which marks marker range. Found element is removed from\n// DocumentFragment but path of this element is stored in a Map which is then returned.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/node~Node} modelItem Fragment of model.\n// @returns {Map<String, module:engine/model/range~Range>} List of static markers.\nfunction extractMarkersFromModelFragment( modelItem, writer ) {\n\tconst markerElements = new Set();\n\tconst markers = new Map();\n\n\t// Create ModelTreeWalker.\n\tconst range = ModelRange._createIn( modelItem ).getItems();\n\n\t// Walk through DocumentFragment and collect marker elements.\n\tfor ( const item of range ) {\n\t\t// Check if current element is a marker.\n\t\tif ( item.name == '$marker' ) {\n\t\t\tmarkerElements.add( item );\n\t\t}\n\t}\n\n\t// Walk through collected marker elements store its path and remove its from the DocumentFragment.\n\tfor ( const markerElement of markerElements ) {\n\t\tconst markerName = markerElement.getAttribute( 'data-name' );\n\t\tconst currentPosition = writer.createPositionBefore( markerElement );\n\n\t\t// When marker of given name is not stored it means that we have found the beginning of the range.\n\t\tif ( !markers.has( markerName ) ) {\n\t\t\tmarkers.set( markerName, new ModelRange( currentPosition.clone() ) );\n\t\t// Otherwise is means that we have found end of the marker range.\n\t\t} else {\n\t\t\tmarkers.get( markerName ).end = currentPosition.clone();\n\t\t}\n\n\t\t// Remove marker element from DocumentFragment.\n\t\twriter.remove( markerElement );\n\t}\n\n\treturn markers;\n}\n\n// Creates model fragment according to given context and returns position in the bottom (the deepest) element.\nfunction createContextTree( contextDefinition, writer ) {\n\tlet position;\n\n\tfor ( const item of new SchemaContext( contextDefinition ) ) {\n\t\tconst attributes = {};\n\n\t\tfor ( const key of item.getAttributeKeys() ) {\n\t\t\tattributes[ key ] = item.getAttribute( key );\n\t\t}\n\n\t\tconst current = writer.createElement( item.name, attributes );\n\n\t\tif ( position ) {\n\t\t\twriter.append( current, position );\n\t\t}\n\n\t\tposition = ModelPosition._createAt( current, 0 );\n\t}\n\n\treturn position;\n}\n\n/**\n * Conversion interface that is registered for given {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher}\n * and is passed as one of parameters when {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher dispatcher}\n * fires it's events.\n *\n * @interface module:engine/conversion/upcastdispatcher~UpcastConversionApi\n */\n\n/**\n * Starts conversion of given item by firing an appropriate event.\n *\n * Every fired event is passed (as first parameter) an object with `modelRange` property. Every event may set and/or\n * modify that property. When all callbacks are done, the final value of `modelRange` property is returned by this method.\n * The `modelRange` must be {@link module:engine/model/range~Range model range} or `null` (as set by default).\n *\n * @method #convertItem\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:text\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:documentFragment\n * @param {module:engine/view/item~Item} viewItem Item to convert.\n * @param {module:engine/model/position~Position} modelCursor Position of conversion.\n * @returns {Object} result Conversion result.\n * @returns {module:engine/model/range~Range|null} result.modelRange Model range containing result of item conversion,\n * created and modified by callbacks attached to fired event, or `null` if the conversion result was incorrect.\n * @returns {module:engine/model/position~Position} result.modelCursor Position where conversion should be continued.\n */\n\n/**\n * Starts conversion of all children of given item by firing appropriate events for all those children.\n *\n * @method #convertChildren\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:text\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:documentFragment\n * @param {module:engine/view/item~Item} viewItem Element which children should be converted.\n * @param {module:engine/model/position~Position} modelCursor Position of conversion.\n * @returns {Object} result Conversion result.\n * @returns {module:engine/model/range~Range} result.modelRange Model range containing results of conversion of all children of given item.\n * When no children was converted then range is collapsed.\n * @returns {module:engine/model/position~Position} result.modelCursor Position where conversion should be continued.\n */\n\n/**\n * Checks {@link module:engine/model/schema~Schema schema} to find allowed parent for element that we are going to insert\n * starting from given position. If current parent does not allow to insert element but one of the ancestors does then\n * split nodes to allowed parent.\n *\n * If schema allows to insert node in given position, nothing is split and object with that position is returned.\n *\n * If it was not possible to find allowed parent, `null` is returned, nothing is split.\n *\n * Otherwise, ancestors are split and object with position and the copy of the split element is returned.\n *\n * For instance, if `<image>` is not allowed in `<paragraph>` but is allowed in `$root`:\n *\n *\t\t<paragraph>foo[]bar</paragraph>\n *\n * \t-> split for `<image>` ->\n *\n * \t<paragraph>foo</paragraph>[]<paragraph>bar</paragraph>\n *\n * In the sample above position between `<paragraph>` elements will be returned as `position` and the second `paragraph`\n * as `cursorParent`.\n *\n * @method #splitToAllowedParent\n * @param {module:engine/model/position~Position} position Position on which element is going to be inserted.\n * @param {module:engine/model/node~Node} node Node to insert.\n * @returns {Object|null} Split result. If it was not possible to find allowed position `null` is returned.\n * @returns {module:engine/model/position~Position} position between split elements.\n * @returns {module:engine/model/element~Element} [cursorParent] Element inside which cursor should be placed to\n * continue conversion. When element is not defined it means that there was no split.\n */\n\n/**\n * Returns all the split parts of given `element` that were created during upcasting through using {@link #splitToAllowedParent}.\n * It enables you to easily track those elements and continue processing them after they are split during their children conversion.\n *\n *\t\t<paragraph>Foo<image />bar<image />baz</paragraph> ->\n *\t\t<paragraph>Foo</paragraph><image /><paragraph>bar</paragraph><image /><paragraph>baz</paragraph>\n *\n * For a reference to any of above paragraphs, the function will return all three paragraphs (the original element included),\n * sorted in the order of their creation (the original element is the first one).\n *\n * If given `element` was not split, an array with single element is returned.\n *\n * Example of a usage in a converter code:\n *\n *\t\tconst myElement = conversionApi.writer.createElement( 'myElement' );\n *\n *\t\t// Children conversion may split `myElement`.\n *\t\tconversionApi.convertChildren( myElement, modelCursor );\n *\n *\t\tconst splitParts = conversionApi.getSplitParts( myElement );\n *\t\tconst lastSplitPart = splitParts[ splitParts.length - 1 ];\n *\n *\t\t// Setting `data.modelRange` basing on split parts:\n *\t\tdata.modelRange = conversionApi.writer.createRange(\n *\t\t\tconversionApi.writer.createPositionBefore( myElement ),\n *\t\t\tconversionApi.writer.createPositionAfter( lastSplitPart )\n *\t\t);\n *\n *\t\t// Setting `data.modelCursor` to continue after the last split element:\n *\t\tdata.modelCursor = conversionApi.writer.createPositionAfter( lastSplitPart );\n *\n * **Tip:** if you are unable to get a reference to the original element (for example because the code is split into multiple converters\n * or even classes) but it was already converted, you might want to check first element in `data.modelRange`. This is a common situation\n * if an attribute converter is separated from an element converter.\n *\n * @method #getSplitParts\n * @param {module:engine/model/element~Element} element\n * @returns {Array.<module:engine/model/element~Element>}\n */\n\n/**\n * Stores information about what parts of processed view item are still waiting to be handled. After a piece of view item\n * was converted, appropriate consumable value should be {@link module:engine/conversion/viewconsumable~ViewConsumable#consume consumed}.\n *\n * @member {module:engine/conversion/viewconsumable~ViewConsumable} #consumable\n */\n\n/**\n * Custom data stored by converters for conversion process. Custom properties of this object can be defined and use to\n * pass parameters between converters.\n *\n * The difference between this property and `data` parameter of\n * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element} is that `data` parameters allows you\n * to pass parameters within a single event and `store` within the whole conversion.\n *\n * @member {Object} #store\n */\n\n/**\n * The model's schema instance.\n *\n * @member {module:engine/model/schema~Schema} #schema\n */\n\n/**\n * The {@link module:engine/model/writer~Writer} instance used to manipulate data during conversion.\n *\n * @member {module:engine/model/writer~Writer} #writer\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/controller/datacontroller\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nimport Mapper from '../conversion/mapper';\n\nimport DowncastDispatcher from '../conversion/downcastdispatcher';\nimport { insertText } from '../conversion/downcasthelpers';\n\nimport UpcastDispatcher from '../conversion/upcastdispatcher';\nimport { convertText, convertToModelFragment } from '../conversion/upcasthelpers';\n\nimport ViewDocumentFragment from '../view/documentfragment';\nimport ViewDocument from '../view/document';\nimport ViewDowncastWriter from '../view/downcastwriter';\n\nimport ModelRange from '../model/range';\n\n/**\n * Controller for the data pipeline. The data pipeline controls how data is retrieved from the document\n * and set inside it. Hence, the controller features two methods which allow to {@link ~DataController#get get}\n * and {@link ~DataController#set set} data of the {@link ~DataController#model model}\n * using given:\n *\n * * {@link module:engine/dataprocessor/dataprocessor~DataProcessor data processor},\n * * downcast converters,\n * * upcast converters.\n *\n * An instance of the data controller is always available in the {@link module:core/editor/editor~Editor#data `editor.data`}\n * property:\n *\n *\t\teditor.data.get( { rootName: 'customRoot' } ); // -> '<p>Hello!</p>'\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class DataController {\n\t/**\n\t * Creates a data controller instance.\n\t *\n\t * @param {module:engine/model/model~Model} model Data model.\n\t * @param {module:engine/dataprocessor/dataprocessor~DataProcessor} [dataProcessor] Data processor that should be used\n\t * by the controller.\n\t */\n\tconstructor( model, dataProcessor ) {\n\t\t/**\n\t\t * Data 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 * Data processor used during the conversion.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/dataprocessor/dataprocessor~DataProcessor}\n\t\t */\n\t\tthis.processor = dataProcessor;\n\n\t\t/**\n\t\t * Mapper used for the conversion. It has no permanent bindings, because they are created when getting data and\n\t\t * cleared directly after the data are converted. However, the mapper is defined as a class property, because\n\t\t * it needs to be passed to the `DowncastDispatcher` as a conversion API.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/mapper~Mapper}\n\t\t */\n\t\tthis.mapper = new Mapper();\n\n\t\t/**\n\t\t * Downcast dispatcher used by the {@link #get get method}. Downcast converters should be attached to it.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/downcastdispatcher~DowncastDispatcher}\n\t\t */\n\t\tthis.downcastDispatcher = new DowncastDispatcher( {\n\t\t\tmapper: this.mapper\n\t\t} );\n\t\tthis.downcastDispatcher.on( 'insert:$text', insertText(), { priority: 'lowest' } );\n\n\t\t/**\n\t\t * Upcast dispatcher used by the {@link #set set method}. Upcast converters should be attached to it.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/upcastdispatcher~UpcastDispatcher}\n\t\t */\n\t\tthis.upcastDispatcher = new UpcastDispatcher( {\n\t\t\tschema: model.schema\n\t\t} );\n\n\t\t// Define default converters for text and elements.\n\t\t//\n\t\t// Note that if there is no default converter for the element it will be skipped, for instance `<b>foo</b>` will be\n\t\t// converted to nothing. We add `convertToModelFragment` as a last converter so it converts children of that\n\t\t// element to the document fragment so `<b>foo</b>` will be converted to `foo` if there is no converter for `<b>`.\n\t\tthis.upcastDispatcher.on( 'text', convertText(), { priority: 'lowest' } );\n\t\tthis.upcastDispatcher.on( 'element', convertToModelFragment(), { priority: 'lowest' } );\n\t\tthis.upcastDispatcher.on( 'documentFragment', convertToModelFragment(), { priority: 'lowest' } );\n\n\t\tthis.decorate( 'init' );\n\n\t\t// Fire `ready` event when initialisation has completed. Such low level listener gives possibility\n\t\t// to plug into initialisation pipeline without interrupting the initialisation flow.\n\t\tthis.on( 'init', () => {\n\t\t\tthis.fire( 'ready' );\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Returns the model's data converted by downcast dispatchers attached to {@link #downcastDispatcher} and\n\t * formatted by the {@link #processor data processor}.\n\t *\n\t * @param {Object} [options]\n\t * @param {String} [options.rootName='main'] Root name.\n\t * @param {String} [options.trim='empty'] Whether returned data should be trimmed. This option is set to `empty` by default,\n\t * which means whenever editor content is considered empty, an empty string will be returned. To turn off trimming completely\n\t * use `'none'`. In such cases exact content will be returned (for example `<p> </p>` for an empty editor).\n\t * @returns {String} Output data.\n\t */\n\tget( options ) {\n\t\tconst { rootName = 'main', trim = 'empty' } = options || {};\n\n\t\tif ( !this._checkIfRootsExists( [ rootName ] ) ) {\n\t\t\t/**\n\t\t\t * Cannot get data from a non-existing root. This error is thrown when {@link #get DataController#get() method}\n\t\t\t * is called with non-existent root name. For example, if there is an editor instance with only `main` root,\n\t\t\t * calling {@link #get} like:\n\t\t\t *\n\t\t\t *\t\tdata.get( { rootName: 'root2' } );\n\t\t\t *\n\t\t\t * will throw this error.\n\t\t\t *\n\t\t\t * @error datacontroller-get-non-existent-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-get-non-existent-root: Attempting to get data from a non-existing root.', this );\n\t\t}\n\n\t\tconst root = this.model.document.getRoot( rootName );\n\n\t\tif ( trim === 'empty' && !this.model.hasContent( root, { ignoreWhitespaces: true } ) ) {\n\t\t\treturn '';\n\t\t}\n\n\t\treturn this.stringify( root );\n\t}\n\n\t/**\n\t * Returns the content of the given {@link module:engine/model/element~Element model's element} or\n\t * {@link module:engine/model/documentfragment~DocumentFragment model document fragment} converted by the downcast converters\n\t * attached to {@link #downcastDispatcher} and formatted by the {@link #processor data processor}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} modelElementOrFragment\n\t * Element whose content will be stringified.\n\t * @returns {String} Output data.\n\t */\n\tstringify( modelElementOrFragment ) {\n\t\t// Model -> view.\n\t\tconst viewDocumentFragment = this.toView( modelElementOrFragment );\n\n\t\t// View -> data.\n\t\treturn this.processor.toData( viewDocumentFragment );\n\t}\n\n\t/**\n\t * Returns the content of the given {@link module:engine/model/element~Element model element} or\n\t * {@link module:engine/model/documentfragment~DocumentFragment model document fragment} converted by the downcast\n\t * converters attached to {@link #downcastDispatcher} to a\n\t * {@link module:engine/view/documentfragment~DocumentFragment view document fragment}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} modelElementOrFragment\n\t * Element or document fragment whose content will be converted.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} Output view DocumentFragment.\n\t */\n\ttoView( modelElementOrFragment ) {\n\t\t// Clear bindings so the call to this method gives correct results.\n\t\tthis.mapper.clearBindings();\n\n\t\t// First, convert elements.\n\t\tconst modelRange = ModelRange._createIn( modelElementOrFragment );\n\n\t\tconst viewDocumentFragment = new ViewDocumentFragment();\n\n\t\t// Create separate ViewDowncastWriter just for data conversion purposes.\n\t\t// We have no view controller and rendering do DOM in DataController so view.change() block is not used here.\n\t\tconst viewWriter = new ViewDowncastWriter( new ViewDocument() );\n\t\tthis.mapper.bindElements( modelElementOrFragment, viewDocumentFragment );\n\n\t\tthis.downcastDispatcher.convertInsert( modelRange, viewWriter );\n\n\t\tif ( !modelElementOrFragment.is( 'documentFragment' ) ) {\n\t\t\t// Then, if a document element is converted, convert markers.\n\t\t\t// From all document markers, get those, which \"intersect\" with the converter element.\n\t\t\tconst markers = _getMarkersRelativeToElement( modelElementOrFragment );\n\n\t\t\tfor ( const [ name, range ] of markers ) {\n\t\t\t\tthis.downcastDispatcher.convertMarkerAdd( name, range, viewWriter );\n\t\t\t}\n\t\t}\n\n\t\treturn viewDocumentFragment;\n\t}\n\n\t/**\n\t * Sets initial input data parsed by the {@link #processor data processor} and\n\t * converted by the {@link #upcastDispatcher view-to-model converters}.\n\t * Initial data can be set only to document that {@link module:engine/model/document~Document#version} is equal 0.\n\t *\n\t * **Note** This method is {@link module:utils/observablemixin~ObservableMixin#decorate decorated} which is\n\t * used by e.g. collaborative editing plugin that syncs remote data on init.\n\t *\n\t * When data is passed as a string it is initialized on a default `main` root:\n\t *\n\t *\t\tdataController.init( '<p>Foo</p>' ); // Initializes data on the `main` root.\n\t *\n\t * To initialize data on a different root or multiple roots at once, object containing `rootName` - `data` pairs should be passed:\n\t *\n\t *\t\tdataController.init( { main: '<p>Foo</p>', title: '<h1>Bar</h1>' } ); // Initializes data on the `main` and `title` roots.\n\t *\n\t * @fires init\n\t * @param {String|Object.<String,String>} data Input data as a string or an object containing `rootName` - `data`\n\t * pairs to initialize data on multiple roots at once.\n\t * @returns {Promise} Promise that is resolved after the data is set on the editor.\n\t */\n\tinit( data ) {\n\t\tif ( this.model.document.version ) {\n\t\t\t/**\n\t\t\t * Cannot set initial data to not empty {@link module:engine/model/document~Document}.\n\t\t\t * Initial data should be set once, during {@link module:core/editor/editor~Editor} initialization,\n\t\t\t * when the {@link module:engine/model/document~Document#version} is equal 0.\n\t\t\t *\n\t\t\t * @error datacontroller-init-document-not-empty\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-init-document-not-empty: Trying to set initial data to not empty document.', this );\n\t\t}\n\n\t\tlet initialData = {};\n\t\tif ( typeof data === 'string' ) {\n\t\t\tinitialData.main = data; // Default root is 'main'. To initiate data on a different root, object should be passed.\n\t\t} else {\n\t\t\tinitialData = data;\n\t\t}\n\n\t\tif ( !this._checkIfRootsExists( Object.keys( initialData ) ) ) {\n\t\t\t/**\n\t\t\t * Cannot init data on a non-existing root. This error is thrown when {@link #init DataController#init() method}\n\t\t\t * is called with non-existent root name. For example, if there is an editor instance with only `main` root,\n\t\t\t * calling {@link #init} like:\n\t\t\t *\n\t\t\t * \t\tdata.init( { main: '<p>Foo</p>', root2: '<p>Bar</p>' } );\n\t\t\t *\n\t\t\t * will throw this error.\n\t\t\t *\n\t\t\t * @error datacontroller-init-non-existent-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-init-non-existent-root: Attempting to init data on a non-existing root.', this );\n\t\t}\n\n\t\tthis.model.enqueueChange( 'transparent', writer => {\n\t\t\tfor ( const rootName of Object.keys( initialData ) ) {\n\t\t\t\tconst modelRoot = this.model.document.getRoot( rootName );\n\t\t\t\twriter.insert( this.parse( initialData[ rootName ], modelRoot ), modelRoot, 0 );\n\t\t\t}\n\t\t} );\n\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * Sets input data parsed by the {@link #processor data processor} and\n\t * converted by the {@link #upcastDispatcher view-to-model converters}.\n\t * This method can be used any time to replace existing editor data by the new one without clearing the\n\t * {@link module:engine/model/document~Document#history document history}.\n\t *\n\t * This method also creates a batch with all the changes applied. If all you need is to parse data, use\n\t * the {@link #parse} method.\n\t *\n\t * When data is passed as a string it is set on a default `main` root:\n\t *\n\t *\t\tdataController.set( '<p>Foo</p>' ); // Sets data on the `main` root.\n\t *\n\t * To set data on a different root or multiple roots at once, object containing `rootName` - `data` pairs should be passed:\n\t *\n\t *\t\tdataController.set( { main: '<p>Foo</p>', title: '<h1>Bar</h1>' } ); // Sets data on the `main` and `title` roots.\n\t *\n\t * @param {String|Object.<String,String>} data Input data as a string or an object containing `rootName` - `data`\n\t * pairs to set data on multiple roots at once.\n\t */\n\tset( data ) {\n\t\tlet newData = {};\n\n\t\tif ( typeof data === 'string' ) {\n\t\t\tnewData.main = data; // Default root is 'main'. To set data on a different root, object should be passed.\n\t\t} else {\n\t\t\tnewData = data;\n\t\t}\n\n\t\tif ( !this._checkIfRootsExists( Object.keys( newData ) ) ) {\n\t\t\t/**\n\t\t\t * Cannot set data on a non-existing root. This error is thrown when {@link #set DataController#set() method}\n\t\t\t * is called with non-existent root name. For example, if there is an editor instance with only `main` root,\n\t\t\t * calling {@link #set} like:\n\t\t\t *\n\t\t\t * \t\tdata.set( { main: '<p>Foo</p>', root2: '<p>Bar</p>' } );\n\t\t\t *\n\t\t\t * will throw this error.\n\t\t\t *\n\t\t\t * @error datacontroller-set-non-existent-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-set-non-existent-root: Attempting to set data on a non-existing root.', this );\n\t\t}\n\n\t\tthis.model.enqueueChange( 'transparent', writer => {\n\t\t\twriter.setSelection( null );\n\t\t\twriter.removeSelectionAttribute( this.model.document.selection.getAttributeKeys() );\n\n\t\t\tfor ( const rootName of Object.keys( newData ) ) {\n\t\t\t\t// Save to model.\n\t\t\t\tconst modelRoot = this.model.document.getRoot( rootName );\n\n\t\t\t\twriter.remove( writer.createRangeIn( modelRoot ) );\n\t\t\t\twriter.insert( this.parse( newData[ rootName ], modelRoot ), modelRoot, 0 );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the data parsed by the {@link #processor data processor} and then converted by upcast converters\n\t * attached to the {@link #upcastDispatcher}.\n\t *\n\t * @see #set\n\t * @param {String} data Data to parse.\n\t * @param {module:engine/model/schema~SchemaContextDefinition} [context='$root'] Base context in which the view will\n\t * be converted to the model. See: {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#convert}.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Parsed data.\n\t */\n\tparse( data, context = '$root' ) {\n\t\t// data -> view\n\t\tconst viewDocumentFragment = this.processor.toView( data );\n\n\t\t// view -> model\n\t\treturn this.toModel( viewDocumentFragment, context );\n\t}\n\n\t/**\n\t * Returns the result of the given {@link module:engine/view/element~Element view element} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment view document fragment} converted by the\n\t * {@link #upcastDispatcher view-to-model converters}, wrapped by {@link module:engine/model/documentfragment~DocumentFragment}.\n\t *\n\t * When marker elements were converted during the conversion process, it will be set as a document fragment's\n\t * {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewElementOrFragment\n\t * Element or document fragment whose content will be converted.\n\t * @param {module:engine/model/schema~SchemaContextDefinition} [context='$root'] Base context in which the view will\n\t * be converted to the model. See: {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#convert}.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Output document fragment.\n\t */\n\ttoModel( viewElementOrFragment, context = '$root' ) {\n\t\treturn this.model.change( writer => {\n\t\t\treturn this.upcastDispatcher.convert( viewElementOrFragment, writer, context );\n\t\t} );\n\t}\n\n\t/**\n\t * Removes all event listeners set by the DataController.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Checks if all provided root names are existing editor roots.\n\t *\n\t * @private\n\t * @param {Array.<String>} rootNames Root names to check.\n\t * @returns {Boolean} Whether all provided root names are existing editor roots.\n\t */\n\t_checkIfRootsExists( rootNames ) {\n\t\tfor ( const rootName of rootNames ) {\n\t\t\tif ( !this.model.document.getRootNames().includes( rootName ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Event fired once data initialisation has finished.\n\t *\n\t * @event ready\n\t */\n\n\t/**\n\t * Event fired after {@link #init init() method} has been run. It can be {@link #listenTo listened to} to adjust/modify\n\t * the initialisation flow. However, if the `init` event is stopped or prevented, the {@link #event:ready ready event}\n\t * should be fired manually.\n\t *\n\t * The `init` event is fired by decorated {@link #init} method.\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * @event init\n\t */\n}\n\nmix( DataController, ObservableMixin );\n\n// Helper function for downcast conversion.\n//\n// Takes a document element (element that is added to a model document) and checks which markers are inside it\n// and which markers are containing it. If the marker is intersecting with element, the intersection is returned.\nfunction _getMarkersRelativeToElement( element ) {\n\tconst result = [];\n\tconst doc = element.root.document;\n\n\tif ( !doc ) {\n\t\treturn [];\n\t}\n\n\tconst elementRange = ModelRange._createIn( element );\n\n\tfor ( const marker of doc.model.markers ) {\n\t\tconst intersection = elementRange.getIntersection( marker.getRange() );\n\n\t\tif ( intersection ) {\n\t\t\tresult.push( [ marker.name, intersection ] );\n\t\t}\n\t}\n\n\treturn result;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/conversion/conversion\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport UpcastHelpers from './upcasthelpers';\nimport DowncastHelpers from './downcasthelpers';\n\n/**\n * A utility class that helps add converters to upcast and downcast dispatchers.\n *\n * We recommend reading the {@glink framework/guides/architecture/editing-engine Editing engine architecture} guide first to\n * understand the core concepts of the conversion mechanisms.\n *\n * An instance of the conversion manager is available in the\n * {@link module:core/editor/editor~Editor#conversion `editor.conversion`} property\n * and by default has the following groups of dispatchers (i.e. directions of conversion):\n *\n * * `downcast` (editing and data downcasts)\n * * `editingDowncast`\n * * `dataDowncast`\n * * `upcast`\n *\n * # One-way converters\n *\n * To add a converter to a specific group, use the {@link module:engine/conversion/conversion~Conversion#for `for()`}\n * method:\n *\n *\t\t// Add a converter to editing downcast and data downcast.\n *\t\teditor.conversion.for( 'downcast' ).elementToElement( config ) );\n *\n *\t\t// Add a converter to the data pipepline only:\n *\t\teditor.conversion.for( 'dataDowncast' ).elementToElement( dataConversionConfig ) );\n *\n *\t\t// And a slightly different one for the editing pipeline:\n *\t\teditor.conversion.for( 'editingDowncast' ).elementToElement( editingConversionConfig ) );\n *\n * See {@link module:engine/conversion/conversion~Conversion#for `for()`} method documentation to learn more about\n * available conversion helpers and how to use your custom ones.\n *\n * # Two-way converters\n *\n * Besides using one-way converters via the `for()` method, you can also use other methods available in this\n * class to add two-way converters (upcast and downcast):\n *\n * * {@link module:engine/conversion/conversion~Conversion#elementToElement `elementToElement()`} –\n * Model element to view element and vice versa.\n * * {@link module:engine/conversion/conversion~Conversion#attributeToElement `attributeToElement()`} –\n * Model attribute to view element and vice versa.\n * * {@link module:engine/conversion/conversion~Conversion#attributeToAttribute `attributeToAttribute()`} –\n * Model attribute to view element and vice versa.\n */\nexport default class Conversion {\n\t/**\n\t * Creates a new conversion instance.\n\t *\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher>} downcastDispatchers\n\t * @param {module:engine/conversion/upcastdispatcher~UpcastDispatcher|\n\t * Array.<module:engine/conversion/upcastdispatcher~UpcastDispatcher>} upcastDispatchers\n\t */\n\tconstructor( downcastDispatchers, upcastDispatchers ) {\n\t\t/**\n\t\t * Maps dispatchers group name to ConversionHelpers instances.\n\t\t *\n\t\t * @private\n\t\t * @member {Map.<String,module:engine/conversion/conversionhelpers~ConversionHelpers>}\n\t\t */\n\t\tthis._helpers = new Map();\n\n\t\t// Define default 'downcast' & 'upcast' dispatchers groups. Those groups are always available as two-way converters needs them.\n\t\tthis._downcast = Array.isArray( downcastDispatchers ) ? downcastDispatchers : [ downcastDispatchers ];\n\t\tthis._createConversionHelpers( { name: 'downcast', dispatchers: this._downcast, isDowncast: true } );\n\n\t\tthis._upcast = Array.isArray( upcastDispatchers ) ? upcastDispatchers : [ upcastDispatchers ];\n\t\tthis._createConversionHelpers( { name: 'upcast', dispatchers: this._upcast, isDowncast: false } );\n\t}\n\n\t/**\n\t * Define an alias for registered dispatcher.\n\t *\n\t *\t\tconst conversion = new Conversion(\n\t *\t\t\t[ dataDowncastDispatcher, editingDowncastDispatcher ],\n\t *\t\t\tupcastDispatcher\n\t *\t\t);\n\t *\n\t *\t\tconversion.addAlias( 'dataDowncast', dataDowncastDispatcher );\n\t *\n\t * @param {String} alias An alias of a dispatcher.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * module:engine/conversion/upcastdispatcher~UpcastDispatcher} dispatcher Dispatcher which should have an alias.\n\t */\n\taddAlias( alias, dispatcher ) {\n\t\tconst isDowncast = this._downcast.includes( dispatcher );\n\t\tconst isUpcast = this._upcast.includes( dispatcher );\n\n\t\tif ( !isUpcast && !isDowncast ) {\n\t\t\t/**\n\t\t\t * Trying to register and alias for a dispatcher that nas not been registered.\n\t\t\t *\n\t\t\t * @error conversion-add-alias-dispatcher-not-registered\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'conversion-add-alias-dispatcher-not-registered: ' +\n\t\t\t\t'Trying to register and alias for a dispatcher that nas not been registered.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tthis._createConversionHelpers( { name: alias, dispatchers: [ dispatcher ], isDowncast } );\n\t}\n\n\t/**\n\t * Provides a chainable API to assign converters to conversion dispatchers group.\n\t *\n\t * If the given group name has not been registered, the\n\t * {@link module:utils/ckeditorerror~CKEditorError `conversion-for-unknown-group` error} is thrown.\n\t *\n\t * You can use conversion helpers available directly in the `for()` chain or your custom ones via\n\t * the {@link module:engine/conversion/conversionhelpers~ConversionHelpers#add `add()`} method.\n\t *\n\t * # Using bulit-in conversion helpers\n\t *\n\t * The `for()` chain comes with a set of conversion helpers which you can use like this:\n\t *\n\t *\t\teditor.conversion.for( 'downcast' )\n\t *\t\t\t.elementToElement( config1 ) // Adds an element-to-element downcast converter.\n\t *\t\t\t.attributeToElement( config2 ); // Adds an attribute-to-element downcast converter.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' )\n\t *\t\t\t.elementToAttribute( config3 ); // Adds an element-to-attribute upcast converter.\n\t *\n\t * Refer to the documentation of built-in conversion helpers to learn about their configuration options.\n\t *\n\t * * downcast (model-to-view) conversion helpers:\n\t *\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`},\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement `attributeToElement()`},\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToAttribute `attributeToAttribute()`}.\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToElement `markerToElement()`}.\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToHighlight `markerToHighlight()`}.\n\t *\n\t * * upcast (view-to-model) conversion helpers:\n\t *\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToElement `elementToElement()`},\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToAttribute `elementToAttribute()`},\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#attributeToAttribute `attributeToAttribute()`}.\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToMarker `elementToMarker()`}.\n\t *\n\t * # Using custom conversion helpers\n\t *\n\t * If you need to implement a nontypical converter, you can do so by calling:\n\t *\n\t *\t\teditor.conversion.for( direction ).add( customHelper );\n\t *\n\t * The `.add()` method takes exactly one parameter, which is a function. This function should accept one parameter that\n\t * is a dispatcher instance. The function should add an actual converter to the passed dispatcher instance.\n\t *\n\t * Example:\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).add( dispatcher => {\n\t *\t\t\tdispatcher.on( 'element:a', ( evt, data, conversionApi ) => {\n\t *\t\t\t\t// Do something with a view <a> element.\n\t *\t\t\t} );\n\t *\t\t} );\n\t *\n\t * Refer to the documentation of {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher}\n\t * and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} to learn how to write\n\t * custom converters.\n\t *\n\t * @param {String} groupName The name of dispatchers group to add the converters to.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tfor( groupName ) {\n\t\tif ( !this._helpers.has( groupName ) ) {\n\t\t\t/**\n\t\t\t * Trying to add a converter to an unknown dispatchers group.\n\t\t\t *\n\t\t\t * @error conversion-for-unknown-group\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'conversion-for-unknown-group: Trying to add a converter to an unknown dispatchers group.', this );\n\t\t}\n\n\t\treturn this._helpers.get( groupName );\n\t}\n\n\t/**\n\t * Sets up converters between the model and the view that convert a model element to a view element (and vice versa).\n\t * For example, the model `<paragraph>Foo</paragraph>` is `<p>Foo</p>` in the view.\n\t *\n\t *\t\t// A simple conversion from the `paragraph` model element to the `<p>` view element (and vice versa).\n\t *\t\teditor.conversion.elementToElement( { model: 'paragraph', view: 'p' } );\n\t *\n\t *\t\t// Override other converters by specifying a converter definition with a higher priority.\n\t *\t\teditor.conversion.elementToElement( { model: 'paragraph', view: 'div', converterPriority: 'high' } );\n\t *\n\t *\t\t// View specified as an object instead of a string.\n\t *\t\teditor.conversion.elementToElement( {\n\t *\t\t\tmodel: 'fancyParagraph',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'fancy'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Use `upcastAlso` to define other view elements that should also be converted to a `paragraph` element.\n\t *\t\teditor.conversion.elementToElement( {\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tview: 'p',\n\t *\t\t\tupcastAlso: [\n\t *\t\t\t\t'div',\n\t *\t\t\t\t{\n\t *\t\t\t\t\t// Any element with the `display: block` style.\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\tdisplay: 'block'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// `upcastAlso` set as callback enables a conversion of a wide range of different view elements.\n\t *\t\teditor.conversion.elementToElement( {\n\t *\t\t\tmodel: 'heading',\n\t *\t\t\tview: 'h2',\n\t *\t\t\t// Convert \"headling-like\" paragraphs to headings.\n\t *\t\t\tupcastAlso: viewElement => {\n\t *\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\n\t *\t\t\t\tif ( !fontSize ) {\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\tconst match = fontSize.match( /(\\d+)\\s*px/ );\n\t *\n\t *\t\t\t\tif ( !match ) {\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\tconst size = Number( match[ 1 ] );\n\t *\n\t *\t\t\t\tif ( size > 26 ) {\n\t *\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\treturn { name: true, styles: [ 'font-size' ] };\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\treturn null;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * `definition.model` is a `String` with a model element name to convert from or to.\n\t * See {@link module:engine/conversion/conversion~ConverterDefinition} to learn about other parameters.\n\t *\n\t * @param {module:engine/conversion/conversion~ConverterDefinition} definition The converter definition.\n\t */\n\telementToElement( definition ) {\n\t\t// Set up downcast converter.\n\t\tthis.for( 'downcast' ).elementToElement( definition );\n\n\t\t// Set up upcast converter.\n\t\tfor ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {\n\t\t\tthis.for( 'upcast' )\n\t\t\t\t.elementToElement( {\n\t\t\t\t\tmodel,\n\t\t\t\t\tview,\n\t\t\t\t\tconverterPriority: definition.converterPriority\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Sets up converters between the model and the view that convert a model attribute to a view element (and vice versa).\n\t * For example, a model text node with `\"Foo\"` as data and the `bold` attribute is `<strong>Foo</strong>` in the view.\n\t *\n\t *\t\t// A simple conversion from the `bold=true` attribute to the `<strong>` view element (and vice versa).\n\t *\t\teditor.conversion.attributeToElement( { model: 'bold', view: 'strong' } );\n\t *\n\t *\t\t// Override other converters by specifying a converter definition with a higher priority.\n\t *\t\teditor.conversion.attributeToElement( { model: 'bold', view: 'b', converterPriority: 'high' } );\n\t *\n\t *\t\t// View specified as an object instead of a string.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: 'bold'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Use `config.model.name` to define the conversion only from a given node type, `$text` in this case.\n\t *\t\t// The same attribute on different elements may then be handled by a different converter.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'textDecoration',\n\t *\t\t\t\tvalues: [ 'underline', 'lineThrough' ],\n\t *\t\t\t\tname: '$text'\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tunderline: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-decoration': 'underline'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tlineThrough: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-decoration': 'line-through'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Use `upcastAlso` to define other view elements that should also be converted to the `bold` attribute.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: 'strong',\n\t *\t\t\tupcastAlso: [\n\t *\t\t\t\t'b',\n\t *\t\t\t\t{\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tclasses: 'bold'\n\t *\t\t\t\t},\n\t *\t\t\t\t{\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-weight': 'bold'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tviewElement => {\n\t *\t\t\t\t\tconst fontWeight = viewElement.getStyle( 'font-weight' );\n\t *\n\t *\t\t\t\t\tif ( viewElement.is( 'span' ) && fontWeight && /\\d+/.test() && Number( fontWeight ) > 500 ) {\n\t *\t\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\t\treturn {\n\t *\t\t\t\t\t\t\tname: true,\n\t *\t\t\t\t\t\t\tstyles: [ 'font-weight' ]\n\t *\t\t\t\t\t\t};\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// Conversion from and to a model attribute key whose value is an enum (`fontSize=big|small`).\n\t *\t\t// `upcastAlso` set as callback enables a conversion of a wide range of different view elements.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'fontSize',\n\t *\t\t\t\tvalues: [ 'big', 'small' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tbig: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '1.2em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tsmall: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '0.8em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tupcastAlso: {\n\t *\t\t\t\tbig: viewElement => {\n\t *\t\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\n\t *\t\t\t\t\tif ( !fontSize ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst match = fontSize.match( /(\\d+)\\s*px/ );\n\t *\n\t *\t\t\t\t\tif ( !match ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst size = Number( match[ 1 ] );\n\t *\n\t *\t\t\t\t\tif ( viewElement.is( 'span' ) && size > 10 ) {\n\t *\t\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\t\treturn { name: true, styles: [ 'font-size' ] };\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t},\n\t *\t\t\t\tsmall: viewElement => {\n\t *\t\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\n\t *\t\t\t\t\tif ( !fontSize ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst match = fontSize.match( /(\\d+)\\s*px/ );\n\t *\n\t *\t\t\t\t\tif ( !match ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst size = Number( match[ 1 ] );\n\t *\n\t *\t\t\t\t\tif ( viewElement.is( 'span' ) && size < 10 ) {\n\t *\t\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\t\treturn { name: true, styles: [ 'font-size' ] };\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * The `definition.model` parameter specifies which model attribute should be converted from or to. It can be a `{ key, value }` object\n\t * describing the attribute key and value to convert or a `String` specifying just the attribute key (then `value` is set to `true`).\n\t * See {@link module:engine/conversion/conversion~ConverterDefinition} to learn about other parameters.\n\t *\n\t * @param {module:engine/conversion/conversion~ConverterDefinition} definition The converter definition.\n\t */\n\tattributeToElement( definition ) {\n\t\t// Set up downcast converter.\n\t\tthis.for( 'downcast' ).attributeToElement( definition );\n\n\t\t// Set up upcast converter.\n\t\tfor ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {\n\t\t\tthis.for( 'upcast' )\n\t\t\t\t.elementToAttribute( {\n\t\t\t\t\tview,\n\t\t\t\t\tmodel,\n\t\t\t\t\tconverterPriority: definition.converterPriority\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Sets up converters between the model and the view that convert a model attribute to a view attribute (and vice versa).\n\t * For example, `<image src='foo.jpg'></image>` is converted to `<img src='foo.jpg'></img>` (the same attribute key and value).\n\t * This type of converters is intended to be used with {@link module:engine/model/element~Element model element} nodes.\n\t * To convert text attributes {@link module:engine/conversion/conversion~Conversion#attributeToElement `attributeToElement converter`}\n\t * should be set up.\n\t *\n\t *\t\t// A simple conversion from the `source` model attribute to the `src` view attribute (and vice versa).\n\t *\t\teditor.conversion.attributeToAttribute( { model: 'source', view: 'src' } );\n\t *\n\t *\t\t// Attribute values are strictly specified.\n\t *\t\teditor.conversion.attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'image',\n\t *\t\t\t\tkey: 'aside',\n\t *\t\t\t\tvalues: [ 'aside' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\taside: {\n\t *\t\t\t\t\tname: 'img',\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: [ 'aside', 'half-size' ]\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Set the style attribute.\n\t *\t\teditor.conversion.attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'image',\n\t *\t\t\t\tkey: 'aside',\n\t *\t\t\t\tvalues: [ 'aside' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\taside: {\n\t *\t\t\t\t\tname: 'img',\n\t *\t\t\t\t\tkey: 'style',\n\t *\t\t\t\t\tvalue: {\n\t *\t\t\t\t\t\tfloat: 'right',\n\t *\t\t\t\t\t\twidth: '50%',\n\t *\t\t\t\t\t\tmargin: '5px'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Conversion from and to a model attribute key whose value is an enum (`align=right|center`).\n\t *\t\t// Use `upcastAlso` to define other view elements that should also be converted to the `align=right` attribute.\n\t *\t\teditor.conversion.attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'align',\n\t *\t\t\t\tvalues: [ 'right', 'center' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tright: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: 'align-right'\n\t *\t\t\t\t},\n\t *\t\t\t\tcenter: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: 'align-center'\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tupcastAlso: {\n\t *\t\t\t\tright: {\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-align': 'right'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tcenter: {\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-align': 'center'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * The `definition.model` parameter specifies which model attribute should be converted from and to.\n\t * It can be a `{ key, [ values ], [ name ] }` object or a `String`, which will be treated like `{ key: definition.model }`.\n\t * The `key` property is the model attribute key to convert from and to.\n\t * The `values` are the possible model attribute values. If `values` is not set, the model attribute value will be the same as the\n\t * view attribute value.\n\t * If `name` is set, the conversion will be set up only for model elements with the given name.\n\t *\n\t * The `definition.view` parameter specifies which view attribute should be converted from and to.\n\t * It can be a `{ key, value, [ name ] }` object or a `String`, which will be treated like `{ key: definition.view }`.\n\t * The `key` property is the view attribute key to convert from and to.\n\t * The `value` is the view attribute value to convert from and to. If `definition.value` is not set, the view attribute value will be\n\t * the same as the model attribute value.\n\t * If `key` is `'class'`, `value` can be a `String` or an array of `String`s.\n\t * If `key` is `'style'`, `value` is an object with key-value pairs.\n\t * In other cases, `value` is a `String`.\n\t * If `name` is set, the conversion will be set up only for model elements with the given name.\n\t * If `definition.model.values` is set, `definition.view` is an object that assigns values from `definition.model.values`\n\t * to `{ key, value, [ name ] }` objects.\n\t *\n\t * `definition.upcastAlso` specifies which other matching view elements should also be upcast to the given model configuration.\n\t * If `definition.model.values` is set, `definition.upcastAlso` should be an object assigning values from `definition.model.values`\n\t * to {@link module:engine/view/matcher~MatcherPattern}s or arrays of {@link module:engine/view/matcher~MatcherPattern}s.\n\t *\n\t * **Note:** `definition.model` and `definition.view` form should be mirrored, so the same types of parameters should\n\t * be given in both parameters.\n\t *\n\t * @param {Object} definition The converter definition.\n\t * @param {String|Object} definition.model The model attribute to convert from and to.\n\t * @param {String|Object} definition.view The view attribute to convert from and to.\n\t * @param {module:engine/view/matcher~MatcherPattern|Array.<module:engine/view/matcher~MatcherPattern>} [definition.upcastAlso]\n\t * Any view element matching `definition.upcastAlso` will also be converted to the given model attribute. `definition.upcastAlso`\n\t * is used only if `config.model.values` is specified.\n\t */\n\tattributeToAttribute( definition ) {\n\t\t// Set up downcast converter.\n\t\tthis.for( 'downcast' ).attributeToAttribute( definition );\n\n\t\t// Set up upcast converter.\n\t\tfor ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {\n\t\t\tthis.for( 'upcast' )\n\t\t\t\t.attributeToAttribute( {\n\t\t\t\t\tview,\n\t\t\t\t\tmodel\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Creates and caches conversion helpers for given dispatchers group.\n\t *\n\t * @private\n\t * @param {Object} options\n\t * @param {String} options.name Group name.\n\t * @param {Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * module:engine/conversion/upcastdispatcher~UpcastDispatcher>} options.dispatchers\n\t * @param {Boolean} options.isDowncast\n\t */\n\t_createConversionHelpers( { name, dispatchers, isDowncast } ) {\n\t\tif ( this._helpers.has( name ) ) {\n\t\t\t/**\n\t\t\t * Trying to register a group name that has already been registered.\n\t\t\t *\n\t\t\t * @error conversion-group-exists\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'conversion-group-exists: Trying to register a group name that has already been registered.', this );\n\t\t}\n\n\t\tconst helpers = isDowncast ? new DowncastHelpers( dispatchers ) : new UpcastHelpers( dispatchers );\n\n\t\tthis._helpers.set( name, helpers );\n\t}\n}\n\n/**\n * Defines how the model should be converted from and to the view.\n *\n * @typedef {Object} module:engine/conversion/conversion~ConverterDefinition\n *\n * @property {*} [model] The model conversion definition. Describes the model element or model attribute to convert. This parameter differs\n * for different functions that accept `ConverterDefinition`. See the description of the function to learn how to set it.\n * @property {module:engine/view/elementdefinition~ElementDefinition|Object} view The definition of the view element to convert from and\n * to. If `model` describes multiple values, `view` is an object that assigns these values (`view` object keys) to view element definitions\n * (`view` object values).\n * @property {module:engine/view/matcher~MatcherPattern|Array.<module:engine/view/matcher~MatcherPattern>} [upcastAlso]\n * Any view element matching `upcastAlso` will also be converted to the model. If `model` describes multiple values, `upcastAlso`\n * is an object that assigns these values (`upcastAlso` object keys) to {@link module:engine/view/matcher~MatcherPattern}s\n * (`upcastAlso` object values).\n * @property {module:utils/priorities~PriorityString} [converterPriority] The converter priority.\n */\n\n// Helper function that creates a joint array out of an item passed in `definition.view` and items passed in\n// `definition.upcastAlso`.\n//\n// @param {module:engine/conversion/conversion~ConverterDefinition} definition\n// @returns {Array} Array containing view definitions.\nfunction* _getAllUpcastDefinitions( definition ) {\n\tif ( definition.model.values ) {\n\t\tfor ( const value of definition.model.values ) {\n\t\t\tconst model = { key: definition.model.key, value };\n\t\t\tconst view = definition.view[ value ];\n\t\t\tconst upcastAlso = definition.upcastAlso ? definition.upcastAlso[ value ] : undefined;\n\n\t\t\tyield* _getUpcastDefinition( model, view, upcastAlso );\n\t\t}\n\t} else {\n\t\tyield* _getUpcastDefinition( definition.model, definition.view, definition.upcastAlso );\n\t}\n}\n\nfunction* _getUpcastDefinition( model, view, upcastAlso ) {\n\tyield { model, view };\n\n\tif ( upcastAlso ) {\n\t\tupcastAlso = Array.isArray( upcastAlso ) ? upcastAlso : [ upcastAlso ];\n\n\t\tfor ( const upcastAlsoItem of upcastAlso ) {\n\t\t\tyield { model, view: upcastAlsoItem };\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/batch\n */\n\n/**\n * A batch instance groups model changes ({@link module:engine/model/operation/operation~Operation operations}). All operations\n * grouped in a single batch can be reverted together, so you can also think about a batch as of a single undo step. If you want\n * to extend a given undo step, you can add more changes to the batch using {@link module:engine/model/model~Model#enqueueChange}:\n *\n *\t\tmodel.enqueueChange( batch, writer => {\n *\t\t\twriter.insertText( 'foo', paragraph, 'end' );\n *\t\t} );\n *\n * @see module:engine/model/model~Model#enqueueChange\n * @see module:engine/model/model~Model#change\n */\nexport default class Batch {\n\t/**\n\t * Creates a batch instance.\n\t *\n\t * @see module:engine/model/model~Model#enqueueChange\n\t * @see module:engine/model/model~Model#change\n\t * @param {'transparent'|'default'} [type='default'] The type of the batch.\n\t */\n\tconstructor( type = 'default' ) {\n\t\t/**\n\t\t * An array of operations that compose this batch.\n\t\t *\n\t\t * @readonly\n\t\t * @type {Array.<module:engine/model/operation/operation~Operation>}\n\t\t */\n\t\tthis.operations = [];\n\n\t\t/**\n\t\t * The type of the batch.\n\t\t *\n\t\t * It can be one of the following values:\n\t\t * * `'default'` – All \"normal\" batches. This is the most commonly used type.\n\t\t * * `'transparent'` – A batch that should be ignored by other features, i.e. an initial batch or collaborative editing\n\t\t * changes.\n\t\t *\n\t\t * @readonly\n\t\t * @type {'transparent'|'default'}\n\t\t */\n\t\tthis.type = type;\n\t}\n\n\t/**\n\t * Returns the base version of this batch, which is equal to the base version of the first operation in the batch.\n\t * If there are no operations in the batch or neither operation has the base version set, it returns `null`.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget baseVersion() {\n\t\tfor ( const op of this.operations ) {\n\t\t\tif ( op.baseVersion !== null ) {\n\t\t\t\treturn op.baseVersion;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Adds an operation to the batch instance.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation An operation to add.\n\t * @returns {module:engine/model/operation/operation~Operation} The added operation.\n\t */\n\taddOperation( operation ) {\n\t\toperation.batch = this;\n\t\tthis.operations.push( operation );\n\n\t\treturn operation;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/operation\n */\n\n/**\n * Abstract base operation class.\n *\n * @abstract\n */\nexport default class Operation {\n\t/**\n\t * Base operation constructor.\n\t *\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( baseVersion ) {\n\t\t/**\n\t\t * {@link module:engine/model/document~Document#version} on which operation can be applied. If you try to\n\t\t * {@link module:engine/model/model~Model#applyOperation apply} operation with different base version than the\n\t\t * {@link module:engine/model/document~Document#version document version} the\n\t\t * {@link module:utils/ckeditorerror~CKEditorError model-document-applyOperation-wrong-version} error is thrown.\n\t\t *\n\t\t * @member {Number}\n\t\t */\n\t\tthis.baseVersion = baseVersion;\n\n\t\t/**\n\t\t * Defines whether operation is executed on attached or detached {@link module:engine/model/item~Item items}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isDocumentOperation\n\t\t */\n\t\tthis.isDocumentOperation = this.baseVersion !== null;\n\n\t\t/**\n\t\t * {@link module:engine/model/batch~Batch Batch} to which the operation is added or `null` if the operation is not\n\t\t * added to any batch yet.\n\t\t *\n\t\t * @member {module:engine/model/batch~Batch|null} #batch\n\t\t */\n\t\tthis.batch = null;\n\n\t\t/**\n\t\t * Operation type.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} #type\n\t\t */\n\n\t\t/**\n\t\t * Creates and returns an operation that has the same parameters as this operation.\n\t\t *\n\t\t * @method #clone\n\t\t * @returns {module:engine/model/operation/operation~Operation} Clone of this operation.\n\t\t */\n\n\t\t/**\n\t\t * Creates and returns a reverse operation. Reverse operation when executed right after\n\t\t * the original operation will bring back tree model state to the point before the original\n\t\t * operation execution. In other words, it reverses changes done by the original operation.\n\t\t *\n\t\t * Keep in mind that tree model state may change since executing the original operation,\n\t\t * so reverse operation will be \"outdated\". In that case you will need to transform it by\n\t\t * all operations that were executed after the original operation.\n\t\t *\n\t\t * @method #getReversed\n\t\t * @returns {module:engine/model/operation/operation~Operation} Reversed operation.\n\t\t */\n\n\t\t/**\n\t\t * Executes the operation - modifications described by the operation properties will be applied to the model tree.\n\t\t *\n\t\t * @protected\n\t\t * @method #_execute\n\t\t */\n\t}\n\n\t/**\n\t * Checks whether the operation's parameters are correct and the operation can be correctly executed. Throws\n\t * an error if operation is not valid.\n\t *\n\t * @protected\n\t * @method #_validate\n\t */\n\t_validate() {\n\t}\n\n\t/**\n\t * Custom toJSON method to solve child-parent circular dependencies.\n\t *\n\t * @method #toJSON\n\t * @returns {Object} Clone of this object with the operation property replaced with string.\n\t */\n\ttoJSON() {\n\t\t// This method creates only a shallow copy, all nested objects should be defined separately.\n\t\t// See https://github.com/ckeditor/ckeditor5-engine/issues/1477.\n\t\tconst json = Object.assign( {}, this );\n\n\t\tjson.__className = this.constructor.className;\n\n\t\t// Remove reference to the parent `Batch` to avoid circular dependencies.\n\t\tdelete json.batch;\n\n\t\t// Only document operations are shared with other clients so it is not necessary to keep this information.\n\t\tdelete json.isDocumentOperation;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Name of the operation class used for serialization.\n\t *\n\t * @type {String}\n\t */\n\tstatic get className() {\n\t\treturn 'Operation';\n\t}\n\n\t/**\n\t * Creates Operation object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} doc Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/operation~Operation}\n\t */\n\tstatic fromJSON( json ) {\n\t\treturn new this( json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.toString() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 module:engine/model/documentfragment\n */\n\nimport NodeList from './nodelist';\nimport Element from './element';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\n// @if CK_DEBUG_ENGINE // const { stringifyMap } = require( '../dev-utils/utils' );\n\n/**\n * DocumentFragment represents a part of model which does not have a common root but it's top-level nodes\n * can be seen as siblings. In other words, it is a detached part of model tree, without a root.\n *\n * DocumentFragment has own {@link module:engine/model/markercollection~MarkerCollection}. Markers from this collection\n * will be set to the {@link module:engine/model/model~Model#markers model markers} by a\n * {@link module:engine/model/writer~Writer#insert} function.\n */\nexport default class DocumentFragment {\n\t/**\n\t * Creates an empty `DocumentFragment`.\n\t *\n\t * **Note:** Constructor of this class shouldn't be used directly in the code.\n\t * Use the {@link module:engine/model/writer~Writer#createDocumentFragment} method instead.\n\t *\n\t * @protected\n\t * @param {module:engine/model/node~Node|Iterable.<module:engine/model/node~Node>} [children]\n\t * Nodes to be contained inside the `DocumentFragment`.\n\t */\n\tconstructor( children ) {\n\t\t/**\n\t\t * DocumentFragment static markers map. This is a list of names and {@link module:engine/model/range~Range ranges}\n\t\t * which will be set as Markers to {@link module:engine/model/model~Model#markers model markers collection}\n\t\t * when DocumentFragment will be inserted to the document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Map<String,module:engine/model/range~Range>} module:engine/model/documentfragment~DocumentFragment#markers\n\t\t */\n\t\tthis.markers = new Map();\n\n\t\t/**\n\t\t * List of nodes contained inside the document fragment.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/nodelist~NodeList} module:engine/model/documentfragment~DocumentFragment#_children\n\t\t */\n\t\tthis._children = new NodeList();\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all nodes contained inside this document fragment.\n\t *\n\t * @returns {Iterable.<module:engine/model/node~Node>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this.getChildren();\n\t}\n\n\t/**\n\t * Number of this document fragment's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all of this document fragment's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget maxOffset() {\n\t\treturn this._children.maxOffset;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this document fragment, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this.childCount === 0;\n\t}\n\n\t/**\n\t * Artificial root of `DocumentFragment`. Returns itself. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Artificial parent of `DocumentFragment`. Returns `null`. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {null}\n\t */\n\tget parent() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tdocFrag.is( 'documentFragment' ); // -> true\n\t *\t\tdocFrag.is( 'model:documentFragment' ); // -> true\n\t *\n\t *\t\tdocFrag.is( 'view:documentFragment' ); // -> false\n\t *\t\tdocFrag.is( 'element' ); // -> false\n\t *\t\tdocFrag.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'documentFragment' || type == 'model:documentFragment';\n\t}\n\n\t/**\n\t * Gets the child at the given index. Returns `null` if incorrect index was passed.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/model/node~Node|null} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children.getNode( index );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all of this document fragment's children.\n\t *\n\t * @returns {Iterable.<module:engine/model/node~Node>}\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns an index of the given child node. Returns `null` if given node is not a child of this document fragment.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number|null} Child node's index.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.getNodeIndex( node );\n\t}\n\n\t/**\n\t * Returns the starting offset of given child. Starting offset is equal to the sum of\n\t * {@link module:engine/model/node~Node#offsetSize offset sizes} of all node's siblings that are before it. Returns `null` if\n\t * given node is not a child of this document fragment.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number|null} Child node's starting offset.\n\t */\n\tgetChildStartOffset( node ) {\n\t\treturn this._children.getNodeStartOffset( node );\n\t}\n\n\t/**\n\t * Returns path to a `DocumentFragment`, which is an empty array. Added for compatibility reasons.\n\t *\n\t * @returns {Array}\n\t */\n\tgetPath() {\n\t\treturn [];\n\t}\n\n\t/**\n\t * Returns a descendant node by its path relative to this element.\n\t *\n\t *\t\t// <this>a<b>c</b></this>\n\t *\t\tthis.getNodeByPath( [ 0 ] ); // -> \"a\"\n\t *\t\tthis.getNodeByPath( [ 1 ] ); // -> <b>\n\t *\t\tthis.getNodeByPath( [ 1, 0 ] ); // -> \"c\"\n\t *\n\t * @param {Array.<Number>} relativePath Path of the node to find, relative to this element.\n\t * @returns {module:engine/model/node~Node|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tgetNodeByPath( relativePath ) {\n\t\tlet node = this; // eslint-disable-line consistent-this\n\n\t\tfor ( const index of relativePath ) {\n\t\t\tnode = node.getChild( node.offsetToIndex( index ) );\n\t\t}\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Converts offset \"position\" to index \"position\".\n\t *\n\t * Returns index of a node that occupies given offset. If given offset is too low, returns `0`. If given offset is\n\t * too high, returns index after last child}.\n\t *\n\t *\t\tconst textNode = new Text( 'foo' );\n\t *\t\tconst pElement = new Element( 'p' );\n\t *\t\tconst docFrag = new DocumentFragment( [ textNode, pElement ] );\n\t *\t\tdocFrag.offsetToIndex( -1 ); // Returns 0, because offset is too low.\n\t *\t\tdocFrag.offsetToIndex( 0 ); // Returns 0, because offset 0 is taken by `textNode` which is at index 0.\n\t *\t\tdocFrag.offsetToIndex( 1 ); // Returns 0, because `textNode` has `offsetSize` equal to 3, so it occupies offset 1 too.\n\t *\t\tdocFrag.offsetToIndex( 2 ); // Returns 0.\n\t *\t\tdocFrag.offsetToIndex( 3 ); // Returns 1.\n\t *\t\tdocFrag.offsetToIndex( 4 ); // Returns 2. There are no nodes at offset 4, so last available index is returned.\n\t *\n\t * @param {Number} offset Offset to look for.\n\t * @returns {Number} Index of a node that occupies given offset.\n\t */\n\toffsetToIndex( offset ) {\n\t\treturn this._children.offsetToIndex( offset );\n\t}\n\n\t/**\n\t * Converts `DocumentFragment` instance to plain object and returns it.\n\t * Takes care of converting all of this document fragment's children.\n\t *\n\t * @returns {Object} `DocumentFragment` instance converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = [];\n\n\t\tfor ( const node of this._children ) {\n\t\t\tjson.push( node.toJSON() );\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Creates a `DocumentFragment` instance from given plain object (i.e. parsed JSON string).\n\t * Converts `DocumentFragment` children to proper nodes.\n\t *\n\t * @param {Object} json Plain object to be converted to `DocumentFragment`.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} `DocumentFragment` instance created using given plain object.\n\t */\n\tstatic fromJSON( json ) {\n\t\tconst children = [];\n\n\t\tfor ( const child of json ) {\n\t\t\tif ( child.name ) {\n\t\t\t\t// If child has name property, it is an Element.\n\t\t\t\tchildren.push( Element.fromJSON( child ) );\n\t\t\t} else {\n\t\t\t\t// Otherwise, it is a Text node.\n\t\t\t\tchildren.push( Text.fromJSON( child ) );\n\t\t\t}\n\t\t}\n\n\t\treturn new DocumentFragment( children );\n\t}\n\n\t/**\n\t * {@link #_insertChild Inserts} one or more nodes at the end of this document fragment.\n\t *\n\t * @protected\n\t * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.\n\t */\n\t_appendChild( items ) {\n\t\tthis._insertChild( this.childCount, items );\n\t}\n\n\t/**\n\t * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes\n\t * to this document fragment.\n\t *\n\t * @protected\n\t * @param {Number} index Index at which nodes should be inserted.\n\t * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.\n\t */\n\t_insertChild( index, items ) {\n\t\tconst nodes = normalize( items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\t\t}\n\n\t\tthis._children._insertNodes( index, nodes );\n\t}\n\n\t/**\n\t * Removes one or more nodes starting at the given index\n\t * and sets {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.\n\t *\n\t * @protected\n\t * @param {Number} index Index of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tconst nodes = this._children._removeNodes( index, howMany );\n\n\t\tfor ( const node of nodes ) {\n\t\t\tnode.parent = null;\n\t\t}\n\n\t\treturn nodes;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn 'documentFragment';\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelDocumentFragment: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // printTree() {\n\t// @if CK_DEBUG_ENGINE //\tlet string = 'ModelDocumentFragment: [';\n\n\t// @if CK_DEBUG_ENGINE //\tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE //\t\tstring += '\\n';\n\n\t// @if CK_DEBUG_ENGINE //\t\tif ( child.is( 'text' ) ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\tconst textAttrs = stringifyMap( child._attrs );\n\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\t'.repeat( 1 );\n\n\t// @if CK_DEBUG_ENGINE //\t\t\tif ( textAttrs !== '' ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\t\tstring += `<$text${ textAttrs }>` + child.data + '</$text>';\n\t// @if CK_DEBUG_ENGINE //\t\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\t\tstring += child.data;\n\t// @if CK_DEBUG_ENGINE //\t\t\t}\n\t// @if CK_DEBUG_ENGINE //\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += child.printTree( 1 );\n\t// @if CK_DEBUG_ENGINE //\t\t}\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tstring += '\\n]';\n\n\t// @if CK_DEBUG_ENGINE //\treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>}\n// @returns {Iterable.<module:engine/model/node~Node>}\nfunction normalize( nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( node.data, node.getAttributes() );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/utils\n */\n\nimport Node from '../node';\nimport Text from '../text';\nimport TextProxy from '../textproxy';\nimport Range from '../range';\nimport DocumentFragment from '../documentfragment';\nimport NodeList from '../nodelist';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Contains functions used for composing model tree by {@link module:engine/model/operation/operation~Operation operations}.\n * Those functions are built on top of {@link module:engine/model/node~Node node}, and it's child classes', APIs.\n *\n * @protected\n * @namespace utils\n */\n\n/**\n * Inserts given nodes at given position.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.insert\n * @param {module:engine/model/position~Position} position Position at which nodes should be inserted.\n * @param {module:engine/model/node~NodeSet} nodes Nodes to insert.\n * @returns {module:engine/model/range~Range} Range spanning over inserted elements.\n */\nexport function _insert( position, nodes ) {\n\tnodes = _normalizeNodes( nodes );\n\n\t// We have to count offset before inserting nodes because they can get merged and we would get wrong offsets.\n\tconst offset = nodes.reduce( ( sum, node ) => sum + node.offsetSize, 0 );\n\tconst parent = position.parent;\n\n\t// Insertion might be in a text node, we should split it if that's the case.\n\t_splitNodeAtPosition( position );\n\tconst index = position.index;\n\n\t// Insert nodes at given index. After splitting we have a proper index and insertion is between nodes,\n\t// using basic `Element` API.\n\tparent._insertChild( index, nodes );\n\n\t// Merge text nodes, if possible. Merging is needed only at points where inserted nodes \"touch\" \"old\" nodes.\n\t_mergeNodesAtIndex( parent, index + nodes.length );\n\t_mergeNodesAtIndex( parent, index );\n\n\treturn new Range( position, position.getShiftedBy( offset ) );\n}\n\n/**\n * Removed nodes in given range. Only {@link module:engine/model/range~Range#isFlat flat} ranges are accepted.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils._remove\n * @param {module:engine/model/range~Range} range Range containing nodes to remove.\n * @returns {Array.<module:engine/model/node~Node>}\n */\nexport function _remove( range ) {\n\tif ( !range.isFlat ) {\n\t\t/**\n\t\t * Trying to remove a range which starts and ends in different element.\n\t\t *\n\t\t * @error operation-utils-remove-range-not-flat\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'operation-utils-remove-range-not-flat: ' +\n\t\t\t'Trying to remove a range which starts and ends in different element.',\n\t\t\tthis\n\t\t);\n\t}\n\n\tconst parent = range.start.parent;\n\n\t// Range may be inside text nodes, we have to split them if that's the case.\n\t_splitNodeAtPosition( range.start );\n\t_splitNodeAtPosition( range.end );\n\n\t// Remove the text nodes using basic `Element` API.\n\tconst removed = parent._removeChildren( range.start.index, range.end.index - range.start.index );\n\n\t// Merge text nodes, if possible. After some nodes were removed, node before and after removed range will be\n\t// touching at the position equal to the removed range beginning. We check merging possibility there.\n\t_mergeNodesAtIndex( parent, range.start.index );\n\n\treturn removed;\n}\n\n/**\n * Moves nodes in given range to given target position. Only {@link module:engine/model/range~Range#isFlat flat} ranges are accepted.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.move\n * @param {module:engine/model/range~Range} sourceRange Range containing nodes to move.\n * @param {module:engine/model/position~Position} targetPosition Position to which nodes should be moved.\n * @returns {module:engine/model/range~Range} Range containing moved nodes.\n */\nexport function _move( sourceRange, targetPosition ) {\n\tif ( !sourceRange.isFlat ) {\n\t\t/**\n\t\t * Trying to move a range which starts and ends in different element.\n\t\t *\n\t\t * @error operation-utils-move-range-not-flat\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'operation-utils-move-range-not-flat: ' +\n\t\t\t'Trying to move a range which starts and ends in different element.',\n\t\t\tthis\n\t\t);\n\t}\n\n\tconst nodes = _remove( sourceRange );\n\n\t// We have to fix `targetPosition` because model changed after nodes from `sourceRange` got removed and\n\t// that change might have an impact on `targetPosition`.\n\ttargetPosition = targetPosition._getTransformedByDeletion( sourceRange.start, sourceRange.end.offset - sourceRange.start.offset );\n\n\treturn _insert( targetPosition, nodes );\n}\n\n/**\n * Sets given attribute on nodes in given range. The attributes are only set on top-level nodes of the range, not on its children.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils._setAttribute\n * @param {module:engine/model/range~Range} range Range containing nodes that should have the attribute set. Must be a flat range.\n * @param {String} key Key of attribute to set.\n * @param {*} value Attribute value.\n */\nexport function _setAttribute( range, key, value ) {\n\t// Range might start or end in text nodes, so we have to split them.\n\t_splitNodeAtPosition( range.start );\n\t_splitNodeAtPosition( range.end );\n\n\t// Iterate over all items in the range.\n\tfor ( const item of range.getItems( { shallow: true } ) ) {\n\t\t// Iterator will return `TextProxy` instances but we know that those text proxies will\n\t\t// always represent full text nodes (this is guaranteed thanks to splitting we did before).\n\t\t// So, we can operate on those text proxies' text nodes.\n\t\tconst node = item.is( 'textProxy' ) ? item.textNode : item;\n\n\t\tif ( value !== null ) {\n\t\t\tnode._setAttribute( key, value );\n\t\t} else {\n\t\t\tnode._removeAttribute( key );\n\t\t}\n\n\t\t// After attributes changing it may happen that some text nodes can be merged. Try to merge with previous node.\n\t\t_mergeNodesAtIndex( node.parent, node.index );\n\t}\n\n\t// Try to merge last changed node with it's previous sibling (not covered by the loop above).\n\t_mergeNodesAtIndex( range.end.parent, range.end.index );\n}\n\n/**\n * Normalizes given object or an array of objects to an array of {@link module:engine/model/node~Node nodes}. See\n * {@link module:engine/model/node~NodeSet NodeSet} for details on how normalization is performed.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.normalizeNodes\n * @param {module:engine/model/node~NodeSet} nodes Objects to normalize.\n * @returns {Array.<module:engine/model/node~Node>} Normalized nodes.\n */\nexport function _normalizeNodes( nodes ) {\n\tconst normalized = [];\n\n\tif ( !( nodes instanceof Array ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Convert instances of classes other than Node.\n\tfor ( let i = 0; i < nodes.length; i++ ) {\n\t\tif ( typeof nodes[ i ] == 'string' ) {\n\t\t\tnormalized.push( new Text( nodes[ i ] ) );\n\t\t} else if ( nodes[ i ] instanceof TextProxy ) {\n\t\t\tnormalized.push( new Text( nodes[ i ].data, nodes[ i ].getAttributes() ) );\n\t\t} else if ( nodes[ i ] instanceof DocumentFragment || nodes[ i ] instanceof NodeList ) {\n\t\t\tfor ( const child of nodes[ i ] ) {\n\t\t\t\tnormalized.push( child );\n\t\t\t}\n\t\t} else if ( nodes[ i ] instanceof Node ) {\n\t\t\tnormalized.push( nodes[ i ] );\n\t\t}\n\t\t// Skip unrecognized type.\n\t}\n\n\t// Merge text nodes.\n\tfor ( let i = 1; i < normalized.length; i++ ) {\n\t\tconst node = normalized[ i ];\n\t\tconst prev = normalized[ i - 1 ];\n\n\t\tif ( node instanceof Text && prev instanceof Text && _haveSameAttributes( node, prev ) ) {\n\t\t\t// Doing this instead changing `prev.data` because `data` is readonly.\n\t\t\tnormalized.splice( i - 1, 2, new Text( prev.data + node.data, prev.getAttributes() ) );\n\t\t\ti--;\n\t\t}\n\t}\n\n\treturn normalized;\n}\n\n// Checks if nodes before and after given index in given element are {@link module:engine/model/text~Text text nodes} and\n// merges them into one node if they have same attributes.\n//\n// Merging is done by removing two text nodes and inserting a new text node containing data from both merged text nodes.\n//\n// @private\n// @param {module:engine/model/element~Element} element Parent element of nodes to merge.\n// @param {Number} index Index between nodes to merge.\nfunction _mergeNodesAtIndex( element, index ) {\n\tconst nodeBefore = element.getChild( index - 1 );\n\tconst nodeAfter = element.getChild( index );\n\n\t// Check if both of those nodes are text objects with same attributes.\n\tif ( nodeBefore && nodeAfter && nodeBefore.is( 'text' ) && nodeAfter.is( 'text' ) && _haveSameAttributes( nodeBefore, nodeAfter ) ) {\n\t\t// Append text of text node after index to the before one.\n\t\tconst mergedNode = new Text( nodeBefore.data + nodeAfter.data, nodeBefore.getAttributes() );\n\n\t\t// Remove separate text nodes.\n\t\telement._removeChildren( index - 1, 2 );\n\n\t\t// Insert merged text node.\n\t\telement._insertChild( index - 1, mergedNode );\n\t}\n}\n\n// Checks if given position is in a text node, and if so, splits the text node in two text nodes, each of them\n// containing a part of original text node.\n//\n// @private\n// @param {module:engine/model/position~Position} position Position at which node should be split.\nfunction _splitNodeAtPosition( position ) {\n\tconst textNode = position.textNode;\n\tconst element = position.parent;\n\n\tif ( textNode ) {\n\t\tconst offsetDiff = position.offset - textNode.startOffset;\n\t\tconst index = textNode.index;\n\n\t\telement._removeChildren( index, 1 );\n\n\t\tconst firstPart = new Text( textNode.data.substr( 0, offsetDiff ), textNode.getAttributes() );\n\t\tconst secondPart = new Text( textNode.data.substr( offsetDiff ), textNode.getAttributes() );\n\n\t\telement._insertChild( index, [ firstPart, secondPart ] );\n\t}\n}\n\n// Checks whether two given nodes have same attributes.\n//\n// @private\n// @param {module:engine/model/node~Node} nodeA Node to check.\n// @param {module:engine/model/node~Node} nodeB Node to check.\n// @returns {Boolean} `true` if nodes have same attributes, `false` otherwise.\nfunction _haveSameAttributes( nodeA, nodeB ) {\n\tconst iteratorA = nodeA.getAttributes();\n\tconst iteratorB = nodeB.getAttributes();\n\n\tfor ( const attr of iteratorA ) {\n\t\tif ( attr[ 1 ] !== nodeB.getAttribute( attr[ 0 ] ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\titeratorB.next();\n\t}\n\n\treturn iteratorB.next().done;\n}\n\n/**\n * Value that can be normalized to an array of {@link module:engine/model/node~Node nodes}.\n *\n * Non-arrays are normalized as follows:\n * * {@link module:engine/model/node~Node Node} is left as is,\n * * {@link module:engine/model/textproxy~TextProxy TextProxy} and `String` are normalized to {@link module:engine/model/text~Text Text},\n * * {@link module:engine/model/nodelist~NodeList NodeList} is normalized to an array containing all nodes that are in that node list,\n * * {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment} is normalized to an array containing all of it's\n * * children.\n *\n * Arrays are processed item by item like non-array values and flattened to one array. Normalization always results in\n * a flat array of {@link module:engine/model/node~Node nodes}. Consecutive text nodes (or items normalized to text nodes) will be\n * merged if they have same attributes.\n *\n * @typedef {module:engine/model/node~Node|module:engine/model/textproxy~TextProxy|String|\n * module:engine/model/nodelist~NodeList|module:engine/model/documentfragment~DocumentFragment|Iterable}\n * module:engine/model/node~NodeSet\n */\n","import baseIsEqual from './_baseIsEqual.js';\n\n/**\n * Performs a deep comparison between two values to determine if they are\n * equivalent.\n *\n * **Note:** This method supports comparing arrays, array buffers, booleans,\n * date objects, error objects, maps, numbers, `Object` objects, regexes,\n * sets, strings, symbols, and typed arrays. `Object` objects are compared\n * by their own, not inherited, enumerable properties. Functions and DOM\n * nodes are compared by strict equality, i.e. `===`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.isEqual(object, other);\n * // => true\n *\n * object === other;\n * // => false\n */\nfunction isEqual(value, other) {\n return baseIsEqual(value, other);\n}\n\nexport default isEqual;\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/attributeoperation\n */\n\nimport Operation from './operation';\nimport Range from '../range';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport { _setAttribute } from './utils';\nimport { isEqual } from 'lodash-es';\n\n/**\n * Operation to change nodes' attribute.\n *\n * Using this class you can add, remove or change value of the attribute.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class AttributeOperation extends Operation {\n\t/**\n\t * Creates an operation that changes, removes or adds attributes.\n\t *\n\t * If only `newValue` is set, attribute will be added on a node. Note that all nodes in operation's range must not\n\t * have an attribute with the same key as the added attribute.\n\t *\n\t * If only `oldValue` is set, then attribute with given key will be removed. Note that all nodes in operation's range\n\t * must have an attribute with that key added.\n\t *\n\t * If both `newValue` and `oldValue` are set, then the operation will change the attribute value. Note that all nodes in\n\t * operation's ranges must already have an attribute with given key and `oldValue` as value\n\t *\n\t * @param {module:engine/model/range~Range} range Range on which the operation should be applied. Must be a flat range.\n\t * @param {String} key Key of an attribute to change or remove.\n\t * @param {*} oldValue Old value of the attribute with given key or `null`, if attribute was not set before.\n\t * @param {*} newValue New value of the attribute with given key or `null`, if operation should remove attribute.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( range, key, oldValue, newValue, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Range on which operation should be applied.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range}\n\t\t */\n\t\tthis.range = range.clone();\n\n\t\t/**\n\t\t * Key of an attribute to change or remove.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.key = key;\n\n\t\t/**\n\t\t * Old value of the attribute with given key or `null`, if attribute was not set before.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.oldValue = oldValue === undefined ? null : oldValue;\n\n\t\t/**\n\t\t * New value of the attribute with given key or `null`, if operation should remove attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.newValue = newValue === undefined ? null : newValue;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\tif ( this.oldValue === null ) {\n\t\t\treturn 'addAttribute';\n\t\t} else if ( this.newValue === null ) {\n\t\t\treturn 'removeAttribute';\n\t\t} else {\n\t\t\treturn 'changeAttribute';\n\t\t}\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new AttributeOperation( this.range, this.key, this.oldValue, this.newValue, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation}\n\t */\n\tgetReversed() {\n\t\treturn new AttributeOperation( this.range, this.key, this.newValue, this.oldValue, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.range = this.range.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tif ( !this.range.isFlat ) {\n\t\t\t/**\n\t\t\t * The range to change is not flat.\n\t\t\t *\n\t\t\t * @error attribute-operation-range-not-flat\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'attribute-operation-range-not-flat: The range to change is not flat.', this );\n\t\t}\n\n\t\tfor ( const item of this.range.getItems( { shallow: true } ) ) {\n\t\t\tif ( this.oldValue !== null && !isEqual( item.getAttribute( this.key ), this.oldValue ) ) {\n\t\t\t\t/**\n\t\t\t\t * Changed node has different attribute value than operation's old attribute value.\n\t\t\t\t *\n\t\t\t\t * @error attribute-operation-wrong-old-value\n\t\t\t\t * @param {module:engine/model/item~Item} item\n\t\t\t\t * @param {String} key\n\t\t\t\t * @param {*} value\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'attribute-operation-wrong-old-value: Changed node has different attribute value than operation\\'s ' +\n\t\t\t\t\t'old attribute value.',\n\t\t\t\t\tthis,\n\t\t\t\t\t{ item, key: this.key, value: this.oldValue }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( this.oldValue === null && this.newValue !== null && item.hasAttribute( this.key ) ) {\n\t\t\t\t/**\n\t\t\t\t * The attribute with given key already exists for the given node.\n\t\t\t\t *\n\t\t\t\t * @error attribute-operation-attribute-exists\n\t\t\t\t * @param {module:engine/model/node~Node} node\n\t\t\t\t * @param {String} key\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'attribute-operation-attribute-exists: The attribute with given key already exists.',\n\t\t\t\t\tthis,\n\t\t\t\t\t{ node: item, key: this.key }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t// If value to set is same as old value, don't do anything.\n\t\tif ( !isEqual( this.oldValue, this.newValue ) ) {\n\t\t\t// Execution.\n\t\t\t_setAttribute( this.range, this.key, this.newValue );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'AttributeOperation';\n\t}\n\n\t/**\n\t * Creates `AttributeOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn new AttributeOperation( Range.fromJSON( json.range, document ), json.key, json.oldValue, json.newValue, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `AttributeOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`\"${ this.key }\": ${ JSON.stringify( this.oldValue ) }` +\n\t// @if CK_DEBUG_ENGINE //\t\t` -> ${ JSON.stringify( this.newValue ) }, ${ this.range }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/detachoperation\n */\n\nimport Operation from './operation';\nimport Range from '../range';\nimport { _remove } from './utils';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// @if CK_DEBUG_ENGINE // const ModelRange = require( '../range' ).default;\n\n/**\n * Operation to permanently remove node from detached root.\n * Note this operation is only a local operation and won't be send to the other clients.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class DetachOperation extends Operation {\n\t/**\n\t * Creates an insert operation.\n\t *\n\t * @param {module:engine/model/position~Position} sourcePosition\n\t * Position before the first {@link module:engine/model/item~Item model item} to move.\n\t * @param {Number} howMany Offset size of moved range. Moved range will start from `sourcePosition` and end at\n\t * `sourcePosition` with offset shifted by `howMany`.\n\t */\n\tconstructor( sourcePosition, howMany ) {\n\t\tsuper( null );\n\n\t\t/**\n\t\t * Position before the first {@link module:engine/model/item~Item model item} to detach.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} #sourcePosition\n\t\t */\n\t\tthis.sourcePosition = sourcePosition.clone();\n\n\t\t/**\n\t\t * Offset size of moved range.\n\t\t *\n\t\t * @member {Number} #howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'detach';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.sourcePosition = this.sourcePosition.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tif ( this.sourcePosition.root.document ) {\n\t\t\t/**\n\t\t\t * Cannot detach document node.\n\t\t\t *\n\t\t\t * @error detach-operation-on-document-node\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'detach-operation-on-document-node: Cannot detach document node.', this );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t_remove( Range._createFromPositionAndShift( this.sourcePosition, this.howMany ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'DetachOperation';\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // const range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany );\n\t// @if CK_DEBUG_ENGINE //\tconst nodes = Array.from( range.getItems() );\n\t// @if CK_DEBUG_ENGINE //\tconst nodeString = nodes.length > 1 ? `[ ${ nodes.length } ]` : nodes[ 0 ];\n\n\t// @if CK_DEBUG_ENGINE //\treturn `DetachOperation( ${ this.baseVersion } ): ${ nodeString } -> ${ range }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/moveoperation\n */\n\nimport Operation from './operation';\nimport Position from '../position';\nimport Range from '../range';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport { _move } from './utils';\n\n// @if CK_DEBUG_ENGINE // const ModelRange = require( '../range' ).default;\n\n/**\n * Operation to move a range of {@link module:engine/model/item~Item model items}\n * to given {@link module:engine/model/position~Position target position}.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class MoveOperation extends Operation {\n\t/**\n\t * Creates a move operation.\n\t *\n\t * @param {module:engine/model/position~Position} sourcePosition\n\t * Position before the first {@link module:engine/model/item~Item model item} to move.\n\t * @param {Number} howMany Offset size of moved range. Moved range will start from `sourcePosition` and end at\n\t * `sourcePosition` with offset shifted by `howMany`.\n\t * @param {module:engine/model/position~Position} targetPosition Position at which moved nodes will be inserted.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( sourcePosition, howMany, targetPosition, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position before the first {@link module:engine/model/item~Item model item} to move.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/moveoperation~MoveOperation#sourcePosition\n\t\t */\n\t\tthis.sourcePosition = sourcePosition.clone();\n\t\t// `'toNext'` because `sourcePosition` is a bit like a start of the moved range.\n\t\tthis.sourcePosition.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Offset size of moved range.\n\t\t *\n\t\t * @member {Number} module:engine/model/operation/moveoperation~MoveOperation#howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\n\t\t/**\n\t\t * Position at which moved nodes will be inserted.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/moveoperation~MoveOperation#targetPosition\n\t\t */\n\t\tthis.targetPosition = targetPosition.clone();\n\t\tthis.targetPosition.stickiness = 'toNone';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\tif ( this.targetPosition.root.rootName == '$graveyard' ) {\n\t\t\treturn 'remove';\n\t\t} else if ( this.sourcePosition.root.rootName == '$graveyard' ) {\n\t\t\treturn 'reinsert';\n\t\t}\n\n\t\treturn 'move';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.sourcePosition, this.howMany, this.targetPosition, this.baseVersion );\n\t}\n\n\t/**\n\t * Returns the start position of the moved range after it got moved. This may be different than\n\t * {@link module:engine/model/operation/moveoperation~MoveOperation#targetPosition} in some cases, i.e. when a range is moved\n\t * inside the same parent but {@link module:engine/model/operation/moveoperation~MoveOperation#targetPosition targetPosition}\n\t * is after {@link module:engine/model/operation/moveoperation~MoveOperation#sourcePosition sourcePosition}.\n\t *\n\t *\t\t vv vv\n\t *\t\tabcdefg ===> adefbcg\n\t *\t\t ^ ^\n\t *\t\t targetPos\tmovedRangeStart\n\t *\t\t offset 6\toffset 4\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetMovedRangeStart() {\n\t\treturn this.targetPosition._getTransformedByDeletion( this.sourcePosition, this.howMany );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation}\n\t */\n\tgetReversed() {\n\t\tconst newTargetPosition = this.sourcePosition._getTransformedByInsertion( this.targetPosition, this.howMany );\n\n\t\treturn new this.constructor( this.getMovedRangeStart(), this.howMany, newTargetPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst sourceElement = this.sourcePosition.parent;\n\t\tconst targetElement = this.targetPosition.parent;\n\t\tconst sourceOffset = this.sourcePosition.offset;\n\t\tconst targetOffset = this.targetPosition.offset;\n\n\t\t// Validate whether move operation has correct parameters.\n\t\t// Validation is pretty complex but move operation is one of the core ways to manipulate the document state.\n\t\t// We expect that many errors might be connected with one of scenarios described below.\n\t\tif ( sourceOffset + this.howMany > sourceElement.maxOffset ) {\n\t\t\t/**\n\t\t\t * The nodes which should be moved do not exist.\n\t\t\t *\n\t\t\t * @error move-operation-nodes-do-not-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'move-operation-nodes-do-not-exist: The nodes which should be moved do not exist.', this\n\t\t\t);\n\t\t} else if ( sourceElement === targetElement && sourceOffset < targetOffset && targetOffset < sourceOffset + this.howMany ) {\n\t\t\t/**\n\t\t\t * Trying to move a range of nodes into the middle of that range.\n\t\t\t *\n\t\t\t * @error move-operation-range-into-itself\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'move-operation-range-into-itself: Trying to move a range of nodes to the inside of that range.', this\n\t\t\t);\n\t\t} else if ( this.sourcePosition.root == this.targetPosition.root ) {\n\t\t\tif ( compareArrays( this.sourcePosition.getParentPath(), this.targetPosition.getParentPath() ) == 'prefix' ) {\n\t\t\t\tconst i = this.sourcePosition.path.length - 1;\n\n\t\t\t\tif ( this.targetPosition.path[ i ] >= sourceOffset && this.targetPosition.path[ i ] < sourceOffset + this.howMany ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Trying to move a range of nodes into one of nodes from that range.\n\t\t\t\t\t *\n\t\t\t\t\t * @error move-operation-node-into-itself\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t'move-operation-node-into-itself: Trying to move a range of nodes into one of nodes from that range.', this\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t_move( Range._createFromPositionAndShift( this.sourcePosition, this.howMany ), this.targetPosition );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.sourcePosition = this.sourcePosition.toJSON();\n\t\tjson.targetPosition = this.targetPosition.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'MoveOperation';\n\t}\n\n\t/**\n\t * Creates `MoveOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst sourcePosition = Position.fromJSON( json.sourcePosition, document );\n\t\tconst targetPosition = Position.fromJSON( json.targetPosition, document );\n\n\t\treturn new this( sourcePosition, json.howMany, targetPosition, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \tconst range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany );\n\n\t// @if CK_DEBUG_ENGINE //\treturn `MoveOperation( ${ this.baseVersion } ): ${ range } -> ${ this.targetPosition }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/insertoperation\n */\n\nimport Operation from './operation';\nimport Position from '../position';\nimport NodeList from '../nodelist';\nimport MoveOperation from './moveoperation';\nimport { _insert, _normalizeNodes } from './utils';\nimport Text from '../text';\nimport Element from '../element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to insert one or more nodes at given position in the model.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class InsertOperation extends Operation {\n\t/**\n\t * Creates an insert operation.\n\t *\n\t * @param {module:engine/model/position~Position} position Position of insertion.\n\t * @param {module:engine/model/node~NodeSet} nodes The list of nodes to be inserted.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( position, nodes, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position of insertion.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/insertoperation~InsertOperation#position\n\t\t */\n\t\tthis.position = position.clone();\n\t\tthis.position.stickiness = 'toNone';\n\n\t\t/**\n\t\t * List of nodes to insert.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/nodelist~NodeList} module:engine/model/operation/insertoperation~InsertOperation#nodeList\n\t\t */\n\t\tthis.nodes = new NodeList( _normalizeNodes( nodes ) );\n\n\t\t/**\n\t\t * Flag deciding how the operation should be transformed. If set to `true`, nodes might get additional attributes\n\t\t * during operational transformation. This happens when the operation insertion position is inside of a range\n\t\t * where attributes have changed.\n\t\t *\n\t\t * @member {Boolean} module:engine/model/operation/insertoperation~InsertOperation#shouldReceiveAttributes\n\t\t */\n\t\tthis.shouldReceiveAttributes = false;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'insert';\n\t}\n\n\t/**\n\t * Total offset size of inserted nodes.\n\t *\n\t * @returns {Number}\n\t */\n\tget howMany() {\n\t\treturn this.nodes.maxOffset;\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/insertoperation~InsertOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\tconst nodes = new NodeList( [ ...this.nodes ].map( node => node._clone( true ) ) );\n\t\tconst insert = new InsertOperation( this.position, nodes, this.baseVersion );\n\n\t\tinsert.shouldReceiveAttributes = this.shouldReceiveAttributes;\n\n\t\treturn insert;\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation}\n\t */\n\tgetReversed() {\n\t\tconst graveyard = this.position.root.document.graveyard;\n\t\tconst gyPosition = new Position( graveyard, [ 0 ] );\n\n\t\treturn new MoveOperation( this.position, this.nodes.maxOffset, gyPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst targetElement = this.position.parent;\n\n\t\tif ( !targetElement || targetElement.maxOffset < this.position.offset ) {\n\t\t\t/**\n\t\t\t * Insertion position is invalid.\n\t\t\t *\n\t\t\t * @error insert-operation-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'insert-operation-position-invalid: Insertion position is invalid.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t// What happens here is that we want original nodes be passed to writer because we want original nodes\n\t\t// to be inserted to the model. But in InsertOperation, we want to keep those nodes as they were added\n\t\t// to the operation, not modified. For example, text nodes can get merged or cropped while Elements can\n\t\t// get children. It is important that InsertOperation has the copy of original nodes in intact state.\n\t\tconst originalNodes = this.nodes;\n\t\tthis.nodes = new NodeList( [ ...originalNodes ].map( node => node._clone( true ) ) );\n\n\t\t_insert( this.position, originalNodes );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.position = this.position.toJSON();\n\t\tjson.nodes = this.nodes.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'InsertOperation';\n\t}\n\n\t/**\n\t * Creates `InsertOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/insertoperation~InsertOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst children = [];\n\n\t\tfor ( const child of json.nodes ) {\n\t\t\tif ( child.name ) {\n\t\t\t\t// If child has name property, it is an Element.\n\t\t\t\tchildren.push( Element.fromJSON( child ) );\n\t\t\t} else {\n\t\t\t\t// Otherwise, it is a Text node.\n\t\t\t\tchildren.push( Text.fromJSON( child ) );\n\t\t\t}\n\t\t}\n\n\t\tconst insert = new InsertOperation( Position.fromJSON( json.position, document ), children, json.baseVersion );\n\t\tinsert.shouldReceiveAttributes = json.shouldReceiveAttributes;\n\n\t\treturn insert;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \tconst nodeString = this.nodes.length > 1 ? `[ ${ this.nodes.length } ]` : this.nodes.getNode( 0 );\n\n\t// @if CK_DEBUG_ENGINE //\treturn `InsertOperation( ${ this.baseVersion } ): ${ nodeString } -> ${ this.position }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/markeroperation\n */\n\nimport Operation from './operation';\nimport Range from '../range';\n\n/**\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class MarkerOperation extends Operation {\n\t/**\n\t * @param {String} name Marker name.\n\t * @param {module:engine/model/range~Range} oldRange Marker range before the change.\n\t * @param {module:engine/model/range~Range} newRange Marker range after the change.\n\t * @param {module:engine/model/markercollection~MarkerCollection} markers Marker collection on which change should be executed.\n\t * @param {Boolean} affectsData Specifies whether the marker operation affects the data produced by the data pipeline\n\t * (is persisted in the editor's data).\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( name, oldRange, newRange, markers, affectsData, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Marker name.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Marker range before the change.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range}\n\t\t */\n\t\tthis.oldRange = oldRange ? oldRange.clone() : null;\n\n\t\t/**\n\t\t * Marker range after the change.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range}\n\t\t */\n\t\tthis.newRange = newRange ? newRange.clone() : null;\n\n\t\t/**\n\t\t * Specifies whether the marker operation affects the data produced by the data pipeline\n\t\t * (is persisted in the editor's data).\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.affectsData = affectsData;\n\n\t\t/**\n\t\t * Marker collection on which change should be executed.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/markercollection~MarkerCollection}\n\t\t */\n\t\tthis._markers = markers;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'marker';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/markeroperation~MarkerOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new MarkerOperation( this.name, this.oldRange, this.newRange, this._markers, this.affectsData, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/markeroperation~MarkerOperation}\n\t */\n\tgetReversed() {\n\t\treturn new MarkerOperation( this.name, this.newRange, this.oldRange, this._markers, this.affectsData, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst type = this.newRange ? '_set' : '_remove';\n\n\t\tthis._markers[ type ]( this.name, this.newRange, true, this.affectsData );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tif ( this.oldRange ) {\n\t\t\tjson.oldRange = this.oldRange.toJSON();\n\t\t}\n\n\t\tif ( this.newRange ) {\n\t\t\tjson.newRange = this.newRange.toJSON();\n\t\t}\n\n\t\tdelete json._markers;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'MarkerOperation';\n\t}\n\n\t/**\n\t * Creates `MarkerOperation` object from deserialized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/markeroperation~MarkerOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn new MarkerOperation(\n\t\t\tjson.name,\n\t\t\tjson.oldRange ? Range.fromJSON( json.oldRange, document ) : null,\n\t\t\tjson.newRange ? Range.fromJSON( json.newRange, document ) : null,\n\t\t\tdocument.model.markers,\n\t\t\tjson.affectsData,\n\t\t\tjson.baseVersion\n\t\t);\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `MarkerOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`\"${ this.name }\": ${ this.oldRange } -> ${ this.newRange }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/renameoperation\n */\n\nimport Operation from './operation';\nimport Element from '../element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Position from '../position';\n\n/**\n * Operation to change element's name.\n *\n * Using this class you can change element's name.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class RenameOperation extends Operation {\n\t/**\n\t * Creates an operation that changes element's name.\n\t *\n\t * @param {module:engine/model/position~Position} position Position before an element to change.\n\t * @param {String} oldName Current name of the element.\n\t * @param {String} newName New name for the element.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( position, oldName, newName, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position before an element to change.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/renameoperation~RenameOperation#position\n\t\t */\n\t\tthis.position = position;\n\t\t// This position sticks to the next node because it is a position before the node that we want to change.\n\t\tthis.position.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Current name of the element.\n\t\t *\n\t\t * @member {String} module:engine/model/operation/renameoperation~RenameOperation#oldName\n\t\t */\n\t\tthis.oldName = oldName;\n\n\t\t/**\n\t\t * New name for the element.\n\t\t *\n\t\t * @member {String} module:engine/model/operation/renameoperation~RenameOperation#newName\n\t\t */\n\t\tthis.newName = newName;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'rename';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/renameoperation~RenameOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new RenameOperation( this.position.clone(), this.oldName, this.newName, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/renameoperation~RenameOperation}\n\t */\n\tgetReversed() {\n\t\treturn new RenameOperation( this.position.clone(), this.newName, this.oldName, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst element = this.position.nodeAfter;\n\n\t\tif ( !( element instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Given position is invalid or node after it is not instance of Element.\n\t\t\t *\n\t\t\t * @error rename-operation-wrong-position\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rename-operation-wrong-position: Given position is invalid or node after it is not an instance of Element.',\n\t\t\t\tthis\n\t\t\t);\n\t\t} else if ( element.name !== this.oldName ) {\n\t\t\t/**\n\t\t\t * Element to change has different name than operation's old name.\n\t\t\t *\n\t\t\t * @error rename-operation-wrong-name\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rename-operation-wrong-name: Element to change has different name than operation\\'s old name.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst element = this.position.nodeAfter;\n\n\t\telement.name = this.newName;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.position = this.position.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'RenameOperation';\n\t}\n\n\t/**\n\t * Creates `RenameOperation` object from deserialized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn new RenameOperation( Position.fromJSON( json.position, document ), json.oldName, json.newName, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `RenameOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`${ this.position }: \"${ this.oldName }\" -> \"${ this.newName }\"`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/rootattributeoperation\n */\n\nimport Operation from './operation';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to change root element's attribute. Using this class you can add, remove or change value of the attribute.\n *\n * This operation is needed, because root elements can't be changed through\n * @link module:engine/model/operation/attributeoperation~AttributeOperation}.\n * It is because {@link module:engine/model/operation/attributeoperation~AttributeOperation}\n * requires a range to change and root element can't\n * be a part of range because every {@link module:engine/model/position~Position} has to be inside a root.\n * {@link module:engine/model/position~Position} can't be created before a root element.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class RootAttributeOperation extends Operation {\n\t/**\n\t * Creates an operation that changes, removes or adds attributes on root element.\n\t *\n\t * @see module:engine/model/operation/attributeoperation~AttributeOperation\n\t * @param {module:engine/model/rootelement~RootElement} root Root element to change.\n\t * @param {String} key Key of an attribute to change or remove.\n\t * @param {*} oldValue Old value of the attribute with given key or `null` if adding a new attribute.\n\t * @param {*} newValue New value to set for the attribute. If `null`, then the operation just removes the attribute.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( root, key, oldValue, newValue, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Root element to change.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/rootelement~RootElement}\n\t\t */\n\t\tthis.root = root;\n\n\t\t/**\n\t\t * Key of an attribute to change or remove.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.key = key;\n\n\t\t/**\n\t\t * Old value of the attribute with given key or `null` if adding a new attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.oldValue = oldValue;\n\n\t\t/**\n\t\t * New value to set for the attribute. If `null`, then the operation just removes the attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.newValue = newValue;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\tif ( this.oldValue === null ) {\n\t\t\treturn 'addRootAttribute';\n\t\t} else if ( this.newValue === null ) {\n\t\t\treturn 'removeRootAttribute';\n\t\t} else {\n\t\t\treturn 'changeRootAttribute';\n\t\t}\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/rootattributeoperation~RootAttributeOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new RootAttributeOperation( this.root, this.key, this.oldValue, this.newValue, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/rootattributeoperation~RootAttributeOperation}\n\t */\n\tgetReversed() {\n\t\treturn new RootAttributeOperation( this.root, this.key, this.newValue, this.oldValue, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tif ( this.root != this.root.root || this.root.is( 'documentFragment' ) ) {\n\t\t\t/**\n\t\t\t * The element to change is not a root element.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-not-a-root\n\t\t\t * @param {module:engine/model/rootelement~RootElement} root\n\t\t\t * @param {String} key\n\t\t\t * @param {*} value\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-not-a-root: The element to change is not a root element.',\n\t\t\t\tthis,\n\t\t\t\t{ root: this.root, key: this.key }\n\t\t\t);\n\t\t}\n\n\t\tif ( this.oldValue !== null && this.root.getAttribute( this.key ) !== this.oldValue ) {\n\t\t\t/**\n\t\t\t * The attribute which should be removed does not exists for the given node.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-wrong-old-value\n\t\t\t * @param {module:engine/model/rootelement~RootElement} root\n\t\t\t * @param {String} key\n\t\t\t * @param {*} value\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-wrong-old-value: Changed node has different attribute value than operation\\'s ' +\n\t\t\t\t'old attribute value.',\n\t\t\t\tthis,\n\t\t\t\t{ root: this.root, key: this.key }\n\t\t\t);\n\t\t}\n\n\t\tif ( this.oldValue === null && this.newValue !== null && this.root.hasAttribute( this.key ) ) {\n\t\t\t/**\n\t\t\t * The attribute with given key already exists for the given node.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-attribute-exists\n\t\t\t * @param {module:engine/model/rootelement~RootElement} root\n\t\t\t * @param {String} key\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-attribute-exists: The attribute with given key already exists.',\n\t\t\t\tthis,\n\t\t\t\t{ root: this.root, key: this.key }\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tif ( this.newValue !== null ) {\n\t\t\tthis.root._setAttribute( this.key, this.newValue );\n\t\t} else {\n\t\t\tthis.root._removeAttribute( this.key );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.root = this.root.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'RootAttributeOperation';\n\t}\n\n\t/**\n\t * Creates RootAttributeOperation object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/rootattributeoperation~RootAttributeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tif ( !document.getRoot( json.root ) ) {\n\t\t\t/**\n\t\t\t * Cannot create RootAttributeOperation for document. Root with specified name does not exist.\n\t\t\t *\n\t\t\t * @error rootattributeoperation-fromjson-no-root\n\t\t\t * @param {String} rootName\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-fromjson-no-root: Cannot create RootAttributeOperation. Root with specified name does not exist.',\n\t\t\t\tthis,\n\t\t\t\t{ rootName: json.root }\n\t\t\t);\n\t\t}\n\n\t\treturn new RootAttributeOperation( document.getRoot( json.root ), json.key, json.oldValue, json.newValue, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `RootAttributeOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`\"${ this.key }\": ${ JSON.stringify( this.oldValue ) }` +\n\t// @if CK_DEBUG_ENGINE //\t\t` -> ${ JSON.stringify( this.newValue ) }, ${ this.root.rootName }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/mergeoperation\n */\n\nimport Operation from './operation';\nimport SplitOperation from './splitoperation';\nimport Position from '../position';\nimport Range from '../range';\nimport { _move } from './utils';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to merge two {@link module:engine/model/element~Element elements}.\n *\n * The merged element is the parent of {@link ~MergeOperation#sourcePosition} and it is merged into the parent of\n * {@link ~MergeOperation#targetPosition}. All nodes from the merged element are moved to {@link ~MergeOperation#targetPosition}.\n *\n * The merged element is moved to the graveyard at {@link ~MergeOperation#graveyardPosition}.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class MergeOperation extends Operation {\n\t/**\n\t * Creates a merge operation.\n\t *\n\t * @param {module:engine/model/position~Position} sourcePosition Position inside the merged element. All nodes from that\n\t * element after that position will be moved to {@link ~#targetPosition}.\n\t * @param {Number} howMany Summary offset size of nodes which will be moved from the merged element to the new parent.\n\t * @param {module:engine/model/position~Position} targetPosition Position which the nodes from the merged elements will be moved to.\n\t * @param {module:engine/model/position~Position} graveyardPosition Position in graveyard to which the merged element will be moved.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( sourcePosition, howMany, targetPosition, graveyardPosition, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position inside the merged element. All nodes from that element after that position will be moved to {@link ~#targetPosition}.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#sourcePosition\n\t\t */\n\t\tthis.sourcePosition = sourcePosition.clone();\n\t\t// This is, and should always remain, the first position in its parent.\n\t\tthis.sourcePosition.stickiness = 'toPrevious';\n\n\t\t/**\n\t\t * Summary offset size of nodes which will be moved from the merged element to the new parent.\n\t\t *\n\t\t * @member {Number} module:engine/model/operation/mergeoperation~MergeOperation#howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\n\t\t/**\n\t\t * Position which the nodes from the merged elements will be moved to.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#targetPosition\n\t\t */\n\t\tthis.targetPosition = targetPosition.clone();\n\t\t// Except of a rare scenario in `MergeOperation` x `MergeOperation` transformation,\n\t\t// this is, and should always remain, the last position in its parent.\n\t\tthis.targetPosition.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Position in graveyard to which the merged element will be moved.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#graveyardPosition\n\t\t */\n\t\tthis.graveyardPosition = graveyardPosition.clone();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'merge';\n\t}\n\n\t/**\n\t * Position before the merged element (which will be deleted).\n\t *\n\t * @readonly\n\t * @type {module:engine/model/position~Position}\n\t */\n\tget deletionPosition() {\n\t\treturn new Position( this.sourcePosition.root, this.sourcePosition.path.slice( 0, -1 ) );\n\t}\n\n\t/**\n\t * Artificial range that contains all the nodes from the merged element that will be moved to {@link ~MergeOperation#sourcePosition}.\n\t * The range starts at {@link ~MergeOperation#sourcePosition} and ends in the same parent, at `POSITIVE_INFINITY` offset.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/range~Range}\n\t */\n\tget movedRange() {\n\t\tconst end = this.sourcePosition.getShiftedBy( Number.POSITIVE_INFINITY );\n\n\t\treturn new Range( this.sourcePosition, end );\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/mergeoperation~MergeOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.sourcePosition, this.howMany, this.targetPosition, this.graveyardPosition, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/splitoperation~SplitOperation}\n\t */\n\tgetReversed() {\n\t\t// Positions in this method are transformed by this merge operation because the split operation bases on\n\t\t// the context after this merge operation happened (because split operation reverses it).\n\t\t// So we need to acknowledge that the merge operation happened and those positions changed a little.\n\t\tconst targetPosition = this.targetPosition._getTransformedByMergeOperation( this );\n\n\t\tconst path = this.sourcePosition.path.slice( 0, -1 );\n\t\tconst insertionPosition = new Position( this.sourcePosition.root, path )._getTransformedByMergeOperation( this );\n\n\t\tconst split = new SplitOperation( targetPosition, this.howMany, this.graveyardPosition, this.baseVersion + 1 );\n\t\tsplit.insertionPosition = insertionPosition;\n\n\t\treturn split;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst sourceElement = this.sourcePosition.parent;\n\t\tconst targetElement = this.targetPosition.parent;\n\n\t\t// Validate whether merge operation has correct parameters.\n\t\tif ( !sourceElement.parent ) {\n\t\t\t/**\n\t\t\t * Merge source position is invalid. The element to be merged must have a parent node.\n\t\t\t *\n\t\t\t * @error merge-operation-source-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'merge-operation-source-position-invalid: Merge source position is invalid.', this );\n\t\t} else if ( !targetElement.parent ) {\n\t\t\t/**\n\t\t\t * Merge target position is invalid. The element to be merged must have a parent node.\n\t\t\t *\n\t\t\t * @error merge-operation-target-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'merge-operation-target-position-invalid: Merge target position is invalid.', this );\n\t\t} else if ( this.howMany != sourceElement.maxOffset ) {\n\t\t\t/**\n\t\t\t * Merge operation specifies wrong number of nodes to move.\n\t\t\t *\n\t\t\t * @error merge-operation-how-many-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'merge-operation-how-many-invalid: Merge operation specifies wrong number of nodes to move.', this );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst mergedElement = this.sourcePosition.parent;\n\t\tconst sourceRange = Range._createIn( mergedElement );\n\n\t\t_move( sourceRange, this.targetPosition );\n\t\t_move( Range._createOn( mergedElement ), this.graveyardPosition );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.sourcePosition = json.sourcePosition.toJSON();\n\t\tjson.targetPosition = json.targetPosition.toJSON();\n\t\tjson.graveyardPosition = json.graveyardPosition.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'MergeOperation';\n\t}\n\n\t/**\n\t * Creates `MergeOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/mergeoperation~MergeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst sourcePosition = Position.fromJSON( json.sourcePosition, document );\n\t\tconst targetPosition = Position.fromJSON( json.targetPosition, document );\n\t\tconst graveyardPosition = Position.fromJSON( json.graveyardPosition, document );\n\n\t\treturn new this( sourcePosition, json.howMany, targetPosition, graveyardPosition, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `MergeOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`${ this.sourcePosition } -> ${ this.targetPosition }` +\n\t// @if CK_DEBUG_ENGINE //\t\t` ( ${ this.howMany } ), ${ this.graveyardPosition }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/splitoperation\n */\n\nimport Operation from './operation';\nimport MergeOperation from './mergeoperation';\nimport Position from '../position';\nimport Range from '../range';\nimport { _insert, _move } from './utils';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to split {@link module:engine/model/element~Element an element} at given\n * {@link module:engine/model/operation/splitoperation~SplitOperation#splitPosition split position} into two elements,\n * both containing a part of the element's original content.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class SplitOperation extends Operation {\n\t/**\n\t * Creates a split operation.\n\t *\n\t * @param {module:engine/model/position~Position} splitPosition Position at which an element should be split.\n\t * @param {Number} howMany Total offset size of elements that are in the split element after `position`.\n\t * @param {module:engine/model/position~Position|null} graveyardPosition Position in the graveyard root before the element which\n\t * should be used as a parent of the nodes after `position`. If it is not set, a copy of the the `position` parent will be used.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( splitPosition, howMany, graveyardPosition, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position at which an element should be split.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/splitoperation~SplitOperation#splitPosition\n\t\t */\n\t\tthis.splitPosition = splitPosition.clone();\n\t\t// Keep position sticking to the next node. This way any new content added at the place where the element is split\n\t\t// will be left in the original element.\n\t\tthis.splitPosition.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Total offset size of elements that are in the split element after `position`.\n\t\t *\n\t\t * @member {Number} module:engine/model/operation/splitoperation~SplitOperation#howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\n\t\t/**\n\t\t * Position at which the clone of split element (or element from graveyard) will be inserted.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/splitoperation~SplitOperation#insertionPosition\n\t\t */\n\t\tthis.insertionPosition = SplitOperation.getInsertionPosition( splitPosition );\n\t\tthis.insertionPosition.stickiness = 'toNone';\n\n\t\t/**\n\t\t * Position in the graveyard root before the element which should be used as a parent of the nodes after `position`.\n\t\t * If it is not set, a copy of the the `position` parent will be used.\n\t\t *\n\t\t * The default behavior is to clone the split element. Element from graveyard is used during undo.\n\t\t *\n\t\t * @member {module:engine/model/position~Position|null} #graveyardPosition\n\t\t */\n\t\tthis.graveyardPosition = graveyardPosition ? graveyardPosition.clone() : null;\n\n\t\tif ( this.graveyardPosition ) {\n\t\t\tthis.graveyardPosition.stickiness = 'toNext';\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'split';\n\t}\n\n\t/**\n\t * Position inside the new clone of a split element.\n\t *\n\t * This is a position where nodes that are after the split position will be moved to.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/position~Position}\n\t */\n\tget moveTargetPosition() {\n\t\tconst path = this.insertionPosition.path.slice();\n\t\tpath.push( 0 );\n\n\t\treturn new Position( this.insertionPosition.root, path );\n\t}\n\n\t/**\n\t * Artificial range that contains all the nodes from the split element that will be moved to the new element.\n\t * The range starts at {@link ~#splitPosition} and ends in the same parent, at `POSITIVE_INFINITY` offset.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/range~Range}\n\t */\n\tget movedRange() {\n\t\tconst end = this.splitPosition.getShiftedBy( Number.POSITIVE_INFINITY );\n\n\t\treturn new Range( this.splitPosition, end );\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/splitoperation~SplitOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\tconst split = new this.constructor( this.splitPosition, this.howMany, this.graveyardPosition, this.baseVersion );\n\t\tsplit.insertionPosition = this.insertionPosition;\n\n\t\treturn split;\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/mergeoperation~MergeOperation}\n\t */\n\tgetReversed() {\n\t\tconst graveyard = this.splitPosition.root.document.graveyard;\n\t\tconst graveyardPosition = new Position( graveyard, [ 0 ] );\n\n\t\treturn new MergeOperation( this.moveTargetPosition, this.howMany, this.splitPosition, graveyardPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst element = this.splitPosition.parent;\n\t\tconst offset = this.splitPosition.offset;\n\n\t\t// Validate whether split operation has correct parameters.\n\t\tif ( !element || element.maxOffset < offset ) {\n\t\t\t/**\n\t\t\t * Split position is invalid.\n\t\t\t *\n\t\t\t * @error split-operation-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-position-invalid: Split position is invalid.', this );\n\t\t} else if ( !element.parent ) {\n\t\t\t/**\n\t\t\t * Cannot split root element.\n\t\t\t *\n\t\t\t * @error split-operation-split-in-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-split-in-root: Cannot split root element.', this );\n\t\t} else if ( this.howMany != element.maxOffset - this.splitPosition.offset ) {\n\t\t\t/**\n\t\t\t * Split operation specifies wrong number of nodes to move.\n\t\t\t *\n\t\t\t * @error split-operation-how-many-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-how-many-invalid: Split operation specifies wrong number of nodes to move.', this );\n\t\t} else if ( this.graveyardPosition && !this.graveyardPosition.nodeAfter ) {\n\t\t\t/**\n\t\t\t * Graveyard position invalid.\n\t\t\t *\n\t\t\t * @error split-operation-graveyard-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-graveyard-position-invalid: Graveyard position invalid.', this );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst splitElement = this.splitPosition.parent;\n\n\t\tif ( this.graveyardPosition ) {\n\t\t\t_move( Range._createFromPositionAndShift( this.graveyardPosition, 1 ), this.insertionPosition );\n\t\t} else {\n\t\t\tconst newElement = splitElement._clone();\n\n\t\t\t_insert( this.insertionPosition, newElement );\n\t\t}\n\n\t\tconst sourceRange = new Range(\n\t\t\tPosition._createAt( splitElement, this.splitPosition.offset ),\n\t\t\tPosition._createAt( splitElement, splitElement.maxOffset )\n\t\t);\n\n\t\t_move( sourceRange, this.moveTargetPosition );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.splitPosition = this.splitPosition.toJSON();\n\t\tjson.insertionPosition = this.insertionPosition.toJSON();\n\n\t\tif ( this.graveyardPosition ) {\n\t\t\tjson.graveyardPosition = this.graveyardPosition.toJSON();\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'SplitOperation';\n\t}\n\n\t/**\n\t * Helper function that returns a default insertion position basing on given `splitPosition`. The default insertion\n\t * position is after the split element.\n\t *\n\t * @param {module:engine/model/position~Position} splitPosition\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tstatic getInsertionPosition( splitPosition ) {\n\t\tconst path = splitPosition.path.slice( 0, -1 );\n\t\tpath[ path.length - 1 ]++;\n\n\t\treturn new Position( splitPosition.root, path );\n\t}\n\n\t/**\n\t * Creates `SplitOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/splitoperation~SplitOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst splitPosition = Position.fromJSON( json.splitPosition, document );\n\t\tconst insertionPosition = Position.fromJSON( json.insertionPosition, document );\n\t\tconst graveyardPosition = json.graveyardPosition ? Position.fromJSON( json.graveyardPosition, document ) : null;\n\n\t\tconst split = new this( splitPosition, json.howMany, graveyardPosition, json.baseVersion );\n\t\tsplit.insertionPosition = insertionPosition;\n\n\t\treturn split;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `SplitOperation( ${ this.baseVersion } ): ${ this.splitPosition } ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`( ${ this.howMany } ) -> ${ this.insertionPosition }` +\n\t// @if CK_DEBUG_ENGINE //\t\t`${ this.graveyardPosition ? ' with ' + this.graveyardPosition : '' }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/rootelement\n */\n\nimport Element from './element';\n\n/**\n * Type of {@link module:engine/model/element~Element} that is a root of a model tree.\n * @extends module:engine/model/element~Element\n */\nexport default class RootElement extends Element {\n\t/**\n\t * Creates root element.\n\t *\n\t * @param {module:engine/model/document~Document} doc Document that is an owner of this root.\n\t * @param {String} name Node name.\n\t * @param {String} [rootName='main'] Unique root name used to identify this root\n\t * element by {@link module:engine/model/document~Document}.\n\t */\n\tconstructor( doc, name, rootName = 'main' ) {\n\t\tsuper( name );\n\n\t\t/**\n\t\t * Document that is an owner of this root.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/document~Document}\n\t\t */\n\t\tthis._doc = doc;\n\n\t\t/**\n\t\t * Unique root name used to identify this root element by {@link module:engine/model/document~Document}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.rootName = rootName;\n\t}\n\n\t/**\n\t * {@link module:engine/model/document~Document Document} that owns this root element.\n\t *\n\t * In contrary, to {@link module:engine/model/node~Node node}, root element always have a `document`.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/document~Document|null}\n\t */\n\tget document() {\n\t\treturn this._doc;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\trootElement.is( 'rootElement' ); // -> true\n\t *\t\trootElement.is( 'element' ); // -> true\n\t *\t\trootElement.is( 'node' ); // -> true\n\t *\t\trootElement.is( 'model:rootElement' ); // -> true\n\t *\t\trootElement.is( 'model:element' ); // -> true\n\t *\t\trootElement.is( 'model:node' ); // -> true\n\t *\n\t *\t\trootElement.is( 'view:element' ); // -> false\n\t *\t\trootElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an element, you can also check its\n\t * {@link module:engine/model/element~Element#name name}:\n\t *\n\t *\t\trootElement.is( '$root' ); // -> true if this is a $root element\n\t *\t\trootElement.is( 'rootElement', '$root' ); // -> same as above\n\t *\t\ttext.is( '$root' ); -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check when `name` parameter is present.\n\t * Otherwise, it acts like the `name` parameter.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name ) {\n\t\tconst cutType = type.replace( 'model:', '' );\n\t\tif ( !name ) {\n\t\t\treturn cutType == 'rootElement' || super.is( type );\n\t\t} else {\n\t\t\treturn ( cutType == 'rootElement' && name == this.name ) || super.is( type, name );\n\t\t}\n\t}\n\n\t/**\n\t * Converts `RootElement` instance to `String` containing it's name.\n\t *\n\t * @returns {String} `RootElement` instance converted to `String`.\n\t */\n\ttoJSON() {\n\t\treturn this.rootName;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn this.rootName;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelRootElement: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/writer\n */\n\nimport AttributeOperation from './operation/attributeoperation';\nimport DetachOperation from './operation/detachoperation';\nimport InsertOperation from './operation/insertoperation';\nimport MarkerOperation from './operation/markeroperation';\nimport MoveOperation from './operation/moveoperation';\nimport RenameOperation from './operation/renameoperation';\nimport RootAttributeOperation from './operation/rootattributeoperation';\nimport SplitOperation from './operation/splitoperation';\nimport MergeOperation from './operation/mergeoperation';\n\nimport DocumentFragment from './documentfragment';\nimport Text from './text';\nimport Element from './element';\nimport RootElement from './rootelement';\nimport Position from './position';\nimport Range from './range.js';\nimport DocumentSelection from './documentselection';\n\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * The model can only be modified by using the writer. It should be used whenever you want to create a node, modify\n * child nodes, attributes or text, set the selection's position and its attributes.\n *\n * The instance of the writer is only available in the {@link module:engine/model/model~Model#change `change()`} or\n * {@link module:engine/model/model~Model#enqueueChange `enqueueChange()`}.\n *\n *\t\tmodel.change( writer => {\n *\t\t\twriter.insertText( 'foo', paragraph, 'end' );\n *\t\t} );\n *\n * Note that the writer should never be stored and used outside of the `change()` and\n * `enqueueChange()` blocks.\n *\n * Note that writer's methods do not check the {@link module:engine/model/schema~Schema}. It is possible\n * to create incorrect model structures by using the writer. Read more about in\n * {@glink framework/guides/deep-dive/schema#who-checks-the-schema \"Who checks the schema?\"}.\n *\n * @see module:engine/model/model~Model#change\n * @see module:engine/model/model~Model#enqueueChange\n */\nexport default class Writer {\n\t/**\n\t * Creates a writer instance.\n\t *\n\t * **Note:** It is not recommended to use it directly. Use {@link module:engine/model/model~Model#change `Model#change()`} or\n\t * {@link module:engine/model/model~Model#enqueueChange `Model#enqueueChange()`} instead.\n\t *\n\t * @protected\n\t * @param {module:engine/model/model~Model} model\n\t * @param {module:engine/model/batch~Batch} batch\n\t */\n\tconstructor( model, batch ) {\n\t\t/**\n\t\t * Instance of the model on which this writer operates.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * The batch to which this writer will add changes.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/batch~Batch}\n\t\t */\n\t\tthis.batch = batch;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/model/text~Text text node}.\n\t *\n\t *\t\twriter.createText( 'foo' );\n\t *\t\twriter.createText( 'foo', { bold: true } );\n\t *\n\t * @param {String} data Text data.\n\t * @param {Object} [attributes] Text attributes.\n\t * @returns {module:engine/model/text~Text} Created text node.\n\t */\n\tcreateText( data, attributes ) {\n\t\treturn new Text( data, attributes );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/model/element~Element element}.\n\t *\n\t *\t\twriter.createElement( 'paragraph' );\n\t *\t\twriter.createElement( 'paragraph', { alignment: 'center' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @returns {module:engine/model/element~Element} Created element.\n\t */\n\tcreateElement( name, attributes ) {\n\t\treturn new Element( name, attributes );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/model/documentfragment~DocumentFragment document fragment}.\n\t *\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Created document fragment.\n\t */\n\tcreateDocumentFragment() {\n\t\treturn new DocumentFragment();\n\t}\n\n\t/**\n\t * Inserts item on given position.\n\t *\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\twriter.insert( paragraph, position );\n\t *\n\t * Instead of using position you can use parent and offset:\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\twriter.insert( text, paragraph, 5 );\n\t *\n\t * You can also use `end` instead of the offset to insert at the end:\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\twriter.insert( text, paragraph, 'end' );\n\t *\n\t * Or insert before or after another element:\n\t *\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\twriter.insert( paragraph, anotherParagraph, 'after' );\n\t *\n\t * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.\n\t *\n\t * Note that if the item already has parent it will be removed from the previous parent.\n\t *\n\t * Note that you cannot re-insert a node from a document to a different document or a document fragment. In this case,\n\t * `model-writer-insert-forbidden-move` is thrown.\n\t *\n\t * If you want to move {@link module:engine/model/range~Range range} instead of an\n\t * {@link module:engine/model/item~Item item} use {@link module:engine/model/writer~Writer#move `Writer#move()`}.\n\t *\n\t * **Note:** For a paste-like content insertion mechanism see\n\t * {@link module:engine/model/model~Model#insertContent `model.insertContent()`}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/documentfragment~DocumentFragment} item Item or document\n\t * fragment to insert.\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * second parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tinsert( item, itemOrPosition, offset = 0 ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( item instanceof Text && item.data == '' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst position = Position._createAt( itemOrPosition, offset );\n\n\t\t// If item has a parent already.\n\t\tif ( item.parent ) {\n\t\t\t// We need to check if item is going to be inserted within the same document.\n\t\t\tif ( isSameTree( item.root, position.root ) ) {\n\t\t\t\t// If it's we just need to move it.\n\t\t\t\tthis.move( Range._createOn( item ), position );\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// If it isn't the same root.\n\t\t\telse {\n\t\t\t\tif ( item.root.document ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Cannot move a node from a document to a different tree.\n\t\t\t\t\t * It is forbidden to move a node that was already in a document outside of it.\n\t\t\t\t\t *\n\t\t\t\t\t * @error model-writer-insert-forbidden-move\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t'model-writer-insert-forbidden-move: ' +\n\t\t\t\t\t\t'Cannot move a node from a document to a different tree. ' +\n\t\t\t\t\t\t'It is forbidden to move a node that was already in a document outside of it.',\n\t\t\t\t\t\tthis\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Move between two different document fragments or from document fragment to a document is possible.\n\t\t\t\t\t// In that case, remove the item from it's original parent.\n\t\t\t\t\tthis.remove( item );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst version = position.root.document ? position.root.document.version : null;\n\n\t\tconst insert = new InsertOperation( position, item, version );\n\n\t\tif ( item instanceof Text ) {\n\t\t\tinsert.shouldReceiveAttributes = true;\n\t\t}\n\n\t\tthis.batch.addOperation( insert );\n\t\tthis.model.applyOperation( insert );\n\n\t\t// When element is a DocumentFragment we need to move its markers to Document#markers.\n\t\tif ( item instanceof DocumentFragment ) {\n\t\t\tfor ( const [ markerName, markerRange ] of item.markers ) {\n\t\t\t\t// We need to migrate marker range from DocumentFragment to Document.\n\t\t\t\tconst rangeRootPosition = Position._createAt( markerRange.root, 0 );\n\t\t\t\tconst range = new Range(\n\t\t\t\t\tmarkerRange.start._getCombined( rangeRootPosition, position ),\n\t\t\t\t\tmarkerRange.end._getCombined( rangeRootPosition, position )\n\t\t\t\t);\n\n\t\t\t\tconst options = { range, usingOperation: true, affectsData: true };\n\n\t\t\t\tif ( this.model.markers.has( markerName ) ) {\n\t\t\t\t\tthis.updateMarker( markerName, options );\n\t\t\t\t} else {\n\t\t\t\t\tthis.addMarker( markerName, options );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates and inserts text on given position. You can optionally set text attributes:\n\t *\n\t *\t\twriter.insertText( 'foo', position );\n\t *\t\twriter.insertText( 'foo', { bold: true }, position );\n\t *\n\t * Instead of using position you can use parent and offset or define that text should be inserted at the end\n\t * or before or after other node:\n\t *\n\t *\t\t// Inserts 'foo' in paragraph, at offset 5:\n\t *\t\twriter.insertText( 'foo', paragraph, 5 );\n\t *\t\t// Inserts 'foo' at the end of a paragraph:\n\t *\t\twriter.insertText( 'foo', paragraph, 'end' );\n\t *\t\t// Inserts 'foo' after an image:\n\t *\t\twriter.insertText( 'foo', image, 'after' );\n\t *\n\t * These parameters work in the same way as {@link #createPositionAt `writer.createPositionAt()`}.\n\t *\n\t * @param {String} data Text data.\n\t * @param {Object} [attributes] Text attributes.\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * third parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tinsertText( text, attributes, itemOrPosition, offset ) {\n\t\tif ( attributes instanceof DocumentFragment || attributes instanceof Element || attributes instanceof Position ) {\n\t\t\tthis.insert( this.createText( text ), attributes, itemOrPosition );\n\t\t} else {\n\t\t\tthis.insert( this.createText( text, attributes ), itemOrPosition, offset );\n\t\t}\n\t}\n\n\t/**\n\t * Creates and inserts element on given position. You can optionally set attributes:\n\t *\n\t *\t\twriter.insertElement( 'paragraph', position );\n\t *\t\twriter.insertElement( 'paragraph', { alignment: 'center' }, position );\n\t *\n\t * Instead of using position you can use parent and offset or define that text should be inserted at the end\n\t * or before or after other node:\n\t *\n\t *\t\t// Inserts paragraph in the root at offset 5:\n\t *\t\twriter.insertElement( 'paragraph', root, 5 );\n\t *\t\t// Inserts paragraph at the end of a blockquote:\n\t *\t\twriter.insertElement( 'paragraph', blockquote, 'end' );\n\t *\t\t// Inserts after an image:\n\t *\t\twriter.insertElement( 'paragraph', image, 'after' );\n\t *\n\t * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * third parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tinsertElement( name, attributes, itemOrPosition, offset ) {\n\t\tif ( attributes instanceof DocumentFragment || attributes instanceof Element || attributes instanceof Position ) {\n\t\t\tthis.insert( this.createElement( name ), attributes, itemOrPosition );\n\t\t} else {\n\t\t\tthis.insert( this.createElement( name, attributes ), itemOrPosition, offset );\n\t\t}\n\t}\n\n\t/**\n\t * Inserts item at the end of the given parent.\n\t *\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\twriter.append( paragraph, root );\n\t *\n\t * Note that if the item already has parent it will be removed from the previous parent.\n\t *\n\t * If you want to move {@link module:engine/model/range~Range range} instead of an\n\t * {@link module:engine/model/item~Item item} use {@link module:engine/model/writer~Writer#move `Writer#move()`}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/documentfragment~DocumentFragment}\n\t * item Item or document fragment to insert.\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} parent\n\t */\n\tappend( item, parent ) {\n\t\tthis.insert( item, parent, 'end' );\n\t}\n\n\t/**\n\t * Creates text node and inserts it at the end of the parent. You can optionally set text attributes:\n\t *\n\t *\t\twriter.appendText( 'foo', paragraph );\n\t *\t\twriter.appendText( 'foo', { bold: true }, paragraph );\n\t *\n\t * @param {String} text Text data.\n\t * @param {Object} [attributes] Text attributes.\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} parent\n\t */\n\tappendText( text, attributes, parent ) {\n\t\tif ( attributes instanceof DocumentFragment || attributes instanceof Element ) {\n\t\t\tthis.insert( this.createText( text ), attributes, 'end' );\n\t\t} else {\n\t\t\tthis.insert( this.createText( text, attributes ), parent, 'end' );\n\t\t}\n\t}\n\n\t/**\n\t * Creates element and inserts it at the end of the parent. You can optionally set attributes:\n\t *\n\t *\t\twriter.appendElement( 'paragraph', root );\n\t *\t\twriter.appendElement( 'paragraph', { alignment: 'center' }, root );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} parent\n\t */\n\tappendElement( name, attributes, parent ) {\n\t\tif ( attributes instanceof DocumentFragment || attributes instanceof Element ) {\n\t\t\tthis.insert( this.createElement( name ), attributes, 'end' );\n\t\t} else {\n\t\t\tthis.insert( this.createElement( name, attributes ), parent, 'end' );\n\t\t}\n\t}\n\n\t/**\n\t * Sets value of the attribute with given key on a {@link module:engine/model/item~Item model item}\n\t * or on a {@link module:engine/model/range~Range range}.\n\t *\n\t * @param {String} key Attribute key.\n\t * @param {*} value Attribute new value.\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange\n\t * Model item or range on which the attribute will be set.\n\t */\n\tsetAttribute( key, value, itemOrRange ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( itemOrRange instanceof Range ) {\n\t\t\tconst ranges = itemOrRange.getMinimalFlatRanges();\n\n\t\t\tfor ( const range of ranges ) {\n\t\t\t\tsetAttributeOnRange( this, key, value, range );\n\t\t\t}\n\t\t} else {\n\t\t\tsetAttributeOnItem( this, key, value, itemOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Sets values of attributes on a {@link module:engine/model/item~Item model item}\n\t * or on a {@link module:engine/model/range~Range range}.\n\t *\n\t *\t\twriter.setAttributes( {\n\t *\t\t\tbold: true,\n\t *\t\t\titalic: true\n\t *\t\t}, range );\n\t *\n\t * @param {Object} attributes Attributes keys and values.\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange\n\t * Model item or range on which the attributes will be set.\n\t */\n\tsetAttributes( attributes, itemOrRange ) {\n\t\tfor ( const [ key, val ] of toMap( attributes ) ) {\n\t\t\tthis.setAttribute( key, val, itemOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Removes an attribute with given key from a {@link module:engine/model/item~Item model item}\n\t * or from a {@link module:engine/model/range~Range range}.\n\t *\n\t * @param {String} key Attribute key.\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange\n\t * Model item or range from which the attribute will be removed.\n\t */\n\tremoveAttribute( key, itemOrRange ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( itemOrRange instanceof Range ) {\n\t\t\tconst ranges = itemOrRange.getMinimalFlatRanges();\n\n\t\t\tfor ( const range of ranges ) {\n\t\t\t\tsetAttributeOnRange( this, key, null, range );\n\t\t\t}\n\t\t} else {\n\t\t\tsetAttributeOnItem( this, key, null, itemOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Removes all attributes from all elements in the range or from the given item.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange\n\t * Model item or range from which all attributes will be removed.\n\t */\n\tclearAttributes( itemOrRange ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst removeAttributesFromItem = item => {\n\t\t\tfor ( const attribute of item.getAttributeKeys() ) {\n\t\t\t\tthis.removeAttribute( attribute, item );\n\t\t\t}\n\t\t};\n\n\t\tif ( !( itemOrRange instanceof Range ) ) {\n\t\t\tremoveAttributesFromItem( itemOrRange );\n\t\t} else {\n\t\t\tfor ( const item of itemOrRange.getItems() ) {\n\t\t\t\tremoveAttributesFromItem( item );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Moves all items in the source range to the target position.\n\t *\n\t *\t\twriter.move( sourceRange, targetPosition );\n\t *\n\t * Instead of the target position you can use parent and offset or define that range should be moved to the end\n\t * or before or after chosen item:\n\t *\n\t *\t\t// Moves all items in the range to the paragraph at offset 5:\n\t *\t\twriter.move( sourceRange, paragraph, 5 );\n\t *\t\t// Moves all items in the range to the end of a blockquote:\n\t *\t\twriter.move( sourceRange, blockquote, 'end' );\n\t *\t\t// Moves all items in the range to a position after an image:\n\t *\t\twriter.move( sourceRange, image, 'after' );\n\t *\n\t * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.\n\t *\n\t * Note that items can be moved only within the same tree. It means that you can move items within the same root\n\t * (element or document fragment) or between {@link module:engine/model/document~Document#roots documents roots},\n\t * but you can not move items from document fragment to the document or from one detached element to another. Use\n\t * {@link module:engine/model/writer~Writer#insert} in such cases.\n\t *\n\t * @param {module:engine/model/range~Range} range Source range.\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * second parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tmove( range, itemOrPosition, offset ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( !( range instanceof Range ) ) {\n\t\t\t/**\n\t\t\t * Invalid range to move.\n\t\t\t *\n\t\t\t * @error writer-move-invalid-range\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-move-invalid-range: Invalid range to move.', this );\n\t\t}\n\n\t\tif ( !range.isFlat ) {\n\t\t\t/**\n\t\t\t * Range to move is not flat.\n\t\t\t *\n\t\t\t * @error writer-move-range-not-flat\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-move-range-not-flat: Range to move is not flat.', this );\n\t\t}\n\n\t\tconst position = Position._createAt( itemOrPosition, offset );\n\n\t\t// Do not move anything if the move target is same as moved range start.\n\t\tif ( position.isEqual( range.start ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If part of the marker is removed, create additional marker operation for undo purposes.\n\t\tthis._addOperationForAffectedMarkers( 'move', range );\n\n\t\tif ( !isSameTree( range.root, position.root ) ) {\n\t\t\t/**\n\t\t\t * Range is going to be moved within not the same document. Please use\n\t\t\t * {@link module:engine/model/writer~Writer#insert insert} instead.\n\t\t\t *\n\t\t\t * @error writer-move-different-document\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-move-different-document: Range is going to be moved between different documents.', this );\n\t\t}\n\n\t\tconst version = range.root.document ? range.root.document.version : null;\n\t\tconst operation = new MoveOperation( range.start, range.end.offset - range.start.offset, position, version );\n\n\t\tthis.batch.addOperation( operation );\n\t\tthis.model.applyOperation( operation );\n\t}\n\n\t/**\n\t * Removes given model {@link module:engine/model/item~Item item} or {@link module:engine/model/range~Range range}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange Model item or range to remove.\n\t */\n\tremove( itemOrRange ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst rangeToRemove = itemOrRange instanceof Range ? itemOrRange : Range._createOn( itemOrRange );\n\t\tconst ranges = rangeToRemove.getMinimalFlatRanges().reverse();\n\n\t\tfor ( const flat of ranges ) {\n\t\t\t// If part of the marker is removed, create additional marker operation for undo purposes.\n\t\t\tthis._addOperationForAffectedMarkers( 'move', flat );\n\n\t\t\tapplyRemoveOperation( flat.start, flat.end.offset - flat.start.offset, this.batch, this.model );\n\t\t}\n\t}\n\n\t/**\n\t * Merges two siblings at the given position.\n\t *\n\t * Node before and after the position have to be an element. Otherwise `writer-merge-no-element-before` or\n\t * `writer-merge-no-element-after` error will be thrown.\n\t *\n\t * @param {module:engine/model/position~Position} position Position between merged elements.\n\t */\n\tmerge( position ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst nodeBefore = position.nodeBefore;\n\t\tconst nodeAfter = position.nodeAfter;\n\n\t\t// If part of the marker is removed, create additional marker operation for undo purposes.\n\t\tthis._addOperationForAffectedMarkers( 'merge', position );\n\n\t\tif ( !( nodeBefore instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Node before merge position must be an element.\n\t\t\t *\n\t\t\t * @error writer-merge-no-element-before\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-merge-no-element-before: Node before merge position must be an element.', this );\n\t\t}\n\n\t\tif ( !( nodeAfter instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Node after merge position must be an element.\n\t\t\t *\n\t\t\t * @error writer-merge-no-element-after\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-merge-no-element-after: Node after merge position must be an element.', this );\n\t\t}\n\n\t\tif ( !position.root.document ) {\n\t\t\tthis._mergeDetached( position );\n\t\t} else {\n\t\t\tthis._merge( position );\n\t\t}\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createPositionFromPath `Model#createPositionFromPath()`}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} root Root of the position.\n\t * @param {Array.<Number>} path Position path. See {@link module:engine/model/position~Position#path}.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * See {@link module:engine/model/position~PositionStickiness}.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionFromPath( root, path, stickiness ) {\n\t\treturn this.model.createPositionFromPath( root, path, stickiness );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createPositionAt `Model#createPositionAt()`}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn this.model.createPositionAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createPositionAfter `Model#createPositionAfter()`}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item after which the position should be placed.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn this.model.createPositionAfter( item );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createPositionBefore `Model#createPositionBefore()`}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item after which the position should be placed.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn this.model.createPositionBefore( item );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createRange `Model#createRange()`}.\n\t *\n\t * @param {module:engine/model/position~Position} start Start position.\n\t * @param {module:engine/model/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn this.model.createRange( start, end );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createRangeIn `Model#createRangeIn()`}.\n\t *\n\t * @param {module:engine/model/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn this.model.createRangeIn( element );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createRangeOn `Model#createRangeOn()`}.\n\t *\n\t * @param {module:engine/model/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRangeOn( element ) {\n\t\treturn this.model.createRangeOn( element );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createSelection `Model#createSelection()`}.\n\t *\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @returns {module:engine/model/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn this.model.createSelection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Performs merge action in a detached tree.\n\t *\n\t * @private\n\t * @param {module:engine/model/position~Position} position Position between merged elements.\n\t */\n\t_mergeDetached( position ) {\n\t\tconst nodeBefore = position.nodeBefore;\n\t\tconst nodeAfter = position.nodeAfter;\n\n\t\tthis.move( Range._createIn( nodeAfter ), Position._createAt( nodeBefore, 'end' ) );\n\t\tthis.remove( nodeAfter );\n\t}\n\n\t/**\n\t * Performs merge action in a non-detached tree.\n\t *\n\t * @private\n\t * @param {module:engine/model/position~Position} position Position between merged elements.\n\t */\n\t_merge( position ) {\n\t\tconst targetPosition = Position._createAt( position.nodeBefore, 'end' );\n\t\tconst sourcePosition = Position._createAt( position.nodeAfter, 0 );\n\n\t\tconst graveyard = position.root.document.graveyard;\n\t\tconst graveyardPosition = new Position( graveyard, [ 0 ] );\n\n\t\tconst version = position.root.document.version;\n\n\t\tconst merge = new MergeOperation( sourcePosition, position.nodeAfter.maxOffset, targetPosition, graveyardPosition, version );\n\n\t\tthis.batch.addOperation( merge );\n\t\tthis.model.applyOperation( merge );\n\t}\n\n\t/**\n\t * Renames the given element.\n\t *\n\t * @param {module:engine/model/element~Element} element The element to rename.\n\t * @param {String} newName New element name.\n\t */\n\trename( element, newName ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( !( element instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Trying to rename an object which is not an instance of Element.\n\t\t\t *\n\t\t\t * @error writer-rename-not-element-instance\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'writer-rename-not-element-instance: Trying to rename an object which is not an instance of Element.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tconst version = element.root.document ? element.root.document.version : null;\n\t\tconst renameOperation = new RenameOperation( Position._createBefore( element ), element.name, newName, version );\n\n\t\tthis.batch.addOperation( renameOperation );\n\t\tthis.model.applyOperation( renameOperation );\n\t}\n\n\t/**\n\t * Splits elements starting from the given position and going to the top of the model tree as long as given\n\t * `limitElement` is reached. When `limitElement` is not defined then only the parent of the given position will be split.\n\t *\n\t * The element needs to have a parent. It cannot be a root element nor a document fragment.\n\t * The `writer-split-element-no-parent` error will be thrown if you try to split an element with no parent.\n\t *\n\t * @param {module:engine/model/position~Position} position Position of split.\n\t * @param {module:engine/model/node~Node} [limitElement] Stop splitting when this element will be reached.\n\t * @returns {Object} result Split result.\n\t * @returns {module:engine/model/position~Position} result.position Position between split elements.\n\t * @returns {module:engine/model/range~Range} result.range Range that stars from the end of the first split element and ends\n\t * at the beginning of the first copy element.\n\t */\n\tsplit( position, limitElement ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tlet splitElement = position.parent;\n\n\t\tif ( !splitElement.parent ) {\n\t\t\t/**\n\t\t\t * Element with no parent can not be split.\n\t\t\t *\n\t\t\t * @error writer-split-element-no-parent\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-split-element-no-parent: Element with no parent can not be split.', this );\n\t\t}\n\n\t\t// When limit element is not defined lets set splitElement parent as limit.\n\t\tif ( !limitElement ) {\n\t\t\tlimitElement = splitElement.parent;\n\t\t}\n\n\t\tif ( !position.parent.getAncestors( { includeSelf: true } ).includes( limitElement ) ) {\n\t\t\tthrow new CKEditorError( 'writer-split-invalid-limit-element: Limit element is not a position ancestor.', this );\n\t\t}\n\n\t\t// We need to cache elements that will be created as a result of the first split because\n\t\t// we need to create a range from the end of the first split element to the beginning of the\n\t\t// first copy element. This should be handled by LiveRange but it doesn't work on detached nodes.\n\t\tlet firstSplitElement, firstCopyElement;\n\n\t\tdo {\n\t\t\tconst version = splitElement.root.document ? splitElement.root.document.version : null;\n\t\t\tconst howMany = splitElement.maxOffset - position.offset;\n\t\t\tconst split = new SplitOperation( position, howMany, null, version );\n\n\t\t\tthis.batch.addOperation( split );\n\t\t\tthis.model.applyOperation( split );\n\n\t\t\t// Cache result of the first split.\n\t\t\tif ( !firstSplitElement && !firstCopyElement ) {\n\t\t\t\tfirstSplitElement = splitElement;\n\t\t\t\tfirstCopyElement = position.parent.nextSibling;\n\t\t\t}\n\n\t\t\tposition = this.createPositionAfter( position.parent );\n\t\t\tsplitElement = position.parent;\n\t\t} while ( splitElement !== limitElement );\n\n\t\treturn {\n\t\t\tposition,\n\t\t\trange: new Range( Position._createAt( firstSplitElement, 'end' ), Position._createAt( firstCopyElement, 0 ) )\n\t\t};\n\t}\n\n\t/**\n\t * Wraps the given range with the given element or with a new element (if a string was passed).\n\t *\n\t * **Note:** range to wrap should be a \"flat range\" (see {@link module:engine/model/range~Range#isFlat `Range#isFlat`}).\n\t * If not, an error will be thrown.\n\t *\n\t * @param {module:engine/model/range~Range} range Range to wrap.\n\t * @param {module:engine/model/element~Element|String} elementOrString Element or name of element to wrap the range with.\n\t */\n\twrap( range, elementOrString ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( !range.isFlat ) {\n\t\t\t/**\n\t\t\t * Range to wrap is not flat.\n\t\t\t *\n\t\t\t * @error writer-wrap-range-not-flat\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-wrap-range-not-flat: Range to wrap is not flat.', this );\n\t\t}\n\n\t\tconst element = elementOrString instanceof Element ? elementOrString : new Element( elementOrString );\n\n\t\tif ( element.childCount > 0 ) {\n\t\t\t/**\n\t\t\t * Element to wrap with is not empty.\n\t\t\t *\n\t\t\t * @error writer-wrap-element-not-empty\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-wrap-element-not-empty: Element to wrap with is not empty.', this );\n\t\t}\n\n\t\tif ( element.parent !== null ) {\n\t\t\t/**\n\t\t\t * Element to wrap with is already attached to a tree model.\n\t\t\t *\n\t\t\t * @error writer-wrap-element-attached\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-wrap-element-attached: Element to wrap with is already attached to tree model.', this );\n\t\t}\n\n\t\tthis.insert( element, range.start );\n\n\t\t// Shift the range-to-wrap because we just inserted an element before that range.\n\t\tconst shiftedRange = new Range( range.start.getShiftedBy( 1 ), range.end.getShiftedBy( 1 ) );\n\n\t\tthis.move( shiftedRange, Position._createAt( element, 0 ) );\n\t}\n\n\t/**\n\t * Unwraps children of the given element – all its children are moved before it and then the element is removed.\n\t * Throws error if you try to unwrap an element which does not have a parent.\n\t *\n\t * @param {module:engine/model/element~Element} element Element to unwrap.\n\t */\n\tunwrap( element ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( element.parent === null ) {\n\t\t\t/**\n\t\t\t * Trying to unwrap an element which has no parent.\n\t\t\t *\n\t\t\t * @error writer-unwrap-element-no-parent\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-unwrap-element-no-parent: Trying to unwrap an element which has no parent.', this );\n\t\t}\n\n\t\tthis.move( Range._createIn( element ), this.createPositionAfter( element ) );\n\t\tthis.remove( element );\n\t}\n\n\t/**\n\t * Adds a {@link module:engine/model/markercollection~Marker marker}. Marker is a named range, which tracks\n\t * changes in the document and updates its range automatically, when model tree changes.\n\t *\n\t * As the first parameter you can set marker name.\n\t *\n\t * The required `options.usingOperation` parameter lets you decide if the marker should be managed by operations or not. See\n\t * {@link module:engine/model/markercollection~Marker marker class description} to learn about the difference between\n\t * markers managed by operations and not-managed by operations.\n\t *\n\t * The `options.affectsData` parameter, which defaults to `false`, allows you to define if a marker affects the data. It should be\n\t * `true` when the marker change changes the data returned by the\n\t * {@link module:core/editor/utils/dataapimixin~DataApi#getData `editor.getData()`} method.\n\t * When set to `true` it fires the {@link module:engine/model/document~Document#event:change:data `change:data`} event.\n\t * When set to `false` it fires the {@link module:engine/model/document~Document#event:change `change`} event.\n\t *\n\t * Create marker directly base on marker's name:\n\t *\n\t *\t\taddMarker( markerName, { range, usingOperation: false } );\n\t *\n\t * Create marker using operation:\n\t *\n\t *\t\taddMarker( markerName, { range, usingOperation: true } );\n\t *\n\t * Create marker that affects the editor data:\n\t *\n\t *\t\taddMarker( markerName, { range, usingOperation: false, affectsData: true } );\n\t *\n\t * Note: For efficiency reasons, it's best to create and keep as little markers as possible.\n\t *\n\t * @see module:engine/model/markercollection~Marker\n\t * @param {String} name Name of a marker to create - must be unique.\n\t * @param {Object} options\n\t * @param {Boolean} options.usingOperation Flag indicating that the marker should be added by MarkerOperation.\n\t * See {@link module:engine/model/markercollection~Marker#managedUsingOperations}.\n\t * @param {module:engine/model/range~Range} options.range Marker range.\n\t * @param {Boolean} [options.affectsData=false] Flag indicating that the marker changes the editor data.\n\t * @returns {module:engine/model/markercollection~Marker} Marker that was set.\n\t */\n\taddMarker( name, options ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( !options || typeof options.usingOperation != 'boolean' ) {\n\t\t\t/**\n\t\t\t * The `options.usingOperation` parameter is required when adding a new marker.\n\t\t\t *\n\t\t\t * @error writer-addMarker-no-usingOperation\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'writer-addMarker-no-usingOperation: The options.usingOperation parameter is required when adding a new marker.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tconst usingOperation = options.usingOperation;\n\t\tconst range = options.range;\n\t\tconst affectsData = options.affectsData === undefined ? false : options.affectsData;\n\n\t\tif ( this.model.markers.has( name ) ) {\n\t\t\t/**\n\t\t\t * Marker with provided name already exists.\n\t\t\t *\n\t\t\t * @error writer-addMarker-marker-exists\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-addMarker-marker-exists: Marker with provided name already exists.', this );\n\t\t}\n\n\t\tif ( !range ) {\n\t\t\t/**\n\t\t\t * Range parameter is required when adding a new marker.\n\t\t\t *\n\t\t\t * @error writer-addMarker-no-range\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'writer-addMarker-no-range: Range parameter is required when adding a new marker.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tif ( !usingOperation ) {\n\t\t\treturn this.model.markers._set( name, range, usingOperation, affectsData );\n\t\t}\n\n\t\tapplyMarkerOperation( this, name, null, range, affectsData );\n\n\t\treturn this.model.markers.get( name );\n\t}\n\n\t/**\n\t * Adds, updates or refreshes a {@link module:engine/model/markercollection~Marker marker}. Marker is a named range, which tracks\n\t * changes in the document and updates its range automatically, when model tree changes. Still, it is possible to change the\n\t * marker's range directly using this method.\n\t *\n\t * As the first parameter you can set marker name or instance. If none of them is provided, new marker, with a unique\n\t * name is created and returned.\n\t *\n\t * As the second parameter you can set the new marker data or leave this parameter as empty which will just refresh\n\t * the marker by triggering downcast conversion for it. Refreshing the marker is useful when you want to change\n\t * the marker {@link module:engine/view/element~Element view element} without changing any marker data.\n\t *\n\t * \t\tlet isCommentActive = false;\n\t *\n\t * \t\tmodel.conversion.markerToHighlight( {\n\t * \t\t\tmodel: 'comment',\n\t *\t\t\tview: data => {\n\t *\t\t\t\tconst classes = [ 'comment-marker' ];\n\t *\n\t *\t\t\t\tif ( isCommentActive ) {\n\t *\t\t\t\t\tclasses.push( 'comment-marker--active' );\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\treturn { classes };\n\t *\t\t\t}\n\t * \t\t} );\n\t *\n\t * \t\t// Change the property that indicates if marker is displayed as active or not.\n\t * \t\tisCommentActive = true;\n\t *\n\t * \t\t// And refresh the marker to convert it with additional class.\n\t * \t\tmodel.change( writer => writer.updateMarker( 'comment' ) );\n\t *\n\t * The `options.usingOperation` parameter lets you change if the marker should be managed by operations or not. See\n\t * {@link module:engine/model/markercollection~Marker marker class description} to learn about the difference between\n\t * markers managed by operations and not-managed by operations. It is possible to change this option for an existing marker.\n\t *\n\t * The `options.affectsData` parameter, which defaults to `false`, allows you to define if a marker affects the data. It should be\n\t * `true` when the marker change changes the data returned by\n\t * the {@link module:core/editor/utils/dataapimixin~DataApi#getData `editor.getData()`} method.\n\t * When set to `true` it fires the {@link module:engine/model/document~Document#event:change:data `change:data`} event.\n\t * When set to `false` it fires the {@link module:engine/model/document~Document#event:change `change`} event.\n\t *\n\t * Update marker directly base on marker's name:\n\t *\n\t *\t\tupdateMarker( markerName, { range } );\n\t *\n\t * Update marker using operation:\n\t *\n\t *\t\tupdateMarker( marker, { range, usingOperation: true } );\n\t *\t\tupdateMarker( markerName, { range, usingOperation: true } );\n\t *\n\t * Change marker's option (start using operations to manage it):\n\t *\n\t *\t\tupdateMarker( marker, { usingOperation: true } );\n\t *\n\t * Change marker's option (inform the engine, that the marker does not affect the data anymore):\n\t *\n\t *\t\tupdateMarker( markerName, { affectsData: false } );\n\t *\n\t * @see module:engine/model/markercollection~Marker\n\t * @param {String|module:engine/model/markercollection~Marker} markerOrName Name of a marker to update, or a marker instance.\n\t * @param {Object} [options] If options object is not defined then marker will be refreshed by triggering\n\t * downcast conversion for this marker with the same data.\n\t * @param {module:engine/model/range~Range} [options.range] Marker range to update.\n\t * @param {Boolean} [options.usingOperation] Flag indicated whether the marker should be added by MarkerOperation.\n\t * See {@link module:engine/model/markercollection~Marker#managedUsingOperations}.\n\t * @param {Boolean} [options.affectsData] Flag indicating that the marker changes the editor data.\n\t */\n\tupdateMarker( markerOrName, options ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst markerName = typeof markerOrName == 'string' ? markerOrName : markerOrName.name;\n\t\tconst currentMarker = this.model.markers.get( markerName );\n\n\t\tif ( !currentMarker ) {\n\t\t\t/**\n\t\t\t * Marker with provided name does not exists.\n\t\t\t *\n\t\t\t * @error writer-updateMarker-marker-not-exists\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-updateMarker-marker-not-exists: Marker with provided name does not exists.', this );\n\t\t}\n\n\t\tif ( !options ) {\n\t\t\tthis.model.markers._refresh( currentMarker );\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst hasUsingOperationDefined = typeof options.usingOperation == 'boolean';\n\t\tconst affectsDataDefined = typeof options.affectsData == 'boolean';\n\n\t\t// Use previously defined marker's affectsData if the property is not provided.\n\t\tconst affectsData = affectsDataDefined ? options.affectsData : currentMarker.affectsData;\n\n\t\tif ( !hasUsingOperationDefined && !options.range && !affectsDataDefined ) {\n\t\t\t/**\n\t\t\t * One of the options is required - provide range, usingOperations or affectsData.\n\t\t\t *\n\t\t\t * @error writer-updateMarker-wrong-options\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'writer-updateMarker-wrong-options: One of the options is required - provide range, usingOperations or affectsData.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tconst currentRange = currentMarker.getRange();\n\t\tconst updatedRange = options.range ? options.range : currentRange;\n\n\t\tif ( hasUsingOperationDefined && options.usingOperation !== currentMarker.managedUsingOperations ) {\n\t\t\t// The marker type is changed so it's necessary to create proper operations.\n\t\t\tif ( options.usingOperation ) {\n\t\t\t\t// If marker changes to a managed one treat this as synchronizing existing marker.\n\t\t\t\t// Create `MarkerOperation` with `oldRange` set to `null`, so reverse operation will remove the marker.\n\t\t\t\tapplyMarkerOperation( this, markerName, null, updatedRange, affectsData );\n\t\t\t} else {\n\t\t\t\t// If marker changes to a marker that do not use operations then we need to create additional operation\n\t\t\t\t// that removes that marker first.\n\t\t\t\tapplyMarkerOperation( this, markerName, currentRange, null, affectsData );\n\n\t\t\t\t// Although not managed the marker itself should stay in model and its range should be preserver or changed to passed range.\n\t\t\t\tthis.model.markers._set( markerName, updatedRange, undefined, affectsData );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Marker's type doesn't change so update it accordingly.\n\t\tif ( currentMarker.managedUsingOperations ) {\n\t\t\tapplyMarkerOperation( this, markerName, currentRange, updatedRange, affectsData );\n\t\t} else {\n\t\t\tthis.model.markers._set( markerName, updatedRange, undefined, affectsData );\n\t\t}\n\t}\n\n\t/**\n\t * Removes given {@link module:engine/model/markercollection~Marker marker} or marker with given name.\n\t * The marker is removed accordingly to how it has been created, so if the marker was created using operation,\n\t * it will be destroyed using operation.\n\t *\n\t * @param {module:engine/model/markercollection~Marker|String} markerOrName Marker or marker name to remove.\n\t */\n\tremoveMarker( markerOrName ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst name = typeof markerOrName == 'string' ? markerOrName : markerOrName.name;\n\n\t\tif ( !this.model.markers.has( name ) ) {\n\t\t\t/**\n\t\t\t * Trying to remove marker which does not exist.\n\t\t\t *\n\t\t\t * @error writer-removeMarker-no-marker\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-removeMarker-no-marker: Trying to remove marker which does not exist.', this );\n\t\t}\n\n\t\tconst marker = this.model.markers.get( name );\n\n\t\tif ( !marker.managedUsingOperations ) {\n\t\t\tthis.model.markers._remove( name );\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst oldRange = marker.getRange();\n\n\t\tapplyMarkerOperation( this, name, oldRange, null, marker.affectsData );\n\t}\n\n\t/**\n\t * Sets the document's selection (ranges and direction) to the specified location based on the given\n\t * {@link module:engine/model/selection~Selectable selectable} or creates an empty selection if no arguments were passed.\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t *\t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets selection to other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\twriter.setSelection( otherSelection );\n\t *\n\t *\t\t// Sets selection to the given document selection.\n\t *\t\tconst documentSelection = model.document.selection;\n\t *\t\twriter.setSelection( documentSelection );\n\t *\n\t *\t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPosition( root, path );\n\t *\t\twriter.setSelection( position );\n\t *\n\t *\t\t// Sets collapsed selection at the position of the given node and an offset.\n\t *\t\twriter.setSelection( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of\n \t * that element and ends after the last child of that element.\n\t *\n\t *\t\twriter.setSelection( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\twriter.setSelection( paragraph, 'on' );\n\t *\n\t *\t\t// Removes all selection's ranges.\n\t *\t\twriter.setSelection( null );\n\t *\n\t * `Writer#setSelection()` allow passing additional options (`backward`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\twriter.setSelection( range, { backward: true } );\n\t *\n\t * Throws `writer-incorrect-use` error when the writer is used outside the `change()` block.\n\t *\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t */\n\tsetSelection( selectable, placeOrOffset, options ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tthis.model.document.selection._setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Moves {@link module:engine/model/documentselection~DocumentSelection#focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as\n\t * {@link #createPositionAt `writer.createPositionAt()`} parameters.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tsetSelectionFocus( itemOrPosition, offset ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tthis.model.document.selection._setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Sets attribute(s) on the selection. If attribute with the same key already is set, it's value is overwritten.\n\t *\n\t * Using key and value pair:\n\t *\n\t * \twriter.setSelectionAttribute( 'italic', true );\n\t *\n\t * Using key-value object:\n\t *\n\t * \twriter.setSelectionAttribute( { italic: true, bold: false } );\n\t *\n\t * Using iterable object:\n\t *\n\t * \twriter.setSelectionAttribute( new Map( [ [ 'italic', true ] ] ) );\n\t *\n\t * @param {String|Object|Iterable.<*>} keyOrObjectOrIterable Key of the attribute to set\n\t * or object / iterable of key => value attribute pairs.\n\t * @param {*} [value] Attribute value.\n\t */\n\tsetSelectionAttribute( keyOrObjectOrIterable, value ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( typeof keyOrObjectOrIterable === 'string' ) {\n\t\t\tthis._setSelectionAttribute( keyOrObjectOrIterable, value );\n\t\t} else {\n\t\t\tfor ( const [ key, value ] of toMap( keyOrObjectOrIterable ) ) {\n\t\t\t\tthis._setSelectionAttribute( key, value );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Removes attribute(s) with given key(s) from the selection.\n\t *\n\t * Remove one attribute:\n\t *\n\t *\t\twriter.removeSelectionAttribute( 'italic' );\n\t *\n\t * Remove multiple attributes:\n\t *\n\t *\t\twriter.removeSelectionAttribute( [ 'italic', 'bold' ] );\n\t *\n\t * @param {String|Iterable.<String>} keyOrIterableOfKeys Key of the attribute to remove or an iterable of attribute keys to remove.\n\t */\n\tremoveSelectionAttribute( keyOrIterableOfKeys ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( typeof keyOrIterableOfKeys === 'string' ) {\n\t\t\tthis._removeSelectionAttribute( keyOrIterableOfKeys );\n\t\t} else {\n\t\t\tfor ( const key of keyOrIterableOfKeys ) {\n\t\t\t\tthis._removeSelectionAttribute( key );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Temporarily changes the {@link module:engine/model/documentselection~DocumentSelection#isGravityOverridden gravity}\n\t * of the selection from left to right.\n\t *\n\t * The gravity defines from which direction the selection inherits its attributes. If it's the default left gravity,\n\t * then the selection (after being moved by the user) inherits attributes from its left-hand side.\n\t * This method allows to temporarily override this behavior by forcing the gravity to the right.\n\t *\n\t * For the following model fragment:\n\t *\n\t *\t\t<$text bold=\"true\" linkHref=\"url\">bar[]</$text><$text bold=\"true\">biz</$text>\n\t *\n\t * * Default gravity: selection will have the `bold` and `linkHref` attributes.\n\t * * Overridden gravity: selection will have `bold` attribute.\n\t *\n\t * **Note**: It returns an unique identifier which is required to restore the gravity. It guarantees the symmetry\n\t * of the process.\n\t *\n\t * @returns {String} The unique id which allows restoring the gravity.\n\t */\n\toverrideSelectionGravity() {\n\t\treturn this.model.document.selection._overrideGravity();\n\t}\n\n\t/**\n\t * Restores {@link ~Writer#overrideSelectionGravity} gravity to default.\n\t *\n\t * Restoring the gravity is only possible using the unique identifier returned by\n\t * {@link ~Writer#overrideSelectionGravity}. Note that the gravity remains overridden as long as won't be restored\n\t * the same number of times it was overridden.\n\t *\n\t * @param {String} uid The unique id returned by {@link ~Writer#overrideSelectionGravity}.\n\t */\n\trestoreSelectionGravity( uid ) {\n\t\tthis.model.document.selection._restoreGravity( uid );\n\t}\n\n\t/**\n\t * @private\n\t * @param {String} key Key of the attribute to remove.\n\t * @param {*} value Attribute value.\n\t */\n\t_setSelectionAttribute( key, value ) {\n\t\tconst selection = this.model.document.selection;\n\n\t\t// Store attribute in parent element if the selection is collapsed in an empty node.\n\t\tif ( selection.isCollapsed && selection.anchor.parent.isEmpty ) {\n\t\t\tconst storeKey = DocumentSelection._getStoreAttributeKey( key );\n\n\t\t\tthis.setAttribute( storeKey, value, selection.anchor.parent );\n\t\t}\n\n\t\tselection._setAttribute( key, value );\n\t}\n\n\t/**\n\t * @private\n\t * @param {String} key Key of the attribute to remove.\n\t */\n\t_removeSelectionAttribute( key ) {\n\t\tconst selection = this.model.document.selection;\n\n\t\t// Remove stored attribute from parent element if the selection is collapsed in an empty node.\n\t\tif ( selection.isCollapsed && selection.anchor.parent.isEmpty ) {\n\t\t\tconst storeKey = DocumentSelection._getStoreAttributeKey( key );\n\n\t\t\tthis.removeAttribute( storeKey, selection.anchor.parent );\n\t\t}\n\n\t\tselection._removeAttribute( key );\n\t}\n\n\t/**\n\t * Throws `writer-detached-writer-tries-to-modify-model` error when the writer is used outside of the `change()` block.\n\t *\n\t * @private\n\t */\n\t_assertWriterUsedCorrectly() {\n\t\t/**\n\t\t * Trying to use a writer outside a {@link module:engine/model/model~Model#change `change()`} or\n\t\t * {@link module:engine/model/model~Model#enqueueChange `enqueueChange()`} blocks.\n\t\t *\n\t\t * The writer can only be used inside these blocks which ensures that the model\n\t\t * can only be changed during such \"sessions\".\n\t\t *\n\t\t * @error writer-incorrect-use\n\t\t */\n\t\tif ( this.model._currentWriter !== this ) {\n\t\t\tthrow new CKEditorError( 'writer-incorrect-use: Trying to use a writer outside the change() block.', this );\n\t\t}\n\t}\n\n\t/**\n\t * For given action `type` and `positionOrRange` where the action happens, this function finds all affected markers\n\t * and applies a marker operation with the new marker range equal to the current range. Thanks to this, the marker range\n\t * can be later correctly processed during undo.\n\t *\n\t * @private\n\t * @param {'move'|'merge'} type Writer action type.\n\t * @param {module:engine/model/position~Position|module:engine/model/range~Range} positionOrRange Position or range\n\t * where the writer action happens.\n\t */\n\t_addOperationForAffectedMarkers( type, positionOrRange ) {\n\t\tfor ( const marker of this.model.markers ) {\n\t\t\tif ( !marker.managedUsingOperations ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst markerRange = marker.getRange();\n\t\t\tlet isAffected = false;\n\n\t\t\tif ( type == 'move' ) {\n\t\t\t\tisAffected =\n\t\t\t\t\tpositionOrRange.containsPosition( markerRange.start ) ||\n\t\t\t\t\tpositionOrRange.start.isEqual( markerRange.start ) ||\n\t\t\t\t\tpositionOrRange.containsPosition( markerRange.end ) ||\n\t\t\t\t\tpositionOrRange.end.isEqual( markerRange.end );\n\t\t\t} else {\n\t\t\t\t// if type == 'merge'.\n\t\t\t\tconst elementBefore = positionOrRange.nodeBefore;\n\t\t\t\tconst elementAfter = positionOrRange.nodeAfter;\n\n\t\t\t\t// Start: <p>Foo[</p><p>Bar]</p>\n\t\t\t\t// After merge: <p>Foo[Bar]</p>\n\t\t\t\t// After undoing split: <p>Foo</p><p>[Bar]</p> <-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedInLeftElement = markerRange.start.parent == elementBefore && markerRange.start.isAtEnd;\n\n\t\t\t\t// Start: <p>[Foo</p><p>]Bar</p>\n\t\t\t\t// After merge: <p>[Foo]Bar</p>\n\t\t\t\t// After undoing split: <p>[Foo]</p><p>Bar</p> <-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedInRightElement = markerRange.end.parent == elementAfter && markerRange.end.offset == 0;\n\n\t\t\t\t// Start: <p>[Foo</p>]<p>Bar</p>\n\t\t\t\t// After merge: <p>[Foo]Bar</p>\n\t\t\t\t// After undoing split: <p>[Foo]</p><p>Bar</p> <-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedAfterLeftElement = markerRange.end.nodeAfter == elementAfter;\n\n\t\t\t\t// Start: <p>Foo</p>[<p>Bar]</p>\n\t\t\t\t// After merge: <p>Foo[Bar]</p>\n\t\t\t\t// After undoing split: <p>Foo</p><p>[Bar]</p> <-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedBeforeRightElement = markerRange.start.nodeAfter == elementAfter;\n\n\t\t\t\tisAffected = affectedInLeftElement || affectedInRightElement || affectedAfterLeftElement || affectedBeforeRightElement;\n\t\t\t}\n\n\t\t\tif ( isAffected ) {\n\t\t\t\tthis.updateMarker( marker.name, { range: markerRange } );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Sets given attribute to each node in given range. When attribute value is null then attribute will be removed.\n//\n// Because attribute operation needs to have the same attribute value on the whole range, this function splits\n// the range into smaller parts.\n//\n// Given `range` must be flat.\n//\n// @private\n// @param {module:engine/model/writer~Writer} writer\n// @param {String} key Attribute key.\n// @param {*} value Attribute new value.\n// @param {module:engine/model/range~Range} range Model range on which the attribute will be set.\nfunction setAttributeOnRange( writer, key, value, range ) {\n\tconst model = writer.model;\n\tconst doc = model.document;\n\n\t// Position of the last split, the beginning of the new range.\n\tlet lastSplitPosition = range.start;\n\n\t// Currently position in the scanning range. Because we need value after the position, it is not a current\n\t// position of the iterator but the previous one (we need to iterate one more time to get the value after).\n\tlet position;\n\n\t// Value before the currently position.\n\tlet valueBefore;\n\n\t// Value after the currently position.\n\tlet valueAfter;\n\n\tfor ( const val of range.getWalker( { shallow: true } ) ) {\n\t\tvalueAfter = val.item.getAttribute( key );\n\n\t\t// At the first run of the iterator the position in undefined. We also do not have a valueBefore, but\n\t\t// because valueAfter may be null, valueBefore may be equal valueAfter ( undefined == null ).\n\t\tif ( position && valueBefore != valueAfter ) {\n\t\t\t// if valueBefore == value there is nothing to change, so we add operation only if these values are different.\n\t\t\tif ( valueBefore != value ) {\n\t\t\t\taddOperation();\n\t\t\t}\n\n\t\t\tlastSplitPosition = position;\n\t\t}\n\n\t\tposition = val.nextPosition;\n\t\tvalueBefore = valueAfter;\n\t}\n\n\t// Because position in the loop is not the iterator position (see let position comment), the last position in\n\t// the while loop will be last but one position in the range. We need to check the last position manually.\n\tif ( position instanceof Position && position != lastSplitPosition && valueBefore != value ) {\n\t\taddOperation();\n\t}\n\n\tfunction addOperation() {\n\t\tconst range = new Range( lastSplitPosition, position );\n\t\tconst version = range.root.document ? doc.version : null;\n\t\tconst operation = new AttributeOperation( range, key, valueBefore, value, version );\n\n\t\twriter.batch.addOperation( operation );\n\t\tmodel.applyOperation( operation );\n\t}\n}\n\n// Sets given attribute to the given node. When attribute value is null then attribute will be removed.\n//\n// @private\n// @param {module:engine/model/writer~Writer} writer\n// @param {String} key Attribute key.\n// @param {*} value Attribute new value.\n// @param {module:engine/model/item~Item} item Model item on which the attribute will be set.\nfunction setAttributeOnItem( writer, key, value, item ) {\n\tconst model = writer.model;\n\tconst doc = model.document;\n\tconst previousValue = item.getAttribute( key );\n\tlet range, operation;\n\n\tif ( previousValue != value ) {\n\t\tconst isRootChanged = item.root === item;\n\n\t\tif ( isRootChanged ) {\n\t\t\t// If we change attributes of root element, we have to use `RootAttributeOperation`.\n\t\t\tconst version = item.document ? doc.version : null;\n\n\t\t\toperation = new RootAttributeOperation( item, key, previousValue, value, version );\n\t\t} else {\n\t\t\trange = new Range( Position._createBefore( item ), writer.createPositionAfter( item ) );\n\n\t\t\tconst version = range.root.document ? doc.version : null;\n\n\t\t\toperation = new AttributeOperation( range, key, previousValue, value, version );\n\t\t}\n\n\t\twriter.batch.addOperation( operation );\n\t\tmodel.applyOperation( operation );\n\t}\n}\n\n// Creates and applies marker operation to {@link module:engine/model/operation/operation~Operation operation}.\n//\n// @private\n// @param {module:engine/model/writer~Writer} writer\n// @param {String} name Marker name.\n// @param {module:engine/model/range~Range} oldRange Marker range before the change.\n// @param {module:engine/model/range~Range} newRange Marker range after the change.\n// @param {Boolean} affectsData\nfunction applyMarkerOperation( writer, name, oldRange, newRange, affectsData ) {\n\tconst model = writer.model;\n\tconst doc = model.document;\n\n\tconst operation = new MarkerOperation( name, oldRange, newRange, model.markers, affectsData, doc.version );\n\n\twriter.batch.addOperation( operation );\n\tmodel.applyOperation( operation );\n}\n\n// Creates `MoveOperation` or `DetachOperation` that removes `howMany` nodes starting from `position`.\n// The operation will be applied on given model instance and added to given operation instance.\n//\n// @private\n// @param {module:engine/model/position~Position} position Position from which nodes are removed.\n// @param {Number} howMany Number of nodes to remove.\n// @param {Batch} batch Batch to which the operation will be added.\n// @param {module:engine/model/model~Model} model Model instance on which operation will be applied.\nfunction applyRemoveOperation( position, howMany, batch, model ) {\n\tlet operation;\n\n\tif ( position.root.document ) {\n\t\tconst doc = model.document;\n\t\tconst graveyardPosition = new Position( doc.graveyard, [ 0 ] );\n\n\t\toperation = new MoveOperation( position, howMany, graveyardPosition, doc.version );\n\t} else {\n\t\toperation = new DetachOperation( position, howMany );\n\t}\n\n\tbatch.addOperation( operation );\n\tmodel.applyOperation( operation );\n}\n\n// Returns `true` if both root elements are the same element or both are documents root elements.\n//\n// Elements in the same tree can be moved (for instance you can move element form one documents root to another, or\n// within the same document fragment), but when element supposed to be moved from document fragment to the document, or\n// to another document it should be removed and inserted to avoid problems with OT. This is because features like undo or\n// collaboration may track changes on the document but ignore changes on detached fragments and should not get\n// unexpected `move` operation.\nfunction isSameTree( rootA, rootB ) {\n\t// If it is the same root this is the same tree.\n\tif ( rootA === rootB ) {\n\t\treturn true;\n\t}\n\n\t// If both roots are documents root it is operation within the document what we still treat as the same tree.\n\tif ( rootA instanceof RootElement && rootB instanceof RootElement ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/differ\n */\n\nimport Position from './position';\nimport Range from './range';\n\n/**\n * Calculates the difference between two model states.\n *\n * Receives operations that are to be applied on the model document. Marks parts of the model document tree which\n * are changed and saves the state of these elements before the change. Then, it compares saved elements with the\n * changed elements, after all changes are applied on the model document. Calculates the diff between saved\n * elements and new ones and returns a change set.\n */\nexport default class Differ {\n\t/**\n\t * Creates a `Differ` instance.\n\t *\n\t * @param {module:engine/model/markercollection~MarkerCollection} markerCollection Model's marker collection.\n\t */\n\tconstructor( markerCollection ) {\n\t\t/**\n\t\t * Reference to the model's marker collection.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/markercollection~MarkerCollection}\n\t\t */\n\t\tthis._markerCollection = markerCollection;\n\n\t\t/**\n\t\t * A map that stores changes that happened in a given element.\n\t\t *\n\t\t * The keys of the map are references to the model elements.\n\t\t * The values of the map are arrays with changes that were done on this element.\n\t\t *\n\t\t * @private\n\t\t * @type {Map}\n\t\t */\n\t\tthis._changesInElement = new Map();\n\n\t\t/**\n\t\t * A map that stores \"element's children snapshots\". A snapshot is representing children of a given element before\n\t\t * the first change was applied on that element. Snapshot items are objects with two properties: `name`,\n\t\t * containing the element name (or `'$text'` for a text node) and `attributes` which is a map of the node's attributes.\n\t\t *\n\t\t * @private\n\t\t * @type {Map}\n\t\t */\n\t\tthis._elementSnapshots = new Map();\n\n\t\t/**\n\t\t * A map that stores all changed markers.\n\t\t *\n\t\t * The keys of the map are marker names.\n\t\t * The values of the map are objects with the `oldRange` and `newRange` properties. They store the marker range\n\t\t * state before and after the change.\n\t\t *\n\t\t * @private\n\t\t * @type {Map}\n\t\t */\n\t\tthis._changedMarkers = new Map();\n\n\t\t/**\n\t\t * Stores the number of changes that were processed. Used to order the changes chronologically. It is important\n\t\t * when changes are sorted.\n\t\t *\n\t\t * @private\n\t\t * @type {Number}\n\t\t */\n\t\tthis._changeCount = 0;\n\n\t\t/**\n\t\t * For efficiency purposes, `Differ` stores the change set returned by the differ after {@link #getChanges} call.\n\t\t * Cache is reset each time a new operation is buffered. If the cache has not been reset, {@link #getChanges} will\n\t\t * return the cached value instead of calculating it again.\n\t\t *\n\t\t * This property stores those changes that did not take place in graveyard root.\n\t\t *\n\t\t * @private\n\t\t * @type {Array.<Object>|null}\n\t\t */\n\t\tthis._cachedChanges = null;\n\n\t\t/**\n\t\t * For efficiency purposes, `Differ` stores the change set returned by the differ after the {@link #getChanges} call.\n\t\t * The cache is reset each time a new operation is buffered. If the cache has not been reset, {@link #getChanges} will\n\t\t * return the cached value instead of calculating it again.\n\t\t *\n\t\t * This property stores all changes evaluated by `Differ`, including those that took place in the graveyard.\n\t\t *\n\t\t * @private\n\t\t * @type {Array.<Object>|null}\n\t\t */\n\t\tthis._cachedChangesWithGraveyard = null;\n\t}\n\n\t/**\n\t * Informs whether there are any changes buffered in `Differ`.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this._changesInElement.size == 0 && this._changedMarkers.size == 0;\n\t}\n\n\t/**\n\t * Marks given `item` in differ to be \"refreshed\". It means that the item will be marked as removed and inserted in the differ changes\n\t * set, so it will be effectively re-converted when differ changes will be handled by a dispatcher.\n\t *\n\t * @param {module:engine/model/item~Item} item Item to refresh.\n\t */\n\trefreshItem( item ) {\n\t\tif ( this._isInInsertedElement( item.parent ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._markRemove( item.parent, item.startOffset, item.offsetSize );\n\t\tthis._markInsert( item.parent, item.startOffset, item.offsetSize );\n\n\t\tconst range = Range._createOn( item );\n\n\t\tfor ( const marker of this._markerCollection.getMarkersIntersectingRange( range ) ) {\n\t\t\tconst markerRange = marker.getRange();\n\n\t\t\tthis.bufferMarkerChange( marker.name, markerRange, markerRange, marker.affectsData );\n\t\t}\n\n\t\t// Clear cache after each buffered operation as it is no longer valid.\n\t\tthis._cachedChanges = null;\n\t}\n\n\t/**\n\t * Buffers the given operation. An operation has to be buffered before it is executed.\n\t *\n\t * Operation type is checked and it is checked which nodes it will affect. These nodes are then stored in `Differ`\n\t * in the state before the operation is executed.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation An operation to buffer.\n\t */\n\tbufferOperation( operation ) {\n\t\t// Below we take an operation, check its type, then use its parameters in marking (private) methods.\n\t\t// The general rule is to not mark elements inside inserted element. All inserted elements are re-rendered.\n\t\t// Marking changes in them would cause a \"double\" changing then.\n\t\t//\n\t\tswitch ( operation.type ) {\n\t\t\tcase 'insert': {\n\t\t\t\tif ( this._isInInsertedElement( operation.position.parent ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._markInsert( operation.position.parent, operation.position.offset, operation.nodes.maxOffset );\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'addAttribute':\n\t\t\tcase 'removeAttribute':\n\t\t\tcase 'changeAttribute': {\n\t\t\t\tfor ( const item of operation.range.getItems( { shallow: true } ) ) {\n\t\t\t\t\tif ( this._isInInsertedElement( item.parent ) ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._markAttribute( item );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'remove':\n\t\t\tcase 'move':\n\t\t\tcase 'reinsert': {\n\t\t\t\t// When range is moved to the same position then not mark it as a change.\n\t\t\t\t// See: https://github.com/ckeditor/ckeditor5-engine/issues/1664.\n\t\t\t\tif (\n\t\t\t\t\toperation.sourcePosition.isEqual( operation.targetPosition ) ||\n\t\t\t\t\toperation.sourcePosition.getShiftedBy( operation.howMany ).isEqual( operation.targetPosition )\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst sourceParentInserted = this._isInInsertedElement( operation.sourcePosition.parent );\n\t\t\t\tconst targetParentInserted = this._isInInsertedElement( operation.targetPosition.parent );\n\n\t\t\t\tif ( !sourceParentInserted ) {\n\t\t\t\t\tthis._markRemove( operation.sourcePosition.parent, operation.sourcePosition.offset, operation.howMany );\n\t\t\t\t}\n\n\t\t\t\tif ( !targetParentInserted ) {\n\t\t\t\t\tthis._markInsert( operation.targetPosition.parent, operation.getMovedRangeStart().offset, operation.howMany );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'rename': {\n\t\t\t\tif ( this._isInInsertedElement( operation.position.parent ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._markRemove( operation.position.parent, operation.position.offset, 1 );\n\t\t\t\tthis._markInsert( operation.position.parent, operation.position.offset, 1 );\n\n\t\t\t\tconst range = Range._createFromPositionAndShift( operation.position, 1 );\n\n\t\t\t\tfor ( const marker of this._markerCollection.getMarkersIntersectingRange( range ) ) {\n\t\t\t\t\tconst markerRange = marker.getRange();\n\n\t\t\t\t\tthis.bufferMarkerChange( marker.name, markerRange, markerRange, marker.affectsData );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'split': {\n\t\t\t\tconst splitElement = operation.splitPosition.parent;\n\n\t\t\t\t// Mark that children of the split element were removed.\n\t\t\t\tif ( !this._isInInsertedElement( splitElement ) ) {\n\t\t\t\t\tthis._markRemove( splitElement, operation.splitPosition.offset, operation.howMany );\n\t\t\t\t}\n\n\t\t\t\t// Mark that the new element (split copy) was inserted.\n\t\t\t\tif ( !this._isInInsertedElement( operation.insertionPosition.parent ) ) {\n\t\t\t\t\tthis._markInsert( operation.insertionPosition.parent, operation.insertionPosition.offset, 1 );\n\t\t\t\t}\n\n\t\t\t\t// If the split took the element from the graveyard, mark that the element from the graveyard was removed.\n\t\t\t\tif ( operation.graveyardPosition ) {\n\t\t\t\t\tthis._markRemove( operation.graveyardPosition.parent, operation.graveyardPosition.offset, 1 );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'merge': {\n\t\t\t\t// Mark that the merged element was removed.\n\t\t\t\tconst mergedElement = operation.sourcePosition.parent;\n\n\t\t\t\tif ( !this._isInInsertedElement( mergedElement.parent ) ) {\n\t\t\t\t\tthis._markRemove( mergedElement.parent, mergedElement.startOffset, 1 );\n\t\t\t\t}\n\n\t\t\t\t// Mark that the merged element was inserted into graveyard.\n\t\t\t\tconst graveyardParent = operation.graveyardPosition.parent;\n\n\t\t\t\tthis._markInsert( graveyardParent, operation.graveyardPosition.offset, 1 );\n\n\t\t\t\t// Mark that children of merged element were inserted at new parent.\n\t\t\t\tconst mergedIntoElement = operation.targetPosition.parent;\n\n\t\t\t\tif ( !this._isInInsertedElement( mergedIntoElement ) ) {\n\t\t\t\t\tthis._markInsert( mergedIntoElement, operation.targetPosition.offset, mergedElement.maxOffset );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Clear cache after each buffered operation as it is no longer valid.\n\t\tthis._cachedChanges = null;\n\t}\n\n\t/**\n\t * Buffers a marker change.\n\t *\n\t * @param {String} markerName The name of the marker that changed.\n\t * @param {module:engine/model/range~Range|null} oldRange Marker range before the change or `null` if the marker has just\n\t * been created.\n\t * @param {module:engine/model/range~Range|null} newRange Marker range after the change or `null` if the marker was removed.\n\t * @param {Boolean} affectsData Flag indicating whether marker affects the editor data.\n\t */\n\tbufferMarkerChange( markerName, oldRange, newRange, affectsData ) {\n\t\tconst buffered = this._changedMarkers.get( markerName );\n\n\t\tif ( !buffered ) {\n\t\t\tthis._changedMarkers.set( markerName, {\n\t\t\t\toldRange,\n\t\t\t\tnewRange,\n\t\t\t\taffectsData\n\t\t\t} );\n\t\t} else {\n\t\t\tbuffered.newRange = newRange;\n\t\t\tbuffered.affectsData = affectsData;\n\n\t\t\tif ( buffered.oldRange == null && buffered.newRange == null ) {\n\t\t\t\t// The marker is going to be removed (`newRange == null`) but it did not exist before the first buffered change\n\t\t\t\t// (`buffered.oldRange == null`). In this case, do not keep the marker in buffer at all.\n\t\t\t\tthis._changedMarkers.delete( markerName );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns all markers that should be removed as a result of buffered changes.\n\t *\n\t * @returns {Array.<Object>} Markers to remove. Each array item is an object containing the `name` and `range` properties.\n\t */\n\tgetMarkersToRemove() {\n\t\tconst result = [];\n\n\t\tfor ( const [ name, change ] of this._changedMarkers ) {\n\t\t\tif ( change.oldRange != null ) {\n\t\t\t\tresult.push( { name, range: change.oldRange } );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns all markers which should be added as a result of buffered changes.\n\t *\n\t * @returns {Array.<Object>} Markers to add. Each array item is an object containing the `name` and `range` properties.\n\t */\n\tgetMarkersToAdd() {\n\t\tconst result = [];\n\n\t\tfor ( const [ name, change ] of this._changedMarkers ) {\n\t\t\tif ( change.newRange != null ) {\n\t\t\t\tresult.push( { name, range: change.newRange } );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns all markers which changed.\n\t *\n\t * @returns {Array.<Object>}\n\t */\n\tgetChangedMarkers() {\n\t\treturn Array.from( this._changedMarkers ).map( item => (\n\t\t\t{\n\t\t\t\tname: item[ 0 ],\n\t\t\t\tdata: {\n\t\t\t\t\toldRange: item[ 1 ].oldRange,\n\t\t\t\t\tnewRange: item[ 1 ].newRange\n\t\t\t\t}\n\t\t\t}\n\t\t) );\n\t}\n\n\t/**\n\t * Checks whether some of the buffered changes affect the editor data.\n\t *\n\t * Types of changes which affect the editor data:\n\t *\n\t * * model structure changes,\n\t * * attribute changes,\n\t * * changes of markers which were defined as `affectingData`.\n\t *\n\t * @returns {Boolean}\n\t */\n\thasDataChanges() {\n\t\tfor ( const [ , change ] of this._changedMarkers ) {\n\t\t\tif ( change.affectsData ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// If markers do not affect the data, check whether there are some changes in elements.\n\t\treturn this._changesInElement.size > 0;\n\t}\n\n\t/**\n\t * Calculates the diff between the old model tree state (the state before the first buffered operations since the last {@link #reset}\n\t * call) and the new model tree state (actual one). It should be called after all buffered operations are executed.\n\t *\n\t * The diff set is returned as an array of diff items, each describing a change done on the model. The items are sorted by\n\t * the position on which the change happened. If a position {@link module:engine/model/position~Position#isBefore is before}\n\t * another one, it will be on an earlier index in the diff set.\n\t *\n\t * Because calculating the diff is a costly operation, the result is cached. If no new operation was buffered since the\n\t * previous {@link #getChanges} call, the next call will return the cached value.\n\t *\n\t * @param {Object} options Additional options.\n\t * @param {Boolean} [options.includeChangesInGraveyard=false] If set to `true`, also changes that happened\n\t * in the graveyard root will be returned. By default, changes in the graveyard root are not returned.\n\t * @returns {Array.<Object>} Diff between the old and the new model tree state.\n\t */\n\tgetChanges( options = { includeChangesInGraveyard: false } ) {\n\t\t// If there are cached changes, just return them instead of calculating changes again.\n\t\tif ( this._cachedChanges ) {\n\t\t\tif ( options.includeChangesInGraveyard ) {\n\t\t\t\treturn this._cachedChangesWithGraveyard.slice();\n\t\t\t} else {\n\t\t\t\treturn this._cachedChanges.slice();\n\t\t\t}\n\t\t}\n\n\t\t// Will contain returned results.\n\t\tconst diffSet = [];\n\n\t\t// Check all changed elements.\n\t\tfor ( const element of this._changesInElement.keys() ) {\n\t\t\t// Get changes for this element and sort them.\n\t\t\tconst changes = this._changesInElement.get( element ).sort( ( a, b ) => {\n\t\t\t\tif ( a.offset === b.offset ) {\n\t\t\t\t\tif ( a.type != b.type ) {\n\t\t\t\t\t\t// If there are multiple changes at the same position, \"remove\" change should be first.\n\t\t\t\t\t\t// If the order is different, for example, we would first add some nodes and then removed them\n\t\t\t\t\t\t// (instead of the nodes that we should remove).\n\t\t\t\t\t\treturn a.type == 'remove' ? -1 : 1;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn a.offset < b.offset ? -1 : 1;\n\t\t\t} );\n\n\t\t\t// Get children of this element before any change was applied on it.\n\t\t\tconst snapshotChildren = this._elementSnapshots.get( element );\n\t\t\t// Get snapshot of current element's children.\n\t\t\tconst elementChildren = _getChildrenSnapshot( element.getChildren() );\n\n\t\t\t// Generate actions basing on changes done on element.\n\t\t\tconst actions = _generateActionsFromChanges( snapshotChildren.length, changes );\n\n\t\t\tlet i = 0; // Iterator in `elementChildren` array -- iterates through current children of element.\n\t\t\tlet j = 0; // Iterator in `snapshotChildren` array -- iterates through old children of element.\n\n\t\t\t// Process every action.\n\t\t\tfor ( const action of actions ) {\n\t\t\t\tif ( action === 'i' ) {\n\t\t\t\t\t// Generate diff item for this element and insert it into the diff set.\n\t\t\t\t\tdiffSet.push( this._getInsertDiff( element, i, elementChildren[ i ].name ) );\n\n\t\t\t\t\ti++;\n\t\t\t\t} else if ( action === 'r' ) {\n\t\t\t\t\t// Generate diff item for this element and insert it into the diff set.\n\t\t\t\t\tdiffSet.push( this._getRemoveDiff( element, i, snapshotChildren[ j ].name ) );\n\n\t\t\t\t\tj++;\n\t\t\t\t} else if ( action === 'a' ) {\n\t\t\t\t\t// Take attributes from saved and current children.\n\t\t\t\t\tconst elementAttributes = elementChildren[ i ].attributes;\n\t\t\t\t\tconst snapshotAttributes = snapshotChildren[ j ].attributes;\n\t\t\t\t\tlet range;\n\n\t\t\t\t\tif ( elementChildren[ i ].name == '$text' ) {\n\t\t\t\t\t\trange = new Range( Position._createAt( element, i ), Position._createAt( element, i + 1 ) );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst index = element.offsetToIndex( i );\n\t\t\t\t\t\trange = new Range( Position._createAt( element, i ), Position._createAt( element.getChild( index ), 0 ) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Generate diff items for this change (there might be multiple attributes changed and\n\t\t\t\t\t// there is a single diff for each of them) and insert them into the diff set.\n\t\t\t\t\tdiffSet.push( ...this._getAttributesDiff( range, snapshotAttributes, elementAttributes ) );\n\n\t\t\t\t\ti++;\n\t\t\t\t\tj++;\n\t\t\t\t} else {\n\t\t\t\t\t// `action` is 'equal'. Child not changed.\n\t\t\t\t\ti++;\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Then, sort the changes by the position (change at position before other changes is first).\n\t\tdiffSet.sort( ( a, b ) => {\n\t\t\t// If the change is in different root, we don't care much, but we'd like to have all changes in given\n\t\t\t// root \"together\" in the array. So let's just sort them by the root name. It does not matter which root\n\t\t\t// will be processed first.\n\t\t\tif ( a.position.root != b.position.root ) {\n\t\t\t\treturn a.position.root.rootName < b.position.root.rootName ? -1 : 1;\n\t\t\t}\n\n\t\t\t// If change happens at the same position...\n\t\t\tif ( a.position.isEqual( b.position ) ) {\n\t\t\t\t// Keep chronological order of operations.\n\t\t\t\treturn a.changeCount - b.changeCount;\n\t\t\t}\n\n\t\t\t// If positions differ, position \"on the left\" should be earlier in the result.\n\t\t\treturn a.position.isBefore( b.position ) ? -1 : 1;\n\t\t} );\n\n\t\t// Glue together multiple changes (mostly on text nodes).\n\t\tfor ( let i = 1; i < diffSet.length; i++ ) {\n\t\t\tconst prevDiff = diffSet[ i - 1 ];\n\t\t\tconst thisDiff = diffSet[ i ];\n\n\t\t\t// Glue remove changes if they happen on text on same position.\n\t\t\tconst isConsecutiveTextRemove =\n\t\t\t\tprevDiff.type == 'remove' && thisDiff.type == 'remove' &&\n\t\t\t\tprevDiff.name == '$text' && thisDiff.name == '$text' &&\n\t\t\t\tprevDiff.position.isEqual( thisDiff.position );\n\n\t\t\t// Glue insert changes if they happen on text on consecutive fragments.\n\t\t\tconst isConsecutiveTextAdd =\n\t\t\t\tprevDiff.type == 'insert' && thisDiff.type == 'insert' &&\n\t\t\t\tprevDiff.name == '$text' && thisDiff.name == '$text' &&\n\t\t\t\tprevDiff.position.parent == thisDiff.position.parent &&\n\t\t\t\tprevDiff.position.offset + prevDiff.length == thisDiff.position.offset;\n\n\t\t\t// Glue attribute changes if they happen on consecutive fragments and have same key, old value and new value.\n\t\t\tconst isConsecutiveAttributeChange =\n\t\t\t\tprevDiff.type == 'attribute' && thisDiff.type == 'attribute' &&\n\t\t\t\tprevDiff.position.parent == thisDiff.position.parent &&\n\t\t\t\tprevDiff.range.isFlat && thisDiff.range.isFlat &&\n\t\t\t\tprevDiff.position.offset + prevDiff.length == thisDiff.position.offset &&\n\t\t\t\tprevDiff.attributeKey == thisDiff.attributeKey &&\n\t\t\t\tprevDiff.attributeOldValue == thisDiff.attributeOldValue &&\n\t\t\t\tprevDiff.attributeNewValue == thisDiff.attributeNewValue;\n\n\t\t\tif ( isConsecutiveTextRemove || isConsecutiveTextAdd || isConsecutiveAttributeChange ) {\n\t\t\t\tdiffSet[ i - 1 ].length++;\n\n\t\t\t\tif ( isConsecutiveAttributeChange ) {\n\t\t\t\t\tdiffSet[ i - 1 ].range.end = diffSet[ i - 1 ].range.end.getShiftedBy( 1 );\n\t\t\t\t}\n\n\t\t\t\tdiffSet.splice( i, 1 );\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\n\t\t// Remove `changeCount` property from diff items. It is used only for sorting and is internal thing.\n\t\tfor ( const item of diffSet ) {\n\t\t\tdelete item.changeCount;\n\n\t\t\tif ( item.type == 'attribute' ) {\n\t\t\t\tdelete item.position;\n\t\t\t\tdelete item.length;\n\t\t\t}\n\t\t}\n\n\t\tthis._changeCount = 0;\n\n\t\t// Cache changes.\n\t\tthis._cachedChangesWithGraveyard = diffSet.slice();\n\t\tthis._cachedChanges = diffSet.slice().filter( _changesInGraveyardFilter );\n\n\t\tif ( options.includeChangesInGraveyard ) {\n\t\t\treturn this._cachedChangesWithGraveyard;\n\t\t} else {\n\t\t\treturn this._cachedChanges;\n\t\t}\n\t}\n\n\t/**\n\t * Resets `Differ`. Removes all buffered changes.\n\t */\n\treset() {\n\t\tthis._changesInElement.clear();\n\t\tthis._elementSnapshots.clear();\n\t\tthis._changedMarkers.clear();\n\t\tthis._cachedChanges = null;\n\t}\n\n\t/**\n\t * Saves and handles an insert change.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent\n\t * @param {Number} offset\n\t * @param {Number} howMany\n\t */\n\t_markInsert( parent, offset, howMany ) {\n\t\tconst changeItem = { type: 'insert', offset, howMany, count: this._changeCount++ };\n\n\t\tthis._markChange( parent, changeItem );\n\t}\n\n\t/**\n\t * Saves and handles a remove change.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent\n\t * @param {Number} offset\n\t * @param {Number} howMany\n\t */\n\t_markRemove( parent, offset, howMany ) {\n\t\tconst changeItem = { type: 'remove', offset, howMany, count: this._changeCount++ };\n\n\t\tthis._markChange( parent, changeItem );\n\n\t\tthis._removeAllNestedChanges( parent, offset, howMany );\n\t}\n\n\t/**\n\t * Saves and handles an attribute change.\n\t *\n\t * @private\n\t * @param {module:engine/model/item~Item} item\n\t */\n\t_markAttribute( item ) {\n\t\tconst changeItem = { type: 'attribute', offset: item.startOffset, howMany: item.offsetSize, count: this._changeCount++ };\n\n\t\tthis._markChange( item.parent, changeItem );\n\t}\n\n\t/**\n\t * Saves and handles a model change.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent\n\t * @param {Object} changeItem\n\t */\n\t_markChange( parent, changeItem ) {\n\t\t// First, make a snapshot of this parent's children (it will be made only if it was not made before).\n\t\tthis._makeSnapshot( parent );\n\n\t\t// Then, get all changes that already were done on the element (empty array if this is the first change).\n\t\tconst changes = this._getChangesForElement( parent );\n\n\t\t// Then, look through all the changes, and transform them or the new change.\n\t\tthis._handleChange( changeItem, changes );\n\n\t\t// Add the new change.\n\t\tchanges.push( changeItem );\n\n\t\t// Remove incorrect changes. During transformation some change might be, for example, included in another.\n\t\t// In that case, the change will have `howMany` property set to `0` or less. We need to remove those changes.\n\t\tfor ( let i = 0; i < changes.length; i++ ) {\n\t\t\tif ( changes[ i ].howMany < 1 ) {\n\t\t\t\tchanges.splice( i, 1 );\n\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Gets an array of changes that have already been saved for a given element.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} element\n\t * @returns {Array.<Object>}\n\t */\n\t_getChangesForElement( element ) {\n\t\tlet changes;\n\n\t\tif ( this._changesInElement.has( element ) ) {\n\t\t\tchanges = this._changesInElement.get( element );\n\t\t} else {\n\t\t\tchanges = [];\n\n\t\t\tthis._changesInElement.set( element, changes );\n\t\t}\n\n\t\treturn changes;\n\t}\n\n\t/**\n\t * Saves a children snapshot for a given element.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} element\n\t */\n\t_makeSnapshot( element ) {\n\t\tif ( !this._elementSnapshots.has( element ) ) {\n\t\t\tthis._elementSnapshots.set( element, _getChildrenSnapshot( element.getChildren() ) );\n\t\t}\n\t}\n\n\t/**\n\t * For a given newly saved change, compares it with a change already done on the element and modifies the incoming\n\t * change and/or the old change.\n\t *\n\t * @private\n\t * @param {Object} inc Incoming (new) change.\n\t * @param {Array.<Object>} changes An array containing all the changes done on that element.\n\t */\n\t_handleChange( inc, changes ) {\n\t\t// We need a helper variable that will store how many nodes are to be still handled for this change item.\n\t\t// `nodesToHandle` (how many nodes still need to be handled) and `howMany` (how many nodes were affected)\n\t\t// needs to be differentiated.\n\t\t//\n\t\t// This comes up when there are multiple changes that are affected by `inc` change item.\n\t\t//\n\t\t// For example: assume two insert changes: `{ offset: 2, howMany: 1 }` and `{ offset: 5, howMany: 1 }`.\n\t\t// Assume that `inc` change is remove `{ offset: 2, howMany: 2, nodesToHandle: 2 }`.\n\t\t//\n\t\t// Then, we:\n\t\t// - \"forget\" about first insert change (it is \"eaten\" by remove),\n\t\t// - because of that, at the end we will want to remove only one node (`nodesToHandle = 1`),\n\t\t// - but still we have to change offset of the second insert change from `5` to `3`!\n\t\t//\n\t\t// So, `howMany` does not change throughout items transformation and keeps information about how many nodes were affected,\n\t\t// while `nodesToHandle` means how many nodes need to be handled after the change item is transformed by other changes.\n\t\tinc.nodesToHandle = inc.howMany;\n\n\t\tfor ( const old of changes ) {\n\t\t\tconst incEnd = inc.offset + inc.howMany;\n\t\t\tconst oldEnd = old.offset + old.howMany;\n\n\t\t\tif ( inc.type == 'insert' ) {\n\t\t\t\tif ( old.type == 'insert' ) {\n\t\t\t\t\tif ( inc.offset <= old.offset ) {\n\t\t\t\t\t\told.offset += inc.howMany;\n\t\t\t\t\t} else if ( inc.offset < oldEnd ) {\n\t\t\t\t\t\told.howMany += inc.nodesToHandle;\n\t\t\t\t\t\tinc.nodesToHandle = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'remove' ) {\n\t\t\t\t\tif ( inc.offset < old.offset ) {\n\t\t\t\t\t\told.offset += inc.howMany;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'attribute' ) {\n\t\t\t\t\tif ( inc.offset <= old.offset ) {\n\t\t\t\t\t\told.offset += inc.howMany;\n\t\t\t\t\t} else if ( inc.offset < oldEnd ) {\n\t\t\t\t\t\t// This case is more complicated, because attribute change has to be split into two.\n\t\t\t\t\t\t// Example (assume that uppercase and lowercase letters mean different attributes):\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// initial state:\t\tabcxyz\n\t\t\t\t\t\t// attribute change:\taBCXYz\n\t\t\t\t\t\t// incoming insert:\t\taBCfooXYz\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// Change ranges cannot intersect because each item has to be described exactly (it was either\n\t\t\t\t\t\t// not changed, inserted, removed, or its attribute was changed). That's why old attribute\n\t\t\t\t\t\t// change has to be split and both parts has to be handled separately from now on.\n\t\t\t\t\t\tconst howMany = old.howMany;\n\n\t\t\t\t\t\told.howMany = inc.offset - old.offset;\n\n\t\t\t\t\t\t// Add the second part of attribute change to the beginning of processed array so it won't\n\t\t\t\t\t\t// be processed again in this loop.\n\t\t\t\t\t\tchanges.unshift( {\n\t\t\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\t\t\toffset: incEnd,\n\t\t\t\t\t\t\thowMany: howMany - old.howMany,\n\t\t\t\t\t\t\tcount: this._changeCount++\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( inc.type == 'remove' ) {\n\t\t\t\tif ( old.type == 'insert' ) {\n\t\t\t\t\tif ( incEnd <= old.offset ) {\n\t\t\t\t\t\told.offset -= inc.howMany;\n\t\t\t\t\t} else if ( incEnd <= oldEnd ) {\n\t\t\t\t\t\tif ( inc.offset < old.offset ) {\n\t\t\t\t\t\t\tconst intersectionLength = incEnd - old.offset;\n\n\t\t\t\t\t\t\told.offset = inc.offset;\n\n\t\t\t\t\t\t\told.howMany -= intersectionLength;\n\t\t\t\t\t\t\tinc.nodesToHandle -= intersectionLength;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\told.howMany -= inc.nodesToHandle;\n\t\t\t\t\t\t\tinc.nodesToHandle = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( inc.offset <= old.offset ) {\n\t\t\t\t\t\t\tinc.nodesToHandle -= old.howMany;\n\t\t\t\t\t\t\told.howMany = 0;\n\t\t\t\t\t\t} else if ( inc.offset < oldEnd ) {\n\t\t\t\t\t\t\tconst intersectionLength = oldEnd - inc.offset;\n\n\t\t\t\t\t\t\told.howMany -= intersectionLength;\n\t\t\t\t\t\t\tinc.nodesToHandle -= intersectionLength;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'remove' ) {\n\t\t\t\t\tif ( incEnd <= old.offset ) {\n\t\t\t\t\t\told.offset -= inc.howMany;\n\t\t\t\t\t} else if ( inc.offset < old.offset ) {\n\t\t\t\t\t\tinc.nodesToHandle += old.howMany;\n\t\t\t\t\t\told.howMany = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'attribute' ) {\n\t\t\t\t\tif ( incEnd <= old.offset ) {\n\t\t\t\t\t\told.offset -= inc.howMany;\n\t\t\t\t\t} else if ( inc.offset < old.offset ) {\n\t\t\t\t\t\tconst intersectionLength = incEnd - old.offset;\n\n\t\t\t\t\t\told.offset = inc.offset;\n\t\t\t\t\t\told.howMany -= intersectionLength;\n\t\t\t\t\t} else if ( inc.offset < oldEnd ) {\n\t\t\t\t\t\tif ( incEnd <= oldEnd ) {\n\t\t\t\t\t\t\t// On first sight in this case we don't need to split attribute operation into two.\n\t\t\t\t\t\t\t// However the changes set is later converted to actions (see `_generateActionsFromChanges`).\n\t\t\t\t\t\t\t// For that reason, no two changes may intersect.\n\t\t\t\t\t\t\t// So we cannot have an attribute change that \"contains\" remove change.\n\t\t\t\t\t\t\t// Attribute change needs to be split.\n\t\t\t\t\t\t\tconst howMany = old.howMany;\n\n\t\t\t\t\t\t\told.howMany = inc.offset - old.offset;\n\n\t\t\t\t\t\t\tconst howManyAfter = howMany - old.howMany - inc.nodesToHandle;\n\n\t\t\t\t\t\t\t// Add the second part of attribute change to the beginning of processed array so it won't\n\t\t\t\t\t\t\t// be processed again in this loop.\n\t\t\t\t\t\t\tchanges.unshift( {\n\t\t\t\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\t\t\t\toffset: inc.offset,\n\t\t\t\t\t\t\t\thowMany: howManyAfter,\n\t\t\t\t\t\t\t\tcount: this._changeCount++\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\told.howMany -= oldEnd - inc.offset;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( inc.type == 'attribute' ) {\n\t\t\t\t// In case of attribute change, `howMany` should be kept same as `nodesToHandle`. It's not an error.\n\t\t\t\tif ( old.type == 'insert' ) {\n\t\t\t\t\tif ( inc.offset < old.offset && incEnd > old.offset ) {\n\t\t\t\t\t\tif ( incEnd > oldEnd ) {\n\t\t\t\t\t\t\t// This case is similar to a case described when incoming change was insert and old change was attribute.\n\t\t\t\t\t\t\t// See comment above.\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// This time incoming change is attribute. We need to split incoming change in this case too.\n\t\t\t\t\t\t\t// However this time, the second part of the attribute change needs to be processed further\n\t\t\t\t\t\t\t// because there might be other changes that it collides with.\n\t\t\t\t\t\t\tconst attributePart = {\n\t\t\t\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\t\t\t\toffset: oldEnd,\n\t\t\t\t\t\t\t\thowMany: incEnd - oldEnd,\n\t\t\t\t\t\t\t\tcount: this._changeCount++\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tthis._handleChange( attributePart, changes );\n\n\t\t\t\t\t\t\tchanges.push( attributePart );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tinc.nodesToHandle = old.offset - inc.offset;\n\t\t\t\t\t\tinc.howMany = inc.nodesToHandle;\n\t\t\t\t\t} else if ( inc.offset >= old.offset && inc.offset < oldEnd ) {\n\t\t\t\t\t\tif ( incEnd > oldEnd ) {\n\t\t\t\t\t\t\tinc.nodesToHandle = incEnd - oldEnd;\n\t\t\t\t\t\t\tinc.offset = oldEnd;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tinc.nodesToHandle = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'remove' ) {\n\t\t\t\t\t// This is a case when attribute change \"contains\" remove change.\n\t\t\t\t\t// The attribute change needs to be split into two because changes cannot intersect.\n\t\t\t\t\tif ( inc.offset < old.offset && incEnd > old.offset ) {\n\t\t\t\t\t\tconst attributePart = {\n\t\t\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\t\t\toffset: old.offset,\n\t\t\t\t\t\t\thowMany: incEnd - old.offset,\n\t\t\t\t\t\t\tcount: this._changeCount++\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tthis._handleChange( attributePart, changes );\n\n\t\t\t\t\t\tchanges.push( attributePart );\n\n\t\t\t\t\t\tinc.nodesToHandle = old.offset - inc.offset;\n\t\t\t\t\t\tinc.howMany = inc.nodesToHandle;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'attribute' ) {\n\t\t\t\t\t// There are only two conflicting scenarios possible here:\n\t\t\t\t\tif ( inc.offset >= old.offset && incEnd <= oldEnd ) {\n\t\t\t\t\t\t// `old` change includes `inc` change, or they are the same.\n\t\t\t\t\t\tinc.nodesToHandle = 0;\n\t\t\t\t\t\tinc.howMany = 0;\n\t\t\t\t\t\tinc.offset = 0;\n\t\t\t\t\t} else if ( inc.offset <= old.offset && incEnd >= oldEnd ) {\n\t\t\t\t\t\t// `inc` change includes `old` change.\n\t\t\t\t\t\told.howMany = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tinc.howMany = inc.nodesToHandle;\n\t\tdelete inc.nodesToHandle;\n\t}\n\n\t/**\n\t * Returns an object with a single insert change description.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent The element in which the change happened.\n\t * @param {Number} offset The offset at which change happened.\n\t * @param {String} name The name of the removed element or `'$text'` for a character.\n\t * @returns {Object} The diff item.\n\t */\n\t_getInsertDiff( parent, offset, name ) {\n\t\treturn {\n\t\t\ttype: 'insert',\n\t\t\tposition: Position._createAt( parent, offset ),\n\t\t\tname,\n\t\t\tlength: 1,\n\t\t\tchangeCount: this._changeCount++\n\t\t};\n\t}\n\n\t/**\n\t * Returns an object with a single remove change description.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent The element in which change happened.\n\t * @param {Number} offset The offset at which change happened.\n\t * @param {String} name The name of the removed element or `'$text'` for a character.\n\t * @returns {Object} The diff item.\n\t */\n\t_getRemoveDiff( parent, offset, name ) {\n\t\treturn {\n\t\t\ttype: 'remove',\n\t\t\tposition: Position._createAt( parent, offset ),\n\t\t\tname,\n\t\t\tlength: 1,\n\t\t\tchangeCount: this._changeCount++\n\t\t};\n\t}\n\n\t/**\n\t * Returns an array of objects where each one is a single attribute change description.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range The range where the change happened.\n\t * @param {Map} oldAttributes A map, map iterator or compatible object that contains attributes before the change.\n\t * @param {Map} newAttributes A map, map iterator or compatible object that contains attributes after the change.\n\t * @returns {Array.<Object>} An array containing one or more diff items.\n\t */\n\t_getAttributesDiff( range, oldAttributes, newAttributes ) {\n\t\t// Results holder.\n\t\tconst diffs = [];\n\n\t\t// Clone new attributes as we will be performing changes on this object.\n\t\tnewAttributes = new Map( newAttributes );\n\n\t\t// Look through old attributes.\n\t\tfor ( const [ key, oldValue ] of oldAttributes ) {\n\t\t\t// Check what is the new value of the attribute (or if it was removed).\n\t\t\tconst newValue = newAttributes.has( key ) ? newAttributes.get( key ) : null;\n\n\t\t\t// If values are different (or attribute was removed)...\n\t\t\tif ( newValue !== oldValue ) {\n\t\t\t\t// Add diff item.\n\t\t\t\tdiffs.push( {\n\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\tposition: range.start,\n\t\t\t\t\trange: range.clone(),\n\t\t\t\t\tlength: 1,\n\t\t\t\t\tattributeKey: key,\n\t\t\t\t\tattributeOldValue: oldValue,\n\t\t\t\t\tattributeNewValue: newValue,\n\t\t\t\t\tchangeCount: this._changeCount++\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Prevent returning two diff items for the same change.\n\t\t\tnewAttributes.delete( key );\n\t\t}\n\n\t\t// Look through new attributes that weren't handled above.\n\t\tfor ( const [ key, newValue ] of newAttributes ) {\n\t\t\t// Each of them is a new attribute. Add diff item.\n\t\t\tdiffs.push( {\n\t\t\t\ttype: 'attribute',\n\t\t\t\tposition: range.start,\n\t\t\t\trange: range.clone(),\n\t\t\t\tlength: 1,\n\t\t\t\tattributeKey: key,\n\t\t\t\tattributeOldValue: null,\n\t\t\t\tattributeNewValue: newValue,\n\t\t\t\tchangeCount: this._changeCount++\n\t\t\t} );\n\t\t}\n\n\t\treturn diffs;\n\t}\n\n\t/**\n\t * Checks whether given element or any of its parents is an element that is buffered as an inserted element.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} element Element to check.\n\t * @returns {Boolean}\n\t */\n\t_isInInsertedElement( element ) {\n\t\tconst parent = element.parent;\n\n\t\tif ( !parent ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst changes = this._changesInElement.get( parent );\n\t\tconst offset = element.startOffset;\n\n\t\tif ( changes ) {\n\t\t\tfor ( const change of changes ) {\n\t\t\t\tif ( change.type == 'insert' && offset >= change.offset && offset < change.offset + change.howMany ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this._isInInsertedElement( parent );\n\t}\n\n\t/**\n\t * Removes deeply all buffered changes that are registered in elements from range specified by `parent`, `offset`\n\t * and `howMany`.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent\n\t * @param {Number} offset\n\t * @param {Number} howMany\n\t */\n\t_removeAllNestedChanges( parent, offset, howMany ) {\n\t\tconst range = new Range( Position._createAt( parent, offset ), Position._createAt( parent, offset + howMany ) );\n\n\t\tfor ( const item of range.getItems( { shallow: true } ) ) {\n\t\t\tif ( item.is( 'element' ) ) {\n\t\t\t\tthis._elementSnapshots.delete( item );\n\t\t\t\tthis._changesInElement.delete( item );\n\n\t\t\t\tthis._removeAllNestedChanges( item, 0, item.maxOffset );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Returns an array that is a copy of passed child list with the exception that text nodes are split to one or more\n// objects, each representing one character and attributes set on that character.\nfunction _getChildrenSnapshot( children ) {\n\tconst snapshot = [];\n\n\tfor ( const child of children ) {\n\t\tif ( child.is( 'text' ) ) {\n\t\t\tfor ( let i = 0; i < child.data.length; i++ ) {\n\t\t\t\tsnapshot.push( {\n\t\t\t\t\tname: '$text',\n\t\t\t\t\tattributes: new Map( child.getAttributes() )\n\t\t\t\t} );\n\t\t\t}\n\t\t} else {\n\t\t\tsnapshot.push( {\n\t\t\t\tname: child.name,\n\t\t\t\tattributes: new Map( child.getAttributes() )\n\t\t\t} );\n\t\t}\n\t}\n\n\treturn snapshot;\n}\n\n// Generates array of actions for given changes set.\n// It simulates what `diff` function does.\n// Generated actions are:\n// - 'e' for 'equal' - when item at that position did not change,\n// - 'i' for 'insert' - when item at that position was inserted,\n// - 'r' for 'remove' - when item at that position was removed,\n// - 'a' for 'attribute' - when item at that position has it attributes changed.\n//\n// Example (assume that uppercase letters have bold attribute, compare with function code):\n//\n// children before:\tfooBAR\n// children after:\tfoxybAR\n//\n// changes: type: remove, offset: 1, howMany: 1\n//\t\t\ttype: insert, offset: 2, howMany: 2\n//\t\t\ttype: attribute, offset: 4, howMany: 1\n//\n// expected actions: equal (f), remove (o), equal (o), insert (x), insert (y), attribute (b), equal (A), equal (R)\n//\n// steps taken by th script:\n//\n// 1. change = \"type: remove, offset: 1, howMany: 1\"; offset = 0; oldChildrenHandled = 0\n// 1.1 between this change and the beginning is one not-changed node, fill with one equal action, one old child has been handled\n// 1.2 this change removes one node, add one remove action\n// 1.3 change last visited `offset` to 1\n// 1.4 since an old child has been removed, one more old child has been handled\n// 1.5 actions at this point are: equal, remove\n//\n// 2. change = \"type: insert, offset: 2, howMany: 2\"; offset = 1; oldChildrenHandled = 2\n// 2.1 between this change and previous change is one not-changed node, add equal action, another one old children has been handled\n// 2.2 this change inserts two nodes, add two insert actions\n// 2.3 change last visited offset to the end of the inserted range, that is 4\n// 2.4 actions at this point are: equal, remove, equal, insert, insert\n//\n// 3. change = \"type: attribute, offset: 4, howMany: 1\"; offset = 4, oldChildrenHandled = 3\n// 3.1 between this change and previous change are no not-changed nodes\n// 3.2 this change changes one node, add one attribute action\n// 3.3 change last visited `offset` to the end of change range, that is 5\n// 3.4 since an old child has been changed, one more old child has been handled\n// 3.5 actions at this point are: equal, remove, equal, insert, insert, attribute\n//\n// 4. after loop oldChildrenHandled = 4, oldChildrenLength = 6 (fooBAR is 6 characters)\n// 4.1 fill up with two equal actions\n//\n// The result actions are: equal, remove, equal, insert, insert, attribute, equal, equal.\nfunction _generateActionsFromChanges( oldChildrenLength, changes ) {\n\tconst actions = [];\n\n\tlet offset = 0;\n\tlet oldChildrenHandled = 0;\n\n\t// Go through all buffered changes.\n\tfor ( const change of changes ) {\n\t\t// First, fill \"holes\" between changes with \"equal\" actions.\n\t\tif ( change.offset > offset ) {\n\t\t\tfor ( let i = 0; i < change.offset - offset; i++ ) {\n\t\t\t\tactions.push( 'e' );\n\t\t\t}\n\n\t\t\toldChildrenHandled += change.offset - offset;\n\t\t}\n\n\t\t// Then, fill up actions accordingly to change type.\n\t\tif ( change.type == 'insert' ) {\n\t\t\tfor ( let i = 0; i < change.howMany; i++ ) {\n\t\t\t\tactions.push( 'i' );\n\t\t\t}\n\n\t\t\t// The last handled offset is after inserted range.\n\t\t\toffset = change.offset + change.howMany;\n\t\t} else if ( change.type == 'remove' ) {\n\t\t\tfor ( let i = 0; i < change.howMany; i++ ) {\n\t\t\t\tactions.push( 'r' );\n\t\t\t}\n\n\t\t\t// The last handled offset is at the position where the nodes were removed.\n\t\t\toffset = change.offset;\n\t\t\t// We removed `howMany` old nodes, update `oldChildrenHandled`.\n\t\t\toldChildrenHandled += change.howMany;\n\t\t} else {\n\t\t\tactions.push( ...'a'.repeat( change.howMany ).split( '' ) );\n\n\t\t\t// The last handled offset is at the position after the changed range.\n\t\t\toffset = change.offset + change.howMany;\n\t\t\t// We changed `howMany` old nodes, update `oldChildrenHandled`.\n\t\t\toldChildrenHandled += change.howMany;\n\t\t}\n\t}\n\n\t// Fill \"equal\" actions at the end of actions set. Use `oldChildrenHandled` to see how many children\n\t// has not been changed / removed at the end of their parent.\n\tif ( oldChildrenHandled < oldChildrenLength ) {\n\t\tfor ( let i = 0; i < oldChildrenLength - oldChildrenHandled - offset; i++ ) {\n\t\t\tactions.push( 'e' );\n\t\t}\n\t}\n\n\treturn actions;\n}\n\n// Filter callback for Array.filter that filters out change entries that are in graveyard.\nfunction _changesInGraveyardFilter( entry ) {\n\tconst posInGy = entry.position && entry.position.root.rootName == '$graveyard';\n\tconst rangeInGy = entry.range && entry.range.root.rootName == '$graveyard';\n\n\treturn !posInGy && !rangeInGy;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/history\n */\n\n/**\n * `History` keeps the track of all the operations applied to the {@link module:engine/model/document~Document document}.\n */\nexport default class History {\n\t/**\n\t * Creates an empty History instance.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Operations added to the history.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.<module:engine/model/operation/operation~Operation>} module:engine/model/history~History#_operations\n\t\t */\n\t\tthis._operations = [];\n\n\t\t/**\n\t\t * Holds an information which {@link module:engine/model/operation/operation~Operation operation} undoes which\n\t\t * {@link module:engine/model/operation/operation~Operation operation}.\n\t\t *\n\t\t * Keys of the map are \"undoing operations\", that is operations that undone some other operations. For each key, the\n\t\t * value is an operation that has been undone by the \"undoing operation\".\n\t\t *\n\t\t * @private\n\t\t * @member {Map} module:engine/model/history~History#_undoPairs\n\t\t */\n\t\tthis._undoPairs = new Map();\n\n\t\t/**\n\t\t * Holds all undone operations.\n\t\t *\n\t\t * @private\n\t\t * @member {Set.<module:engine/model/operation/operation~Operation>} module:engine/model/history~History#_undoneOperations\n\t\t */\n\t\tthis._undoneOperations = new Set();\n\t}\n\n\t/**\n\t * Adds an operation to the history.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to add.\n\t */\n\taddOperation( operation ) {\n\t\tif ( this._operations.includes( operation ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._operations.push( operation );\n\t}\n\n\t/**\n\t * Returns operations added to the history.\n\t *\n\t * @param {Number} [from=0] Base version from which operations should be returned (inclusive). Defaults to `0`, which means\n\t * that operations from the first one will be returned.\n\t * @param {Number} [to=Number.POSITIVE_INFINITY] Base version up to which operations should be returned (exclusive).\n\t * Defaults to `Number.POSITIVE_INFINITY` which means that operations up to the last one will be returned.\n\t * @returns {Iterable.<module:engine/model/operation/operation~Operation>} Operations added to the history.\n\t */\n\tgetOperations( from = 0, to = Number.POSITIVE_INFINITY ) {\n\t\tif ( from < 0 ) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn this._operations.slice( from, to );\n\t}\n\n\t/**\n\t * Returns operation from the history that bases on given `baseVersion`.\n\t *\n\t * @param {Number} baseVersion Base version of the operation to get.\n\t * @returns {module:engine/model/operation/operation~Operation|null} Operation with given base version or `null` if\n\t * there is no such operation in history.\n\t */\n\tgetOperation( baseVersion ) {\n\t\treturn this._operations[ baseVersion ];\n\t}\n\n\t/**\n\t * Marks in history that one operation is an operation that is undoing the other operation. By marking operation this way,\n\t * history is keeping more context information about operations, which helps in operational transformation.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} undoneOperation Operation which is undone by `undoingOperation`.\n\t * @param {module:engine/model/operation/operation~Operation} undoingOperation Operation which undoes `undoneOperation`.\n\t */\n\tsetOperationAsUndone( undoneOperation, undoingOperation ) {\n\t\tthis._undoPairs.set( undoingOperation, undoneOperation );\n\t\tthis._undoneOperations.add( undoneOperation );\n\t}\n\n\t/**\n\t * Checks whether given `operation` is undoing any other operation.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to check.\n\t * @returns {Boolean} `true` if given `operation` is undoing any other operation, `false` otherwise.\n\t */\n\tisUndoingOperation( operation ) {\n\t\treturn this._undoPairs.has( operation );\n\t}\n\n\t/**\n\t * Checks whether given `operation` has been undone by any other operation.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to check.\n\t * @returns {Boolean} `true` if given `operation` has been undone any other operation, `false` otherwise.\n\t */\n\tisUndoneOperation( operation ) {\n\t\treturn this._undoneOperations.has( operation );\n\t}\n\n\t/**\n\t * For given `undoingOperation`, returns the operation which has been undone by it.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} undoingOperation\n\t * @returns {module:engine/model/operation/operation~Operation|undefined} Operation that has been undone by given\n\t * `undoingOperation` or `undefined` if given `undoingOperation` is not undoing any other operation.\n\t */\n\tgetUndoneOperation( undoingOperation ) {\n\t\treturn this._undoPairs.get( undoingOperation );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * Set of utils to handle unicode characters.\n *\n * @module utils/unicode\n */\n\n/**\n * Checks whether given `character` is a combining mark.\n *\n * @param {String} character Character to check.\n * @returns {Boolean}\n */\nexport function isCombiningMark( character ) {\n\treturn !!character && character.length == 1 && /[\\u0300-\\u036f\\u1ab0-\\u1aff\\u1dc0-\\u1dff\\u20d0-\\u20ff\\ufe20-\\ufe2f]/.test( character );\n}\n\n/**\n * Checks whether given `character` is a high half of surrogate pair.\n *\n * Using UTF-16 terminology, a surrogate pair denotes UTF-16 character using two UTF-8 characters. The surrogate pair\n * consist of high surrogate pair character followed by low surrogate pair character.\n *\n * @param {String} character Character to check.\n * @returns {Boolean}\n */\nexport function isHighSurrogateHalf( character ) {\n\treturn !!character && character.length == 1 && /[\\ud800-\\udbff]/.test( character );\n}\n\n/**\n * Checks whether given `character` is a low half of surrogate pair.\n *\n * Using UTF-16 terminology, a surrogate pair denotes UTF-16 character using two UTF-8 characters. The surrogate pair\n * consist of high surrogate pair character followed by low surrogate pair character.\n *\n * @param {String} character Character to check.\n * @returns {Boolean}\n */\nexport function isLowSurrogateHalf( character ) {\n\treturn !!character && character.length == 1 && /[\\udc00-\\udfff]/.test( character );\n}\n\n/**\n * Checks whether given offset in a string is inside a surrogate pair (between two surrogate halves).\n *\n * @param {String} string String to check.\n * @param {Number} offset Offset to check.\n * @returns {Boolean}\n */\nexport function isInsideSurrogatePair( string, offset ) {\n\treturn isHighSurrogateHalf( string.charAt( offset - 1 ) ) && isLowSurrogateHalf( string.charAt( offset ) );\n}\n\n/**\n * Checks whether given offset in a string is between base character and combining mark or between two combining marks.\n *\n * @param {String} string String to check.\n * @param {Number} offset Offset to check.\n * @returns {Boolean}\n */\nexport function isInsideCombinedSymbol( string, offset ) {\n\treturn isCombiningMark( string.charAt( offset ) );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/document\n */\n\nimport Differ from './differ';\nimport RootElement from './rootelement';\nimport History from './history';\nimport DocumentSelection from './documentselection';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { isInsideSurrogatePair, isInsideCombinedSymbol } from '@ckeditor/ckeditor5-utils/src/unicode';\nimport { clone } from 'lodash-es';\n\n// @if CK_DEBUG_ENGINE // const { logDocument } = require( '../dev-utils/utils' );\n\nconst graveyardName = '$graveyard';\n\n/**\n * Data model's document. It contains the model's structure, its selection and the history of changes.\n *\n * Read more about working with the model in\n * {@glink framework/guides/architecture/editing-engine#model introduction to the the editing engine's architecture}.\n *\n * Usually, the document contains just one {@link module:engine/model/document~Document#roots root element}, so\n * you can retrieve it by just calling {@link module:engine/model/document~Document#getRoot} without specifying its name:\n *\n *\t\tmodel.document.getRoot(); // -> returns the main root\n *\n * However, the document may contain multiple roots – e.g. when the editor has multiple editable areas\n * (e.g. a title and a body of a message).\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Document {\n\t/**\n\t * Creates an empty document instance with no {@link #roots} (other than\n\t * the {@link #graveyard graveyard root}).\n\t */\n\tconstructor( model ) {\n\t\t/**\n\t\t * The {@link module:engine/model/model~Model model} that the document is a part of.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * The document version. It starts from `0` and every operation increases the version number. It is used to ensure that\n\t\t * operations are applied on a proper document version.\n\t\t *\n\t\t * If the {@link module:engine/model/operation/operation~Operation#baseVersion base version} does not match the document version,\n\t\t * a {@link module:utils/ckeditorerror~CKEditorError model-document-applyOperation-wrong-version} error is thrown.\n\t\t *\n\t\t * @readonly\n\t\t * @type {Number}\n\t\t */\n\t\tthis.version = 0;\n\n\t\t/**\n\t\t * The document's history.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/history~History}\n\t\t */\n\t\tthis.history = new History( this );\n\n\t\t/**\n\t\t * The selection in this document.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/documentselection~DocumentSelection}\n\t\t */\n\t\tthis.selection = new DocumentSelection( this );\n\n\t\t/**\n\t\t * A list of roots that are owned and managed by this document. Use {@link #createRoot} and\n\t\t * {@link #getRoot} to manipulate it.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/collection~Collection}\n\t\t */\n\t\tthis.roots = new Collection( { idProperty: 'rootName' } );\n\n\t\t/**\n\t\t * The model differ object. Its role is to buffer changes done on the model document and then calculate a diff of those changes.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/differ~Differ}\n\t\t */\n\t\tthis.differ = new Differ( model.markers );\n\n\t\t/**\n\t\t * Post-fixer callbacks registered to the model document.\n\t\t *\n\t\t * @private\n\t\t * @type {Set.<Function>}\n\t\t */\n\t\tthis._postFixers = new Set();\n\n\t\t/**\n\t\t * A boolean indicates whether the selection has changed until\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._hasSelectionChangedFromTheLastChangeBlock = false;\n\n\t\t// Graveyard tree root. Document always have a graveyard root, which stores removed nodes.\n\t\tthis.createRoot( '$root', graveyardName );\n\n\t\t// First, if the operation is a document operation check if it's base version is correct.\n\t\tthis.listenTo( model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( operation.isDocumentOperation && operation.baseVersion !== this.version ) {\n\t\t\t\t/**\n\t\t\t\t * Only operations with matching versions can be applied.\n\t\t\t\t *\n\t\t\t\t * @error document-applyOperation-wrong-version\n\t\t\t\t * @param {module:engine/model/operation/operation~Operation} operation\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-document-applyOperation-wrong-version: Only operations with matching versions can be applied.',\n\t\t\t\t\tthis,\n\t\t\t\t\t{ operation }\n\t\t\t\t);\n\t\t\t}\n\t\t}, { priority: 'highest' } );\n\n\t\t// Then, still before an operation is applied on model, buffer the change in differ.\n\t\tthis.listenTo( model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( operation.isDocumentOperation ) {\n\t\t\t\tthis.differ.bufferOperation( operation );\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\n\t\t// After the operation is applied, bump document's version and add the operation to the history.\n\t\tthis.listenTo( model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( operation.isDocumentOperation ) {\n\t\t\t\tthis.version++;\n\t\t\t\tthis.history.addOperation( operation );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\t// Listen to selection changes. If selection changed, mark it.\n\t\tthis.listenTo( this.selection, 'change', () => {\n\t\t\tthis._hasSelectionChangedFromTheLastChangeBlock = true;\n\t\t} );\n\n\t\t// Buffer marker changes.\n\t\t// This is not covered in buffering operations because markers may change outside of them (when they\n\t\t// are modified using `model.markers` collection, not through `MarkerOperation`).\n\t\tthis.listenTo( model.markers, 'update', ( evt, marker, oldRange, newRange ) => {\n\t\t\t// Whenever marker is updated, buffer that change.\n\t\t\tthis.differ.bufferMarkerChange( marker.name, oldRange, newRange, marker.affectsData );\n\n\t\t\tif ( oldRange === null ) {\n\t\t\t\t// If this is a new marker, add a listener that will buffer change whenever marker changes.\n\t\t\t\tmarker.on( 'change', ( evt, oldRange ) => {\n\t\t\t\t\tthis.differ.bufferMarkerChange( marker.name, oldRange, marker.getRange(), marker.affectsData );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * The graveyard tree root. A document always has a graveyard root that stores removed nodes.\n\t *\n\t * @readonly\n\t * @member {module:engine/model/rootelement~RootElement}\n\t */\n\tget graveyard() {\n\t\treturn this.getRoot( graveyardName );\n\t}\n\n\t/**\n\t * Creates a new root.\n\t *\n\t * @param {String} [elementName='$root'] The element name. Defaults to `'$root'` which also has some basic schema defined\n\t * (`$block`s are allowed inside the `$root`). Make sure to define a proper schema if you use a different name.\n\t * @param {String} [rootName='main'] A unique root name.\n\t * @returns {module:engine/model/rootelement~RootElement} The created root.\n\t */\n\tcreateRoot( elementName = '$root', rootName = 'main' ) {\n\t\tif ( this.roots.get( rootName ) ) {\n\t\t\t/**\n\t\t\t * A root with the specified name already exists.\n\t\t\t *\n\t\t\t * @error model-document-createRoot-name-exists\n\t\t\t * @param {module:engine/model/document~Document} doc\n\t\t\t * @param {String} name\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-document-createRoot-name-exists: Root with specified name already exists.',\n\t\t\t\tthis,\n\t\t\t\t{ name: rootName }\n\t\t\t);\n\t\t}\n\n\t\tconst root = new RootElement( this, elementName, rootName );\n\t\tthis.roots.add( root );\n\n\t\treturn root;\n\t}\n\n\t/**\n\t * Removes all event listeners set by the document instance.\n\t */\n\tdestroy() {\n\t\tthis.selection.destroy();\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Returns a root by its name.\n\t *\n\t * @param {String} [name='main'] A unique root name.\n\t * @returns {module:engine/model/rootelement~RootElement|null} The root registered under a given name or `null` when\n\t * there is no root with the given name.\n\t */\n\tgetRoot( name = 'main' ) {\n\t\treturn this.roots.get( name );\n\t}\n\n\t/**\n\t * Returns an array with names of all roots (without the {@link #graveyard}) added to the document.\n\t *\n\t * @returns {Array.<String>} Roots names.\n\t */\n\tgetRootNames() {\n\t\treturn Array.from( this.roots, root => root.rootName ).filter( name => name != graveyardName );\n\t}\n\n\t/**\n\t * Used to register a post-fixer callback. A post-fixer mechanism guarantees that the features\n\t * will operate on a correct model state.\n\t *\n\t * An execution of a feature may lead to an incorrect document tree state. The callbacks are used to fix the document tree after\n\t * it has changed. Post-fixers are fired just after all changes from the outermost change block were applied but\n\t * before the {@link module:engine/model/document~Document#event:change change event} is fired. If a post-fixer callback made\n\t * a change, it should return `true`. When this happens, all post-fixers are fired again to check if something else should\n\t * not be fixed in the new document tree state.\n\t *\n\t * As a parameter, a post-fixer callback receives a {@link module:engine/model/writer~Writer writer} instance connected with the\n\t * executed changes block. Thanks to that, all changes done by the callback will be added to the same\n\t * {@link module:engine/model/batch~Batch batch} (and undo step) as the original changes. This makes post-fixer changes transparent\n\t * for the user.\n\t *\n\t * An example of a post-fixer is a callback that checks if all the data were removed from the editor. If so, the\n\t * callback should add an empty paragraph so that the editor is never empty:\n\t *\n\t *\t\tdocument.registerPostFixer( writer => {\n\t *\t\t\tconst changes = document.differ.getChanges();\n\t *\n\t *\t\t\t// Check if the changes lead to an empty root in the editor.\n\t *\t\t\tfor ( const entry of changes ) {\n\t *\t\t\t\tif ( entry.type == 'remove' && entry.position.root.isEmpty ) {\n\t *\t\t\t\t\twriter.insertElement( 'paragraph', entry.position.root, 0 );\n\t *\n\t *\t\t\t\t\t// It is fine to return early, even if multiple roots would need to be fixed.\n\t *\t\t\t\t\t// All post-fixers will be fired again, so if there are more empty roots, those will be fixed, too.\n\t *\t\t\t\t\treturn true;\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @param {Function} postFixer\n\t */\n\tregisterPostFixer( postFixer ) {\n\t\tthis._postFixers.add( postFixer );\n\t}\n\n\t/**\n\t * A custom `toJSON()` method to solve child-parent circular dependencies.\n\t *\n\t * @returns {Object} A clone of this object with the document property changed to a string.\n\t */\n\ttoJSON() {\n\t\tconst json = clone( this );\n\n\t\t// Due to circular references we need to remove parent reference.\n\t\tjson.selection = '[engine.model.DocumentSelection]';\n\t\tjson.model = '[engine.model.Model]';\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Check if there were any changes done on document, and if so, call post-fixers,\n\t * fire `change` event for features and conversion and then reset the differ.\n\t * Fire `change:data` event when at least one operation or buffered marker changes the data.\n\t *\n\t * @protected\n\t * @fires change\n\t * @fires change:data\n\t * @param {module:engine/model/writer~Writer} writer The writer on which post-fixers will be called.\n\t */\n\t_handleChangeBlock( writer ) {\n\t\tif ( this._hasDocumentChangedFromTheLastChangeBlock() ) {\n\t\t\tthis._callPostFixers( writer );\n\n\t\t\t// Refresh selection attributes according to the final position in the model after the change.\n\t\t\tthis.selection.refresh();\n\n\t\t\tif ( this.differ.hasDataChanges() ) {\n\t\t\t\tthis.fire( 'change:data', writer.batch );\n\t\t\t} else {\n\t\t\t\tthis.fire( 'change', writer.batch );\n\t\t\t}\n\n\t\t\t// Theoretically, it is not necessary to refresh selection after change event because\n\t\t\t// post-fixers are the last who should change the model, but just in case...\n\t\t\tthis.selection.refresh();\n\n\t\t\tthis.differ.reset();\n\t\t}\n\n\t\tthis._hasSelectionChangedFromTheLastChangeBlock = false;\n\t}\n\n\t/**\n\t * Returns whether there is a buffered change or if the selection has changed from the last\n\t * {@link module:engine/model/model~Model#enqueueChange `enqueueChange()` block}\n\t * or {@link module:engine/model/model~Model#change `change()` block}.\n\t *\n\t * @protected\n\t * @returns {Boolean} Returns `true` if document has changed from the last `change()` or `enqueueChange()` block.\n\t */\n\t_hasDocumentChangedFromTheLastChangeBlock() {\n\t\treturn !this.differ.isEmpty || this._hasSelectionChangedFromTheLastChangeBlock;\n\t}\n\n\t/**\n\t * Returns the default root for this document which is either the first root that was added to the document using\n\t * {@link #createRoot} or the {@link #graveyard graveyard root} if no other roots were created.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/rootelement~RootElement} The default root for this document.\n\t */\n\t_getDefaultRoot() {\n\t\tfor ( const root of this.roots ) {\n\t\t\tif ( root !== this.graveyard ) {\n\t\t\t\treturn root;\n\t\t\t}\n\t\t}\n\n\t\treturn this.graveyard;\n\t}\n\n\t/**\n\t * Returns the default range for this selection. The default range is a collapsed range that starts and ends\n\t * at the beginning of this selection's document {@link #_getDefaultRoot default root}.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getDefaultRange() {\n\t\tconst defaultRoot = this._getDefaultRoot();\n\t\tconst model = this.model;\n\t\tconst schema = model.schema;\n\n\t\t// Find the first position where the selection can be put.\n\t\tconst position = model.createPositionFromPath( defaultRoot, [ 0 ] );\n\t\tconst nearestRange = schema.getNearestSelectionRange( position );\n\n\t\t// If valid selection range is not found - return range collapsed at the beginning of the root.\n\t\treturn nearestRange || model.createRange( position );\n\t}\n\n\t/**\n\t * Checks whether a given {@link module:engine/model/range~Range range} is a valid range for\n\t * the {@link #selection document's selection}.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range A range to check.\n\t * @returns {Boolean} `true` if `range` is valid, `false` otherwise.\n\t */\n\t_validateSelectionRange( range ) {\n\t\treturn validateTextNodePosition( range.start ) && validateTextNodePosition( range.end );\n\t}\n\n\t/**\n\t * Performs post-fixer loops. Executes post-fixer callbacks as long as none of them has done any changes to the model.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer The writer on which post-fixer callbacks will be called.\n\t */\n\t_callPostFixers( writer ) {\n\t\tlet wasFixed = false;\n\n\t\tdo {\n\t\t\tfor ( const callback of this._postFixers ) {\n\t\t\t\t// Ensure selection attributes are up to date before each post-fixer.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/1673.\n\t\t\t\t//\n\t\t\t\t// It might be good to refresh the selection after each operation but at the moment it leads\n\t\t\t\t// to losing attributes for composition or and spell checking\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-typing/issues/188\n\t\t\t\tthis.selection.refresh();\n\n\t\t\t\twasFixed = callback( writer );\n\n\t\t\t\tif ( wasFixed ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} while ( wasFixed );\n\t}\n\n\t/**\n\t * Fired after each {@link module:engine/model/model~Model#enqueueChange `enqueueChange()` block} or the outermost\n\t * {@link module:engine/model/model~Model#change `change()` block} was executed and the document was changed\n\t * during that block's execution.\n\t *\n\t * The changes which this event will cover include:\n\t *\n\t * * document structure changes,\n\t * * selection changes,\n\t * * marker changes.\n\t *\n\t * If you want to be notified about all these changes, then simply listen to this event like this:\n\t *\n\t *\t\tmodel.document.on( 'change', () => {\n\t *\t\t\tconsole.log( 'The document has changed!' );\n\t *\t\t} );\n\t *\n\t * If, however, you only want to be notified about the data changes, then use the\n\t * {@link module:engine/model/document~Document#event:change:data change:data} event,\n\t * which is fired for document structure changes and marker changes (which affects the data).\n\t *\n\t *\t\tmodel.document.on( 'change:data', () => {\n\t *\t\t\tconsole.log( 'The data has changed!' );\n\t *\t\t} );\n\t *\n\t * @event change\n\t * @param {module:engine/model/batch~Batch} batch The batch that was used in the executed changes block.\n\t */\n\n\t/**\n\t * It is a narrower version of the {@link #event:change} event. It is fired for changes which\n\t * affect the editor data. This is:\n\t *\n\t * * document structure changes,\n\t * * marker changes (which affects the data).\n\t *\n\t * If you want to be notified about the data changes, then listen to this event:\n\t *\n\t *\t\tmodel.document.on( 'change:data', () => {\n\t *\t\t\tconsole.log( 'The data has changed!' );\n\t *\t\t} );\n\t *\n\t * If you would like to listen to all document changes, then check out the\n\t * {@link module:engine/model/document~Document#event:change change} event.\n\t *\n\t * @event change:data\n\t * @param {module:engine/model/batch~Batch} batch The batch that was used in the executed changes block.\n\t */\n\n\t// @if CK_DEBUG_ENGINE // log( version = null ) {\n\t// @if CK_DEBUG_ENGINE // \tversion = version === null ? this.version : version;\n\t// @if CK_DEBUG_ENGINE // \tlogDocument( this, version );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\nmix( Document, EmitterMixin );\n\n// Checks whether given range boundary position is valid for document selection, meaning that is not between\n// unicode surrogate pairs or base character and combining marks.\nfunction validateTextNodePosition( rangeBoundary ) {\n\tconst textNode = rangeBoundary.textNode;\n\n\tif ( textNode ) {\n\t\tconst data = textNode.data;\n\t\tconst offset = rangeBoundary.offset - textNode.startOffset;\n\n\t\treturn !isInsideSurrogatePair( data, offset ) && !isInsideCombinedSymbol( data, offset );\n\t}\n\n\treturn true;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/markercollection\n */\n\nimport LiveRange from './liverange';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The collection of all {@link module:engine/model/markercollection~Marker markers} attached to the document.\n * It lets you {@link module:engine/model/markercollection~MarkerCollection#get get} markers or track them using\n * {@link module:engine/model/markercollection~MarkerCollection#event:update} event.\n *\n * To create, change or remove makers use {@link module:engine/model/writer~Writer model writers'} methods:\n * {@link module:engine/model/writer~Writer#addMarker} or {@link module:engine/model/writer~Writer#removeMarker}. Since\n * the writer is the only proper way to change the data model it is not possible to change markers directly using this\n * collection. All markers created by the writer will be automatically added to this collection.\n *\n * By default there is one marker collection available as {@link module:engine/model/model~Model#markers model property}.\n *\n * @see module:engine/model/markercollection~Marker\n */\nexport default class MarkerCollection {\n\t/**\n\t * Creates a markers collection.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Stores {@link ~Marker markers} added to the collection.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} #_markers\n\t\t */\n\t\tthis._markers = new Map();\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all {@link ~Marker markers} added to the collection.\n\t *\n\t * @returns {Iterable}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._markers.values();\n\t}\n\n\t/**\n\t * Checks if marker with given `markerName` is in the collection.\n\t *\n\t * @param {String} markerName Marker name.\n\t * @returns {Boolean} `true` if marker with given `markerName` is in the collection, `false` otherwise.\n\t */\n\thas( markerName ) {\n\t\treturn this._markers.has( markerName );\n\t}\n\n\t/**\n\t * Returns {@link ~Marker marker} with given `markerName`.\n\t *\n\t * @param {String} markerName Name of marker to get.\n\t * @returns {module:engine/model/markercollection~Marker|null} Marker with given name or `null` if such marker was\n\t * not added to the collection.\n\t */\n\tget( markerName ) {\n\t\treturn this._markers.get( markerName ) || null;\n\t}\n\n\t/**\n\t * Creates and adds a {@link ~Marker marker} to the `MarkerCollection` with given name on given\n\t * {@link module:engine/model/range~Range range}.\n\t *\n\t * If `MarkerCollection` already had a marker with given name (or {@link ~Marker marker} was passed), the marker in\n\t * collection is updated and {@link module:engine/model/markercollection~MarkerCollection#event:update} event is fired\n\t * but only if there was a change (marker range or {@link module:engine/model/markercollection~Marker#managedUsingOperations}\n\t * flag has changed.\n\t *\n\t * @protected\n\t * @fires module:engine/model/markercollection~MarkerCollection#event:update\n\t * @param {String|module:engine/model/markercollection~Marker} markerOrName Name of marker to set or marker instance to update.\n\t * @param {module:engine/model/range~Range} range Marker range.\n\t * @param {Boolean} [managedUsingOperations=false] Specifies whether the marker is managed using operations.\n\t * @param {Boolean} [affectsData=false] Specifies whether the marker affects the data produced by the data pipeline\n\t * (is persisted in the editor's data).\n\t * @returns {module:engine/model/markercollection~Marker} `Marker` instance which was added or updated.\n\t */\n\t_set( markerOrName, range, managedUsingOperations = false, affectsData = false ) {\n\t\tconst markerName = markerOrName instanceof Marker ? markerOrName.name : markerOrName;\n\t\tconst oldMarker = this._markers.get( markerName );\n\n\t\tif ( oldMarker ) {\n\t\t\tconst oldRange = oldMarker.getRange();\n\t\t\tlet hasChanged = false;\n\n\t\t\tif ( !oldRange.isEqual( range ) ) {\n\t\t\t\toldMarker._attachLiveRange( LiveRange.fromRange( range ) );\n\t\t\t\thasChanged = true;\n\t\t\t}\n\n\t\t\tif ( managedUsingOperations != oldMarker.managedUsingOperations ) {\n\t\t\t\toldMarker._managedUsingOperations = managedUsingOperations;\n\t\t\t\thasChanged = true;\n\t\t\t}\n\n\t\t\tif ( typeof affectsData === 'boolean' && affectsData != oldMarker.affectsData ) {\n\t\t\t\toldMarker._affectsData = affectsData;\n\t\t\t\thasChanged = true;\n\t\t\t}\n\n\t\t\tif ( hasChanged ) {\n\t\t\t\tthis.fire( 'update:' + markerName, oldMarker, oldRange, range );\n\t\t\t}\n\n\t\t\treturn oldMarker;\n\t\t}\n\n\t\tconst liveRange = LiveRange.fromRange( range );\n\t\tconst marker = new Marker( markerName, liveRange, managedUsingOperations, affectsData );\n\n\t\tthis._markers.set( markerName, marker );\n\t\tthis.fire( 'update:' + markerName, marker, null, range );\n\n\t\treturn marker;\n\t}\n\n\t/**\n\t * Removes given {@link ~Marker marker} or a marker with given name from the `MarkerCollection`.\n\t *\n\t * @protected\n\t * @fires module:engine/model/markercollection~MarkerCollection#event:update\n\t * @param {String} markerOrName Marker or name of a marker to remove.\n\t * @returns {Boolean} `true` if marker was found and removed, `false` otherwise.\n\t */\n\t_remove( markerOrName ) {\n\t\tconst markerName = markerOrName instanceof Marker ? markerOrName.name : markerOrName;\n\t\tconst oldMarker = this._markers.get( markerName );\n\n\t\tif ( oldMarker ) {\n\t\t\tthis._markers.delete( markerName );\n\t\t\tthis.fire( 'update:' + markerName, oldMarker, oldMarker.getRange(), null );\n\n\t\t\tthis._destroyMarker( oldMarker );\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Fires an {@link module:engine/model/markercollection~MarkerCollection#event:update} event for the given {@link ~Marker marker}\n\t * but does not change the marker. Useful to force {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher downcast\n\t * conversion} for the marker.\n\t *\n\t * @protected\n\t * @fires module:engine/model/markercollection~MarkerCollection#event:update\n\t * @param {String} markerOrName Marker or name of a marker to refresh.\n\t */\n\t_refresh( markerOrName ) {\n\t\tconst markerName = markerOrName instanceof Marker ? markerOrName.name : markerOrName;\n\t\tconst marker = this._markers.get( markerName );\n\n\t\tif ( !marker ) {\n\t\t\tthrow new CKEditorError( 'markercollection-refresh-marker-not-exists: Marker with provided name does not exists.', this );\n\t\t}\n\n\t\tconst range = marker.getRange();\n\n\t\tthis.fire( 'update:' + markerName, marker, range, range, marker.managedUsingOperations, marker.affectsData );\n\t}\n\n\t/**\n\t * Returns iterator that iterates over all markers, which ranges contain given {@link module:engine/model/position~Position position}.\n\t *\n\t * @param {module:engine/model/position~Position} position\n\t * @returns {Iterable.<module:engine/model/markercollection~Marker>}\n\t */\n\t* getMarkersAtPosition( position ) {\n\t\tfor ( const marker of this ) {\n\t\t\tif ( marker.getRange().containsPosition( position ) ) {\n\t\t\t\tyield marker;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns iterator that iterates over all markers, which intersects with given {@link module:engine/model/range~Range range}.\n\t *\n\t * @param {module:engine/model/range~Range} range\n\t * @returns {Iterable.<module:engine/model/markercollection~Marker>}\n\t */\n\t* getMarkersIntersectingRange( range ) {\n\t\tfor ( const marker of this ) {\n\t\t\tif ( marker.getRange().getIntersection( range ) !== null ) {\n\t\t\t\tyield marker;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Destroys marker collection and all markers inside it.\n\t */\n\tdestroy() {\n\t\tfor ( const marker of this._markers.values() ) {\n\t\t\tthis._destroyMarker( marker );\n\t\t}\n\n\t\tthis._markers = null;\n\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Iterates over all markers that starts with given `prefix`.\n\t *\n\t *\t\tconst markerFooA = markersCollection.set( 'foo:a', rangeFooA );\n\t *\t\tconst markerFooB = markersCollection.set( 'foo:b', rangeFooB );\n\t *\t\tconst markerBarA = markersCollection.set( 'bar:a', rangeBarA );\n\t *\t\tconst markerFooBarA = markersCollection.set( 'foobar:a', rangeFooBarA );\n\t *\t\tArray.from( markersCollection.getMarkersGroup( 'foo' ) ); // [ markerFooA, markerFooB ]\n\t *\t\tArray.from( markersCollection.getMarkersGroup( 'a' ) ); // []\n\t *\n\t * @param prefix\n\t * @returns {Iterable.<module:engine/model/markercollection~Marker>}\n\t */\n\t* getMarkersGroup( prefix ) {\n\t\tfor ( const marker of this._markers.values() ) {\n\t\t\tif ( marker.name.startsWith( prefix + ':' ) ) {\n\t\t\t\tyield marker;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Destroys the marker.\n\t *\n\t * @private\n\t * @param {module:engine/model/markercollection~Marker} marker Marker to destroy.\n\t */\n\t_destroyMarker( marker ) {\n\t\tmarker.stopListening();\n\t\tmarker._detachLiveRange();\n\t}\n\n\t/**\n\t * Fired whenever marker is added, updated or removed from `MarkerCollection`.\n\t *\n\t * @event update\n\t * @param {module:engine/model/markercollection~Marker} marker Updated Marker.\n\t * @param {module:engine/model/range~Range|null} oldRange Marker range before the update. When is not defined it\n\t * means that marker is just added.\n\t * @param {module:engine/model/range~Range|null} newRange Marker range after update. When is not defined it\n\t * means that marker is just removed.\n\t */\n}\n\nmix( MarkerCollection, EmitterMixin );\n\n/**\n * `Marker` is a continuous parts of model (like a range), is named and represent some kind of information about marked\n * part of model document. In contrary to {@link module:engine/model/node~Node nodes}, which are building blocks of\n * model document tree, markers are not stored directly in document tree but in\n * {@link module:engine/model/model~Model#markers model markers' collection}. Still, they are document data, by giving\n * additional meaning to the part of a model document between marker start and marker end.\n *\n * In this sense, markers are similar to adding and converting attributes on nodes. The difference is that attribute is\n * connected with a given node (e.g. a character is bold no matter if it gets moved or content around it changes).\n * Markers on the other hand are continuous ranges and are characterized by their start and end position. This means that\n * any character in the marker is marked by the marker. For example, if a character is moved outside of marker it stops being\n * \"special\" and the marker is shrunk. Similarly, when a character is moved into the marker from other place in document\n * model, it starts being \"special\" and the marker is enlarged.\n *\n * Another upside of markers is that finding marked part of document is fast and easy. Using attributes to mark some nodes\n * and then trying to find that part of document would require traversing whole document tree. Marker gives instant access\n * to the range which it is marking at the moment.\n *\n * Markers are built from a name and a range.\n *\n * Range of the marker is updated automatically when document changes, using\n * {@link module:engine/model/liverange~LiveRange live range} mechanism.\n *\n * Name is used to group and identify markers. Names have to be unique, but markers can be grouped by\n * using common prefixes, separated with `:`, for example: `user:john` or `search:3`. That's useful in term of creating\n * namespaces for custom elements (e.g. comments, highlights). You can use this prefixes in\n * {@link module:engine/model/markercollection~MarkerCollection#event:update} listeners to listen on changes in a group of markers.\n * For instance: `model.markers.on( 'update:user', callback );` will be called whenever any `user:*` markers changes.\n *\n * There are two types of markers.\n *\n * 1. Markers managed directly, without using operations. They are added directly by {@link module:engine/model/writer~Writer}\n * to the {@link module:engine/model/markercollection~MarkerCollection} without any additional mechanism. They can be used\n * as bookmarks or visual markers. They are great for showing results of the find, or select link when the focus is in the input.\n *\n * 1. Markers managed using operations. These markers are also stored in {@link module:engine/model/markercollection~MarkerCollection}\n * but changes in these markers is managed the same way all other changes in the model structure - using operations.\n * Therefore, they are handled in the undo stack and synchronized between clients if the collaboration plugin is enabled.\n * This type of markers is useful for solutions like spell checking or comments.\n *\n * Both type of them should be added / updated by {@link module:engine/model/writer~Writer#addMarker}\n * and removed by {@link module:engine/model/writer~Writer#removeMarker} methods.\n *\n *\t\tmodel.change( ( writer ) => {\n * \t\t\tconst marker = writer.addMarker( name, { range, usingOperation: true } );\n *\n * \t\t\t// ...\n *\n * \t\t\twriter.removeMarker( marker );\n *\t\t} );\n *\n * See {@link module:engine/model/writer~Writer} to find more examples.\n *\n * Since markers need to track change in the document, for efficiency reasons, it is best to create and keep as little\n * markers as possible and remove them as soon as they are not needed anymore.\n *\n * Markers can be downcasted and upcasted.\n *\n * Markers downcast happens on {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker} and\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:removeMarker} events.\n * Use {@link module:engine/conversion/downcasthelpers downcast converters} or attach a custom converter to mentioned events.\n * For {@link module:engine/controller/datacontroller~DataController data pipeline}, marker should be downcasted to an element.\n * Then, it can be upcasted back to a marker. Again, use {@link module:engine/conversion/upcasthelpers upcast converters} or\n * attach a custom converter to {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element}.\n *\n * `Marker` instances are created and destroyed only by {@link ~MarkerCollection MarkerCollection}.\n */\nclass Marker {\n\t/**\n\t * Creates a marker instance.\n\t *\n\t * @param {String} name Marker name.\n\t * @param {module:engine/model/liverange~LiveRange} liveRange Range marked by the marker.\n\t * @param {Boolean} managedUsingOperations Specifies whether the marker is managed using operations.\n\t * @param {Boolean} affectsData Specifies whether the marker affects the data produced by the data pipeline\n\t * (is persisted in the editor's data).\n\t */\n\tconstructor( name, liveRange, managedUsingOperations, affectsData ) {\n\t\t/**\n\t\t * Marker's name.\n\t\t *\n\t\t * @readonly\n\t\t * @type {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Range marked by the marker.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:engine/model/liverange~LiveRange}\n\t\t */\n\t\tthis._liveRange = this._attachLiveRange( liveRange );\n\n\t\t/**\n\t\t * Flag indicates if the marker is managed using operations or not.\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._managedUsingOperations = managedUsingOperations;\n\n\t\t/**\n\t\t * Specifies whether the marker affects the data produced by the data pipeline\n\t\t * (is persisted in the editor's data).\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._affectsData = affectsData;\n\t}\n\n\t/**\n\t * A value indicating if the marker is managed using operations.\n\t * See {@link ~Marker marker class description} to learn more about marker types.\n\t * See {@link module:engine/model/writer~Writer#addMarker}.\n\t *\n\t * @returns {Boolean}\n\t */\n\tget managedUsingOperations() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );\n\t\t}\n\n\t\treturn this._managedUsingOperations;\n\t}\n\n\t/**\n\t * A value indicating if the marker changes the data.\n\t *\n\t * @returns {Boolean}\n\t */\n\tget affectsData() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );\n\t\t}\n\n\t\treturn this._affectsData;\n\t}\n\n\t/**\n\t * Returns current marker start position.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetStart() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );\n\t\t}\n\n\t\treturn this._liveRange.start.clone();\n\t}\n\n\t/**\n\t * Returns current marker end position.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetEnd() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );\n\t\t}\n\n\t\treturn this._liveRange.end.clone();\n\t}\n\n\t/**\n\t * Returns a range that represents the current state of the marker.\n\t *\n\t * Keep in mind that returned value is a {@link module:engine/model/range~Range Range}, not a\n\t * {@link module:engine/model/liverange~LiveRange LiveRange}. This means that it is up-to-date and relevant only\n\t * until next model document change. Do not store values returned by this method. Instead, store {@link ~Marker#name}\n\t * and get `Marker` instance from {@link module:engine/model/markercollection~MarkerCollection MarkerCollection} every\n\t * time there is a need to read marker properties. This will guarantee that the marker has not been removed and\n\t * that it's data is up-to-date.\n\t *\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tgetRange() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );\n\t\t}\n\n\t\treturn this._liveRange.toRange();\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tmarker.is( 'marker' ); // -> true\n\t *\t\tmarker.is( 'model:marker' ); // -> true\n\t *\n\t *\t\tmarker.is( 'view:element' ); // -> false\n\t *\t\tmarker.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'marker' || type == 'model:marker';\n\t}\n\n\t/**\n\t * Binds new live range to the marker and detach the old one if is attached.\n\t *\n\t * @protected\n\t * @param {module:engine/model/liverange~LiveRange} liveRange Live range to attach\n\t * @returns {module:engine/model/liverange~LiveRange} Attached live range.\n\t */\n\t_attachLiveRange( liveRange ) {\n\t\tif ( this._liveRange ) {\n\t\t\tthis._detachLiveRange();\n\t\t}\n\n\t\t// Delegating does not work with namespaces. Alternatively, we could delegate all events (using `*`).\n\t\tliveRange.delegate( 'change:range' ).to( this );\n\t\tliveRange.delegate( 'change:content' ).to( this );\n\n\t\tthis._liveRange = liveRange;\n\n\t\treturn liveRange;\n\t}\n\n\t/**\n\t * Unbinds and destroys currently attached live range.\n\t *\n\t * @protected\n\t */\n\t_detachLiveRange() {\n\t\tthis._liveRange.stopDelegating( 'change:range', this );\n\t\tthis._liveRange.stopDelegating( 'change:content', this );\n\t\tthis._liveRange.detach();\n\t\tthis._liveRange = null;\n\t}\n\n\t/**\n\t * Fired whenever {@link ~Marker#_liveRange marker range} is changed due to changes on {@link module:engine/model/document~Document}.\n\t * This is a delegated {@link module:engine/model/liverange~LiveRange#event:change:range LiveRange change:range event}.\n\t *\n\t * When marker is removed from {@link module:engine/model/markercollection~MarkerCollection MarkerCollection},\n\t * all event listeners listening to it should be removed. It is best to do it on\n\t * {@link module:engine/model/markercollection~MarkerCollection#event:update MarkerCollection update event}.\n\t *\n\t * @see module:engine/model/liverange~LiveRange#event:change:range\n\t * @event change:range\n\t * @param {module:engine/model/range~Range} oldRange\n\t * @param {Object} data\n\t */\n\n\t/**\n\t * Fired whenever change on {@link module:engine/model/document~Document} is done inside {@link ~Marker#_liveRange marker range}.\n\t * This is a delegated {@link module:engine/model/liverange~LiveRange#event:change:content LiveRange change:content event}.\n\t *\n\t * When marker is removed from {@link module:engine/model/markercollection~MarkerCollection MarkerCollection},\n\t * all event listeners listening to it should be removed. It is best to do it on\n\t * {@link module:engine/model/markercollection~MarkerCollection#event:update MarkerCollection update event}.\n\t *\n\t * @see module:engine/model/liverange~LiveRange#event:change:content\n\t * @event change:content\n\t * @param {module:engine/model/range~Range} oldRange\n\t * @param {Object} data\n\t */\n}\n\nmix( Marker, EmitterMixin );\n\n/**\n * Cannot use a {@link module:engine/model/markercollection~MarkerCollection#destroy destroyed marker} instance.\n *\n * @error marker-destroyed\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/nooperation\n */\n\nimport Operation from './operation';\n\n/**\n * Operation which is doing nothing (\"empty operation\", \"do-nothing operation\", \"noop\"). This is an operation,\n * which when executed does not change the tree model. It still has some parameters defined for transformation purposes.\n *\n * In most cases this operation is a result of transforming operations. When transformation returns\n * {@link module:engine/model/operation/nooperation~NoOperation} it means that changes done by the transformed operation\n * have already been applied.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class NoOperation extends Operation {\n\tget type() {\n\t\treturn 'noop';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/nooperation~NoOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new NoOperation( this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/nooperation~NoOperation}\n\t */\n\tgetReversed() {\n\t\treturn new NoOperation( this.baseVersion + 1 );\n\t}\n\n\t_execute() {\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'NoOperation';\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `NoOperation( ${ this.baseVersion } )`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/operation/operationfactory\n */\n\nimport AttributeOperation from '../operation/attributeoperation';\nimport InsertOperation from '../operation/insertoperation';\nimport MarkerOperation from '../operation/markeroperation';\nimport MoveOperation from '../operation/moveoperation';\nimport NoOperation from '../operation/nooperation';\nimport Operation from '../operation/operation';\nimport RenameOperation from '../operation/renameoperation';\nimport RootAttributeOperation from '../operation/rootattributeoperation';\nimport SplitOperation from '../operation/splitoperation';\nimport MergeOperation from '../operation/mergeoperation';\n\nconst operations = {};\noperations[ AttributeOperation.className ] = AttributeOperation;\noperations[ InsertOperation.className ] = InsertOperation;\noperations[ MarkerOperation.className ] = MarkerOperation;\noperations[ MoveOperation.className ] = MoveOperation;\noperations[ NoOperation.className ] = NoOperation;\noperations[ Operation.className ] = Operation;\noperations[ RenameOperation.className ] = RenameOperation;\noperations[ RootAttributeOperation.className ] = RootAttributeOperation;\noperations[ SplitOperation.className ] = SplitOperation;\noperations[ MergeOperation.className ] = MergeOperation;\n\n/**\n * A factory class for creating operations.\n *\n * @abstract\n */\nexport default class OperationFactory {\n\t/**\n\t * Creates an operation instance from a JSON object (parsed JSON string).\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/operation~Operation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn operations[ json.__className ].fromJSON( json, document );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/liveposition\n */\n\nimport Position from './position';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * `LivePosition` is a type of {@link module:engine/model/position~Position Position}\n * that updates itself as {@link module:engine/model/document~Document document}\n * is changed through operations. It may be used as a bookmark.\n *\n * **Note:** Contrary to {@link module:engine/model/position~Position}, `LivePosition` works only in roots that are\n * {@link module:engine/model/rootelement~RootElement}.\n * If {@link module:engine/model/documentfragment~DocumentFragment} is passed, error will be thrown.\n *\n * **Note:** Be very careful when dealing with `LivePosition`. Each `LivePosition` instance bind events that might\n * have to be unbound.\n * Use {@link module:engine/model/liveposition~LivePosition#detach} whenever you don't need `LivePosition` anymore.\n *\n * @extends module:engine/model/position~Position\n */\nexport default class LivePosition extends Position {\n\t/**\n\t * Creates a live position.\n\t *\n\t * @see module:engine/model/position~Position\n\t * @param {module:engine/model/rootelement~RootElement} root\n\t * @param {Array.<Number>} path\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness]\n\t */\n\tconstructor( root, path, stickiness = 'toNone' ) {\n\t\tsuper( root, path, stickiness );\n\n\t\tif ( !this.root.is( 'rootElement' ) ) {\n\t\t\t/**\n\t\t\t * LivePosition's root has to be an instance of RootElement.\n\t\t\t *\n\t\t\t * @error liveposition-root-not-rootelement\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-liveposition-root-not-rootelement: LivePosition\\'s root has to be an instance of RootElement.',\n\t\t\t\troot\n\t\t\t);\n\t\t}\n\n\t\tbindWithDocument.call( this );\n\t}\n\n\t/**\n\t * Unbinds all events previously bound by `LivePosition`. Use it whenever you don't need `LivePosition` instance\n\t * anymore (i.e. when leaving scope in which it was declared or before re-assigning variable that was\n\t * referring to it).\n\t */\n\tdetach() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tlivePosition.is( 'position' ); // -> true\n\t *\t\tlivePosition.is( 'model:position' ); // -> true\n\t *\t\tlivePosition.is( 'liveposition' ); // -> true\n\t *\t\tlivePosition.is( 'model:livePosition' ); // -> true\n\t *\n\t *\t\tlivePosition.is( 'view:position' ); // -> false\n\t *\t\tlivePosition.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type == 'livePosition' || type == 'model:livePosition' || super.is( type );\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/position~Position position instance}, which is equal to this live position.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\ttoPosition() {\n\t\treturn new Position( this.root, this.path.slice(), this.stickiness );\n\t}\n\n\t/**\n\t * Creates a `LivePosition` instance that is equal to position.\n\t *\n\t * @param {module:engine/model/position~Position} position\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness]\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tstatic fromPosition( position, stickiness ) {\n\t\treturn new this( position.root, position.path.slice(), stickiness ? stickiness : position.stickiness );\n\t}\n\n\t/**\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liveposition~LivePosition._createAfter\n\t * @see module:engine/model/position~Position._createAfter\n\t * @param {module:engine/model/node~Node} node\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone']\n\t * @returns {module:engine/model/liveposition~LivePosition}\n\t */\n\n\t/**\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liveposition~LivePosition._createBefore\n\t * @see module:engine/model/position~Position._createBefore\n\t * @param {module:engine/model/node~Node} node\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone']\n\t * @returns {module:engine/model/liveposition~LivePosition}\n\t */\n\n\t/**\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liveposition~LivePosition._createAt\n\t * @see module:engine/model/position~Position._createAt\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset]\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone']\n\t * @returns {module:engine/model/liveposition~LivePosition}\n\t */\n\n\t/**\n\t * Fired when `LivePosition` instance is changed due to changes on {@link module:engine/model/document~Document}.\n\t *\n\t * @event module:engine/model/liveposition~LivePosition#change\n\t * @param {module:engine/model/position~Position} oldPosition Position equal to this live position before it got changed.\n\t */\n}\n\n// Binds this `LivePosition` to the {@link module:engine/model/document~Document document} that owns\n// this position's {@link module:engine/model/position~Position#root root}.\n//\n// @private\nfunction bindWithDocument() {\n\tthis.listenTo(\n\t\tthis.root.document.model,\n\t\t'applyOperation',\n\t\t( event, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( !operation.isDocumentOperation ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttransform.call( this, operation );\n\t\t},\n\t\t{ priority: 'low' }\n\t);\n}\n\n// Updates this position accordingly to the updates applied to the model. Bases on change events.\n//\n// @private\n// @param {module:engine/model/operation/operation~Operation} operation Executed operation.\nfunction transform( operation ) {\n\tconst result = this.getTransformedByOperation( operation );\n\n\tif ( !this.isEqual( result ) ) {\n\t\tconst oldPosition = this.toPosition();\n\n\t\tthis.path = result.path;\n\t\tthis.root = result.root;\n\n\t\tthis.fire( 'change', oldPosition );\n\t}\n}\n\nmix( LivePosition, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/utils/insertcontent\n */\n\nimport Position from '../position';\nimport LivePosition from '../liveposition';\nimport Element from '../element';\nimport Range from '../range';\nimport DocumentSelection from '../documentselection';\nimport Selection from '../selection';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Inserts content into the editor (specified selection) as one would expect the paste\n * functionality to work.\n *\n * If an instance of {@link module:engine/model/selection~Selection} is passed as `selectable` it will be modified\n * to the insertion selection (equal to a range to be selected after insertion).\n *\n * If `selectable` is not passed, the content will be inserted using the current selection of the model document.\n *\n * **Note:** Use {@link module:engine/model/model~Model#insertContent} instead of this function.\n * This function is only exposed to be reusable in algorithms which change the {@link module:engine/model/model~Model#insertContent}\n * method's behavior.\n *\n * @param {module:engine/model/model~Model} model The model in context of which the insertion\n * should be performed.\n * @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.\n * @param {module:engine/model/selection~Selectable} [selectable=model.document.selection]\n * Selection into which the content should be inserted.\n * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n * @returns {module:engine/model/range~Range} Range which contains all the performed changes. This is a range that, if removed,\n * would return the model to the state before the insertion. If no changes were preformed by `insertContent`, returns a range collapsed\n * at the insertion position.\n */\nexport default function insertContent( model, content, selectable, placeOrOffset ) {\n\treturn model.change( writer => {\n\t\tlet selection;\n\n\t\tif ( !selectable ) {\n\t\t\tselection = model.document.selection;\n\t\t} else if ( selectable instanceof Selection || selectable instanceof DocumentSelection ) {\n\t\t\tselection = selectable;\n\t\t} else {\n\t\t\tselection = writer.createSelection( selectable, placeOrOffset );\n\t\t}\n\n\t\tconst insertionPosition = selection.getFirstPosition();\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\tmodel.deleteContent( selection, { doNotAutoparagraph: true } );\n\t\t}\n\n\t\tconst insertion = new Insertion( model, writer, insertionPosition );\n\n\t\tlet nodesToInsert;\n\n\t\tif ( content.is( 'documentFragment' ) ) {\n\t\t\tnodesToInsert = content.getChildren();\n\t\t} else {\n\t\t\tnodesToInsert = [ content ];\n\t\t}\n\n\t\tinsertion.handleNodes( nodesToInsert, {\n\t\t\t// The set of children being inserted is the only set in this context\n\t\t\t// so it's the first and last (it's a hack ;)).\n\t\t\tisFirst: true,\n\t\t\tisLast: true\n\t\t} );\n\n\t\tconst newRange = insertion.getSelectionRange();\n\n\t\t/* istanbul ignore else */\n\t\tif ( newRange ) {\n\t\t\tif ( selection instanceof DocumentSelection ) {\n\t\t\t\twriter.setSelection( newRange );\n\t\t\t} else {\n\t\t\t\tselection.setTo( newRange );\n\t\t\t}\n\t\t} else {\n\t\t\t// We are not testing else because it's a safe check for unpredictable edge cases:\n\t\t\t// an insertion without proper range to select.\n\t\t\t//\n\t\t\t// @if CK_DEBUG // console.warn( 'Cannot determine a proper selection range after insertion.' );\n\t\t}\n\n\t\tconst affectedRange = insertion.getAffectedRange() || model.createRange( insertionPosition );\n\n\t\tinsertion.destroy();\n\n\t\treturn affectedRange;\n\t} );\n}\n\n/**\n * Utility class for performing content insertion.\n *\n * @private\n */\nclass Insertion {\n\tconstructor( model, writer, position ) {\n\t\t/**\n\t\t * The model in context of which the insertion should be performed.\n\t\t *\n\t\t * @member {module:engine/model~Model} #model\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * Batch to which operations will be added.\n\t\t *\n\t\t * @member {module:engine/controller/writer~Batch} #writer\n\t\t */\n\t\tthis.writer = writer;\n\n\t\t/**\n\t\t * The position at which (or near which) the next node will be inserted.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} #position\n\t\t */\n\t\tthis.position = position;\n\n\t\t/**\n\t\t * Elements with which the inserted elements can be merged.\n\t\t *\n\t\t *\t\t<p>x^</p><p>y</p> + <p>z</p> (can merge to <p>x</p>)\n\t\t *\t\t<p>x</p><p>^y</p> + <p>z</p> (can merge to <p>y</p>)\n\t\t *\t\t<p>x^y</p> + <p>z</p> (can merge to <p>xy</p> which will be split during the action,\n\t\t *\t\t\t\t\t\t\t\tso both its pieces will be added to this set)\n\t\t *\n\t\t *\n\t\t * @member {Set} #canMergeWith\n\t\t */\n\t\tthis.canMergeWith = new Set( [ this.position.parent ] );\n\n\t\t/**\n\t\t * Schema of the model.\n\t\t *\n\t\t * @member {module:engine/model/schema~Schema} #schema\n\t\t */\n\t\tthis.schema = model.schema;\n\n\t\tthis._filterAttributesOf = [];\n\n\t\t/**\n\t\t * Beginning of the affected range. See {@link module:engine/model/utils/insertcontent~Insertion#getAffectedRange}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/liveposition~LivePosition|null} #_affectedStart\n\t\t */\n\t\tthis._affectedStart = null;\n\n\t\t/**\n\t\t * End of the affected range. See {@link module:engine/model/utils/insertcontent~Insertion#getAffectedRange}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/liveposition~LivePosition|null} #_affectedEnd\n\t\t */\n\t\tthis._affectedEnd = null;\n\t}\n\n\t/**\n\t * Handles insertion of a set of nodes.\n\t *\n\t * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes to insert.\n\t * @param {Object} parentContext Context in which parent of these nodes was supposed to be inserted.\n\t * If the parent context is passed it means that the parent element was stripped (was not allowed).\n\t */\n\thandleNodes( nodes, parentContext ) {\n\t\tnodes = Array.from( nodes );\n\n\t\tfor ( let i = 0; i < nodes.length; i++ ) {\n\t\t\tconst node = nodes[ i ];\n\n\t\t\tthis._handleNode( node, {\n\t\t\t\tisFirst: i === 0 && parentContext.isFirst,\n\t\t\t\tisLast: ( i === ( nodes.length - 1 ) ) && parentContext.isLast\n\t\t\t} );\n\t\t}\n\n\t\t// TMP this will become a post-fixer.\n\t\tthis.schema.removeDisallowedAttributes( this._filterAttributesOf, this.writer );\n\t\tthis._filterAttributesOf = [];\n\t}\n\n\t/**\n\t * Returns range to be selected after insertion.\n\t * Returns `null` if there is no valid range to select after insertion.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetSelectionRange() {\n\t\tif ( this.nodeToSelect ) {\n\t\t\treturn Range._createOn( this.nodeToSelect );\n\t\t}\n\n\t\treturn this.model.schema.getNearestSelectionRange( this.position );\n\t}\n\n\t/**\n\t * Returns a range which contains all the performed changes. This is a range that, if removed, would return the model to the state\n\t * before the insertion. Returns `null` if no changes were done.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetAffectedRange() {\n\t\tif ( !this._affectedStart ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn new Range( this._affectedStart, this._affectedEnd );\n\t}\n\n\t/**\n\t * Destroys `Insertion` instance.\n\t */\n\tdestroy() {\n\t\tif ( this._affectedStart ) {\n\t\t\tthis._affectedStart.detach();\n\t\t}\n\n\t\tif ( this._affectedEnd ) {\n\t\t\tthis._affectedEnd.detach();\n\t\t}\n\t}\n\n\t/**\n\t * Handles insertion of a single node.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node\n\t * @param {Object} context\n\t * @param {Boolean} context.isFirst Whether the given node is the first one in the content to be inserted.\n\t * @param {Boolean} context.isLast Whether the given node is the last one in the content to be inserted.\n\t */\n\t_handleNode( node, context ) {\n\t\t// Let's handle object in a special way.\n\t\t// * They should never be merged with other elements.\n\t\t// * If they are not allowed in any of the selection ancestors, they could be either autoparagraphed or totally removed.\n\t\tif ( this.schema.isObject( node ) ) {\n\t\t\tthis._handleObject( node, context );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Try to find a place for the given node.\n\t\t// Split the position.parent's branch up to a point where the node can be inserted.\n\t\t// If it isn't allowed in the whole branch, then of course don't split anything.\n\t\tconst isAllowed = this._checkAndSplitToAllowedPosition( node, context );\n\n\t\tif ( !isAllowed ) {\n\t\t\tthis._handleDisallowedNode( node, context );\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis._insert( node );\n\n\t\t// After the node was inserted we may try to merge it with its siblings.\n\t\t// This should happen only if it was the first and/or last of the nodes (so only with boundary nodes)\n\t\t// and only if the selection was in those elements initially.\n\t\t//\n\t\t// E.g.:\n\t\t// <p>x^</p> + <p>y</p> => <p>x</p><p>y</p> => <p>xy[]</p>\n\t\t// and:\n\t\t// <p>x^y</p> + <p>z</p> => <p>x</p>^<p>y</p> + <p>z</p> => <p>x</p><p>z</p><p>y</p> => <p>xz[]y</p>\n\t\t// but:\n\t\t// <p>x</p><p>^</p><p>z</p> + <p>y</p> => <p>x</p><p>y</p><p>z</p> (no merging)\n\t\t// <p>x</p>[<img>]<p>z</p> + <p>y</p> => <p>x</p><p>y</p><p>z</p> (no merging, note: after running deleteContents\n\t\t//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t it's exactly the same case as above)\n\t\tthis._mergeSiblingsOf( node, context );\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/element~Element} node The object element.\n\t * @param {Object} context\n\t */\n\t_handleObject( node, context ) {\n\t\t// Try finding it a place in the tree.\n\t\tif ( this._checkAndSplitToAllowedPosition( node ) ) {\n\t\t\tthis._insert( node );\n\t\t}\n\t\t// Try autoparagraphing.\n\t\telse {\n\t\t\tthis._tryAutoparagraphing( node, context );\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/node~Node} node The disallowed node which needs to be handled.\n\t * @param {Object} context\n\t */\n\t_handleDisallowedNode( node, context ) {\n\t\t// If the node is an element, try inserting its children (strip the parent).\n\t\tif ( node.is( 'element' ) ) {\n\t\t\tthis.handleNodes( node.getChildren(), context );\n\t\t}\n\t\t// If text is not allowed, try autoparagraphing it.\n\t\telse {\n\t\t\tthis._tryAutoparagraphing( node, context );\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node to insert.\n\t */\n\t_insert( node ) {\n\t\t/* istanbul ignore if */\n\t\tif ( !this.schema.checkChild( this.position, node ) ) {\n\t\t\t// Algorithm's correctness check. We should never end up here but it's good to know that we did.\n\t\t\t// Note that it would often be a silent issue if we insert node in a place where it's not allowed.\n\n\t\t\t/**\n\t\t\t * Given node cannot be inserted on the given position.\n\t\t\t *\n\t\t\t * @error insertcontent-wrong-position\n\t\t\t * @param {module:engine/model/node~Node} node Node to insert.\n\t\t\t * @param {module:engine/model/position~Position} position Position to insert the node at.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'insertcontent-wrong-position: Given node cannot be inserted on the given position.',\n\t\t\t\tthis,\n\t\t\t\t{ node, position: this.position }\n\t\t\t);\n\t\t}\n\n\t\tconst livePos = LivePosition.fromPosition( this.position, 'toNext' );\n\n\t\tthis._setAffectedBoundaries( this.position );\n\t\tthis.writer.insert( node, this.position );\n\n\t\tthis.position = livePos.toPosition();\n\t\tlivePos.detach();\n\n\t\t// The last inserted object should be selected because we can't put a collapsed selection after it.\n\t\tif ( this.schema.isObject( node ) && !this.schema.checkChild( this.position, '$text' ) ) {\n\t\t\tthis.nodeToSelect = node;\n\t\t} else {\n\t\t\tthis.nodeToSelect = null;\n\t\t}\n\n\t\tthis._filterAttributesOf.push( node );\n\t}\n\n\t/**\n\t * Sets `_affectedStart` and `_affectedEnd` to the given `position`. Should be used before a change is done during insertion process to\n\t * mark the affected range.\n\t *\n\t * This method is used before inserting a node or splitting a parent node. `_affectedStart` and `_affectedEnd` are also changed\n\t * during merging, but the logic there is more complicated so it is left out of this function.\n\t *\n\t * @private\n\t * @param {module:engine/model/position~Position} position\n\t */\n\t_setAffectedBoundaries( position ) {\n\t\t// Set affected boundaries stickiness so that those position will \"expand\" when something is inserted in between them:\n\t\t// <paragraph>Foo][bar</paragraph> -> <paragraph>Foo]xx[bar</paragraph>\n\t\t// This is why it cannot be a range but two separate positions.\n\t\tif ( !this._affectedStart ) {\n\t\t\tthis._affectedStart = LivePosition.fromPosition( position, 'toPrevious' );\n\t\t}\n\n\t\t// If `_affectedEnd` is before the new boundary position, expand `_affectedEnd`. This can happen if first inserted node was\n\t\t// inserted into the parent but the next node is moved-out of that parent:\n\t\t// (1) <paragraph>Foo][</paragraph> -> <paragraph>Foo]xx[</paragraph>\n\t\t// (2) <paragraph>Foo]xx[</paragraph> -> <paragraph>Foo]xx</paragraph><widget></widget>[\n\t\tif ( !this._affectedEnd || this._affectedEnd.isBefore( position ) ) {\n\t\t\tif ( this._affectedEnd ) {\n\t\t\t\tthis._affectedEnd.detach();\n\t\t\t}\n\n\t\t\tthis._affectedEnd = LivePosition.fromPosition( position, 'toNext' );\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which could potentially be merged.\n\t * @param {Object} context\n\t */\n\t_mergeSiblingsOf( node, context ) {\n\t\tif ( !( node instanceof Element ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst mergeLeft = this._canMergeLeft( node, context );\n\t\tconst mergeRight = this._canMergeRight( node, context );\n\t\tconst mergePosLeft = LivePosition._createBefore( node );\n\t\tmergePosLeft.stickiness = 'toNext';\n\t\tconst mergePosRight = LivePosition._createAfter( node );\n\t\tmergePosRight.stickiness = 'toNext';\n\n\t\tif ( mergeLeft ) {\n\t\t\tconst livePosition = LivePosition.fromPosition( this.position );\n\t\t\tlivePosition.stickiness = 'toNext';\n\n\t\t\t// If `_affectedStart` is sames as merge position, it means that the element \"marked\" by `_affectedStart` is going to be\n\t\t\t// removed and its contents will be moved. This won't transform `LivePosition` so `_affectedStart` needs to be moved\n\t\t\t// by hand to properly reflect affected range. (Due to `_affectedStart` and `_affectedEnd` stickiness, the \"range\" is\n\t\t\t// shown as `][`).\n\t\t\t//\n\t\t\t// Example - insert `<paragraph>Abc</paragraph><paragraph>Xyz</paragraph>` at the end of `<paragraph>Foo^</paragraph>`:\n\t\t\t//\n\t\t\t// <paragraph>Foo</paragraph><paragraph>Bar</paragraph> -->\n\t\t\t// <paragraph>Foo</paragraph>]<paragraph>Abc</paragraph><paragraph>Xyz</paragraph>[<paragraph>Bar</paragraph> -->\n\t\t\t// <paragraph>Foo]Abc</paragraph><paragraph>Xyz</paragraph>[<paragraph>Bar</paragraph>\n\t\t\t//\n\t\t\t// Note, that if we are here then something must have been inserted, so `_affectedStart` and `_affectedEnd` have to be set.\n\t\t\tif ( this._affectedStart.isEqual( mergePosLeft ) ) {\n\t\t\t\tthis._affectedStart.detach();\n\t\t\t\tthis._affectedStart = LivePosition._createAt( mergePosLeft.nodeBefore, 'end', 'toPrevious' );\n\t\t\t}\n\n\t\t\tthis.writer.merge( mergePosLeft );\n\n\t\t\t// If only one element (the merged one) is in the \"affected range\", also move the affected range end appropriately.\n\t\t\t//\n\t\t\t// Example - insert `<paragraph>Abc</paragraph>` at the of `<paragraph>Foo^</paragraph>`:\n\t\t\t//\n\t\t\t// <paragraph>Foo</paragraph><paragraph>Bar</paragraph> -->\n\t\t\t// <paragraph>Foo</paragraph>]<paragraph>Abc</paragraph>[<paragraph>Bar</paragraph> -->\n\t\t\t// <paragraph>Foo]Abc</paragraph>[<paragraph>Bar</paragraph> -->\n\t\t\t// <paragraph>Foo]Abc[</paragraph><paragraph>Bar</paragraph>\n\t\t\tif ( mergePosLeft.isEqual( this._affectedEnd ) && context.isLast ) {\n\t\t\t\tthis._affectedEnd.detach();\n\t\t\t\tthis._affectedEnd = LivePosition._createAt( mergePosLeft.nodeBefore, 'end', 'toNext' );\n\t\t\t}\n\n\t\t\tthis.position = livePosition.toPosition();\n\t\t\tlivePosition.detach();\n\t\t}\n\n\t\tif ( mergeRight ) {\n\t\t\t/* istanbul ignore if */\n\t\t\tif ( !this.position.isEqual( mergePosRight ) ) {\n\t\t\t\t// Algorithm's correctness check. We should never end up here but it's good to know that we did.\n\t\t\t\t// At this point the insertion position should be after the node we'll merge. If it isn't,\n\t\t\t\t// it should need to be secured as in the left merge case.\n\t\t\t\t/**\n\t\t\t\t * An internal error occured during merging insertion content with siblings.\n\t\t\t\t * The insertion position should equal to the merge position.\n\t\t\t\t *\n\t\t\t\t * @error insertcontent-invalid-insertion-position\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'insertcontent-invalid-insertion-position', this );\n\t\t\t}\n\n\t\t\t// Move the position to the previous node, so it isn't moved to the graveyard on merge.\n\t\t\t// <p>x</p>[]<p>y</p> => <p>x[]</p><p>y</p>\n\t\t\tthis.position = Position._createAt( mergePosRight.nodeBefore, 'end' );\n\n\t\t\t// OK: <p>xx[]</p> + <p>yy</p> => <p>xx[]yy</p> (when sticks to previous)\n\t\t\t// NOK: <p>xx[]</p> + <p>yy</p> => <p>xxyy[]</p> (when sticks to next)\n\t\t\tconst livePosition = LivePosition.fromPosition( this.position, 'toPrevious' );\n\n\t\t\t// See comment above on moving `_affectedStart`.\n\t\t\tif ( this._affectedEnd.isEqual( mergePosRight ) ) {\n\t\t\t\tthis._affectedEnd.detach();\n\t\t\t\tthis._affectedEnd = LivePosition._createAt( mergePosRight.nodeBefore, 'end', 'toNext' );\n\t\t\t}\n\n\t\t\tthis.writer.merge( mergePosRight );\n\n\t\t\t// See comment above on moving `_affectedStart`.\n\t\t\tif ( mergePosRight.getShiftedBy( -1 ).isEqual( this._affectedStart ) && context.isFirst ) {\n\t\t\t\tthis._affectedStart.detach();\n\t\t\t\tthis._affectedStart = LivePosition._createAt( mergePosRight.nodeBefore, 0, 'toPrevious' );\n\t\t\t}\n\n\t\t\tthis.position = livePosition.toPosition();\n\t\t\tlivePosition.detach();\n\t\t}\n\n\t\tif ( mergeLeft || mergeRight ) {\n\t\t\t// After merge elements that were marked by _insert() to be filtered might be gone so\n\t\t\t// we need to mark the new container.\n\t\t\tthis._filterAttributesOf.push( this.position.parent );\n\t\t}\n\n\t\tmergePosLeft.detach();\n\t\tmergePosRight.detach();\n\t}\n\n\t/**\n\t * Checks whether specified node can be merged with previous sibling element.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which could potentially be merged.\n\t * @param {Object} context\n\t * @returns {Boolean}\n\t */\n\t_canMergeLeft( node, context ) {\n\t\tconst previousSibling = node.previousSibling;\n\n\t\treturn context.isFirst &&\n\t\t\t( previousSibling instanceof Element ) &&\n\t\t\tthis.canMergeWith.has( previousSibling ) &&\n\t\t\tthis.model.schema.checkMerge( previousSibling, node );\n\t}\n\n\t/**\n\t * Checks whether specified node can be merged with next sibling element.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which could potentially be merged.\n\t * @param {Object} context\n\t * @returns {Boolean}\n\t */\n\t_canMergeRight( node, context ) {\n\t\tconst nextSibling = node.nextSibling;\n\n\t\treturn context.isLast &&\n\t\t\t( nextSibling instanceof Element ) &&\n\t\t\tthis.canMergeWith.has( nextSibling ) &&\n\t\t\tthis.model.schema.checkMerge( node, nextSibling );\n\t}\n\n\t/**\n\t * Tries wrapping the node in a new paragraph and inserting it this way.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which needs to be autoparagraphed.\n\t * @param {Object} context\n\t */\n\t_tryAutoparagraphing( node, context ) {\n\t\tconst paragraph = this.writer.createElement( 'paragraph' );\n\n\t\t// Do not autoparagraph if the paragraph won't be allowed there,\n\t\t// cause that would lead to an infinite loop. The paragraph would be rejected in\n\t\t// the next _handleNode() call and we'd be here again.\n\t\tif ( this._getAllowedIn( paragraph, this.position.parent ) && this.schema.checkChild( paragraph, node ) ) {\n\t\t\tparagraph._appendChild( node );\n\t\t\tthis._handleNode( paragraph, context );\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/node~Node} node\n\t * @returns {Boolean} Whether an allowed position was found.\n\t * `false` is returned if the node isn't allowed at any position up in the tree, `true` if was.\n\t */\n\t_checkAndSplitToAllowedPosition( node ) {\n\t\tconst allowedIn = this._getAllowedIn( node, this.position.parent );\n\n\t\tif ( !allowedIn ) {\n\t\t\treturn false;\n\t\t}\n\n\t\twhile ( allowedIn != this.position.parent ) {\n\t\t\t// If a parent which we'd need to leave is a limit element, break.\n\t\t\tif ( this.schema.isLimit( this.position.parent ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif ( this.position.isAtStart ) {\n\t\t\t\t// If insertion position is at the beginning of the parent, move it out instead of splitting.\n\t\t\t\t// <p>^Foo</p> -> ^<p>Foo</p>\n\t\t\t\tconst parent = this.position.parent;\n\n\t\t\t\tthis.position = this.writer.createPositionBefore( parent );\n\n\t\t\t\t// Special case – parent is empty (<p>^</p>).\n\t\t\t\t//\n\t\t\t\t// 1. parent.isEmpty\n\t\t\t\t// We can remove the element after moving insertion position out of it.\n\t\t\t\t//\n\t\t\t\t// 2. parent.parent === allowedIn\n\t\t\t\t// However parent should remain in place when allowed element is above limit element in document tree.\n\t\t\t\t// For example there shouldn't be allowed to remove empty paragraph from tableCell, when is pasted\n\t\t\t\t// content allowed in $root.\n\t\t\t\tif ( parent.isEmpty && parent.parent === allowedIn ) {\n\t\t\t\t\tthis.writer.remove( parent );\n\t\t\t\t}\n\t\t\t} else if ( this.position.isAtEnd ) {\n\t\t\t\t// If insertion position is at the end of the parent, move it out instead of splitting.\n\t\t\t\t// <p>Foo^</p> -> <p>Foo</p>^\n\t\t\t\tthis.position = this.writer.createPositionAfter( this.position.parent );\n\t\t\t} else {\n\t\t\t\tconst tempPos = this.writer.createPositionAfter( this.position.parent );\n\n\t\t\t\tthis._setAffectedBoundaries( this.position );\n\t\t\t\tthis.writer.split( this.position );\n\n\t\t\t\tthis.position = tempPos;\n\n\t\t\t\tthis.canMergeWith.add( this.position.nodeAfter );\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Gets the element in which the given node is allowed. It checks the passed element and all its ancestors.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node to check.\n\t * @param {module:engine/model/element~Element} element The element in which the node's correctness should be checked.\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\t_getAllowedIn( node, element ) {\n\t\tif ( this.schema.checkChild( element, node ) ) {\n\t\t\treturn element;\n\t\t}\n\n\t\tif ( element.parent ) {\n\t\t\treturn this._getAllowedIn( node, element.parent );\n\t\t}\n\n\t\treturn null;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/utils/deletecontent\n */\n\nimport LivePosition from '../liveposition';\nimport Range from '../range';\nimport DocumentSelection from '../documentselection';\n\n/**\n * Deletes content of the selection and merge siblings. The resulting selection is always collapsed.\n *\n * **Note:** Use {@link module:engine/model/model~Model#deleteContent} instead of this function.\n * This function is only exposed to be reusable in algorithms\n * which change the {@link module:engine/model/model~Model#deleteContent}\n * method's behavior.\n *\n * @param {module:engine/model/model~Model} model The model in context of which the insertion\n * should be performed.\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * Selection of which the content should be deleted.\n * @param {Object} [options]\n * @param {Boolean} [options.leaveUnmerged=false] Whether to merge elements after removing the content of the selection.\n *\n * For example `<heading>x[x</heading><paragraph>y]y</paragraph>` will become:\n *\n * * `<heading>x^y</heading>` with the option disabled (`leaveUnmerged == false`)\n * * `<heading>x^</heading><paragraph>y</paragraph>` with enabled (`leaveUnmerged == true`).\n *\n * Note: {@link module:engine/model/schema~Schema#isObject object} and {@link module:engine/model/schema~Schema#isLimit limit}\n * elements will not be merged.\n *\n * @param {Boolean} [options.doNotResetEntireContent=false] Whether to skip replacing the entire content with a\n * paragraph when the entire content was selected.\n *\n * For example `<heading>[x</heading><paragraph>y]</paragraph>` will become:\n *\n * * `<paragraph>^</paragraph>` with the option disabled (`doNotResetEntireContent == false`)\n * * `<heading>^</heading>` with enabled (`doNotResetEntireContent == true`).\n *\n * @param {Boolean} [options.doNotAutoparagraph=false] Whether to create a paragraph if after content deletion selection is moved\n * to a place where text cannot be inserted.\n *\n * For example `<paragraph>x</paragraph>[<image src=\"foo.jpg\"></image>]` will become:\n *\n * * `<paragraph>x</paragraph><paragraph>[]</paragraph>` with the option disabled (`doNotAutoparagraph == false`)\n * * `<paragraph>x[]</paragraph>` with the option enabled (`doNotAutoparagraph == true`).\n *\n * **Note:** if there is no valid position for the selection, the paragraph will always be created:\n *\n * `[<image src=\"foo.jpg\"></image>]` -> `<paragraph>[]</paragraph>`.\n */\nexport default function deleteContent( model, selection, options = {} ) {\n\tif ( selection.isCollapsed ) {\n\t\treturn;\n\t}\n\n\tconst selRange = selection.getFirstRange();\n\n\t// If the selection is already removed, don't do anything.\n\tif ( selRange.root.rootName == '$graveyard' ) {\n\t\treturn;\n\t}\n\n\tconst schema = model.schema;\n\n\tmodel.change( writer => {\n\t\t// 1. Replace the entire content with paragraph.\n\t\t// See: https://github.com/ckeditor/ckeditor5-engine/issues/1012#issuecomment-315017594.\n\t\tif ( !options.doNotResetEntireContent && shouldEntireContentBeReplacedWithParagraph( schema, selection ) ) {\n\t\t\treplaceEntireContentWithParagraph( writer, selection, schema );\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst startPos = selRange.start;\n\t\tconst endPos = LivePosition.fromPosition( selRange.end, 'toNext' );\n\n\t\t// 2. Remove the content if there is any.\n\t\tif ( !selRange.start.isTouching( selRange.end ) ) {\n\t\t\twriter.remove( selRange );\n\t\t}\n\n\t\t// 3. Merge elements in the right branch to the elements in the left branch.\n\t\t// The only reasonable (in terms of data and selection correctness) case in which we need to do that is:\n\t\t//\n\t\t// <heading type=1>Fo[</heading><paragraph>]ar</paragraph> => <heading type=1>Fo^ar</heading>\n\t\t//\n\t\t// However, the algorithm supports also merging deeper structures (up to the depth of the shallower branch),\n\t\t// as it's hard to imagine what should actually be the default behavior. Usually, specific features will\n\t\t// want to override that behavior anyway.\n\t\tif ( !options.leaveUnmerged ) {\n\t\t\tmergeBranches( writer, startPos, endPos );\n\n\t\t\t// TMP this will be replaced with a postfixer.\n\t\t\t// We need to check and strip disallowed attributes in all nested nodes because after merge\n\t\t\t// some attributes could end up in a path where are disallowed.\n\t\t\t//\n\t\t\t// e.g. bold is disallowed for <H1>\n\t\t\t// <h1>Fo{o</h1><p>b}a<b>r</b><p> -> <h1>Fo{}a<b>r</b><h1> -> <h1>Fo{}ar<h1>.\n\t\t\tschema.removeDisallowedAttributes( startPos.parent.getChildren(), writer );\n\t\t}\n\n\t\tcollapseSelectionAt( writer, selection, startPos );\n\n\t\t// 4. Add a paragraph to set selection in it.\n\t\t// Check if a text is allowed in the new container. If not, try to create a new paragraph (if it's allowed here).\n\t\tif ( shouldAutoparagraph( schema, startPos ) ) {\n\t\t\t// If auto-paragraphing is off, find the closest valid selection range and collapse the selection there.\n\t\t\t// If there is no valid selection range, create paragraph anyway and set selection there.\n\t\t\tconst validSelectionRange = schema.getNearestSelectionRange( startPos );\n\n\t\t\tif ( options.doNotAutoparagraph && validSelectionRange ) {\n\t\t\t\tcollapseSelectionAt( writer, selection, validSelectionRange );\n\t\t\t} else {\n\t\t\t\tinsertParagraph( writer, startPos, selection );\n\t\t\t}\n\t\t}\n\n\t\tendPos.detach();\n\t} );\n}\n\n// This function is a result of reaching the Ballmer's peak for just the right amount of time.\n// Even I had troubles documenting it after a while and after reading it again I couldn't believe that it really works.\nfunction mergeBranches( writer, startPos, endPos ) {\n\tconst startParent = startPos.parent;\n\tconst endParent = endPos.parent;\n\n\t// If both positions ended up in the same parent, then there's nothing more to merge:\n\t// <$root><p>x[]</p><p>{}y</p></$root> => <$root><p>xy</p>[]{}</$root>\n\tif ( startParent == endParent ) {\n\t\treturn;\n\t}\n\n\t// If one of the positions is a limit element, then there's nothing to merge because we don't want to cross the limit boundaries.\n\tif ( writer.model.schema.isLimit( startParent ) || writer.model.schema.isLimit( endParent ) ) {\n\t\treturn;\n\t}\n\n\t// Check if operations we'll need to do won't need to cross object or limit boundaries.\n\t// E.g., we can't merge endParent into startParent in this case:\n\t// <limit><startParent>x[]</startParent></limit><endParent>{}</endParent>\n\tif ( !checkCanBeMerged( startPos, endPos, writer.model.schema ) ) {\n\t\treturn;\n\t}\n\n\t// Remember next positions to merge. For example:\n\t// <a><b>x[]</b></a><c><d>{}y</d></c>\n\t// will become:\n\t// <a><b>xy</b>[]</a><c>{}</c>\n\tstartPos = writer.createPositionAfter( startParent );\n\tendPos = writer.createPositionBefore( endParent );\n\n\tif ( !endPos.isEqual( startPos ) ) {\n\t\t// In this case, before we merge, we need to move `endParent` to the `startPos`:\n\t\t// <a><b>x[]</b></a><c><d>{}y</d></c>\n\t\t// becomes:\n\t\t// <a><b>x</b>[]<d>y</d></a><c>{}</c>\n\t\twriter.insert( endParent, startPos );\n\t}\n\n\t// Merge two siblings:\n\t// <a>x</a>[]<b>y</b> -> <a>xy</a> (the usual case)\n\t// <a><b>x</b>[]<d>y</d></a><c></c> -> <a><b>xy</b>[]</a><c></c> (this is the \"move parent\" case shown above)\n\twriter.merge( startPos );\n\n\t// Remove empty end ancestors:\n\t// <a>fo[o</a><b><a><c>bar]</c></a></b>\n\t// becomes:\n\t// <a>fo[]</a><b><a>{}</a></b>\n\t// So we can remove <a> and <b>.\n\twhile ( endPos.parent.isEmpty ) {\n\t\tconst parentToRemove = endPos.parent;\n\n\t\tendPos = writer.createPositionBefore( parentToRemove );\n\n\t\twriter.remove( parentToRemove );\n\t}\n\n\t// Continue merging next level.\n\tmergeBranches( writer, startPos, endPos );\n}\n\nfunction shouldAutoparagraph( schema, position ) {\n\tconst isTextAllowed = schema.checkChild( position, '$text' );\n\tconst isParagraphAllowed = schema.checkChild( position, 'paragraph' );\n\n\treturn !isTextAllowed && isParagraphAllowed;\n}\n\n// Check if parents of two positions can be merged by checking if there are no limit/object\n// boundaries between those two positions.\n//\n// E.g. in <bQ><p>x[]</p></bQ><widget><caption>{}</caption></widget>\n// we'll check <p>, <bQ>, <widget> and <caption>.\n// Usually, widget and caption are marked as objects/limits in the schema, so in this case merging will be blocked.\nfunction checkCanBeMerged( leftPos, rightPos, schema ) {\n\tconst rangeToCheck = new Range( leftPos, rightPos );\n\n\tfor ( const value of rangeToCheck.getWalker() ) {\n\t\tif ( schema.isLimit( value.item ) ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nfunction insertParagraph( writer, position, selection ) {\n\tconst paragraph = writer.createElement( 'paragraph' );\n\n\twriter.insert( paragraph, position );\n\n\tcollapseSelectionAt( writer, selection, writer.createPositionAt( paragraph, 0 ) );\n}\n\nfunction replaceEntireContentWithParagraph( writer, selection ) {\n\tconst limitElement = writer.model.schema.getLimitElement( selection );\n\n\twriter.remove( writer.createRangeIn( limitElement ) );\n\tinsertParagraph( writer, writer.createPositionAt( limitElement, 0 ), selection );\n}\n\n// We want to replace the entire content with a paragraph when:\n// * the entire content is selected,\n// * selection contains at least two elements,\n// * whether the paragraph is allowed in schema in the common ancestor.\nfunction shouldEntireContentBeReplacedWithParagraph( schema, selection ) {\n\tconst limitElement = schema.getLimitElement( selection );\n\n\tif ( !selection.containsEntireContent( limitElement ) ) {\n\t\treturn false;\n\t}\n\n\tconst range = selection.getFirstRange();\n\n\tif ( range.start.parent == range.end.parent ) {\n\t\treturn false;\n\t}\n\n\treturn schema.checkChild( limitElement, 'paragraph' );\n}\n\n// Helper function that sets the selection. Depending whether given `selection` is a document selection or not,\n// uses a different method to set it.\nfunction collapseSelectionAt( writer, selection, positionOrRange ) {\n\tif ( selection instanceof DocumentSelection ) {\n\t\twriter.setSelection( positionOrRange );\n\t} else {\n\t\tselection.setTo( positionOrRange );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/utils/modifyselection\n */\n\nimport Position from '../position';\nimport TreeWalker from '../treewalker';\nimport Range from '../range';\nimport { isInsideSurrogatePair, isInsideCombinedSymbol } from '@ckeditor/ckeditor5-utils/src/unicode';\nimport DocumentSelection from '../documentselection';\n\nconst wordBoundaryCharacters = ' ,.?!:;\"-()';\n\n/**\n * Modifies the selection. Currently, the supported modifications are:\n *\n * * Extending. The selection focus is moved in the specified `options.direction` with a step specified in `options.unit`.\n * Possible values for `unit` are:\n * * `'character'` (default) - moves selection by one user-perceived character. In most cases this means moving by one\n * character in `String` sense. However, unicode also defines \"combing marks\". These are special symbols, that combines\n * with a symbol before it (\"base character\") to create one user-perceived character. For example, `q̣̇` is a normal\n * letter `q` with two \"combining marks\": upper dot (`Ux0307`) and lower dot (`Ux0323`). For most actions, i.e. extending\n * selection by one position, it is correct to include both \"base character\" and all of it's \"combining marks\". That is\n * why `'character'` value is most natural and common method of modifying selection.\n * * `'codePoint'` - moves selection by one unicode code point. In contrary to, `'character'` unit, this will insert\n * selection between \"base character\" and \"combining mark\", because \"combining marks\" have their own unicode code points.\n * However, for technical reasons, unicode code points with values above `UxFFFF` are represented in native `String` by\n * two characters, called \"surrogate pairs\". Halves of \"surrogate pairs\" have a meaning only when placed next to each other.\n * For example `𨭎` is represented in `String` by `\\uD862\\uDF4E`. Both `\\uD862` and `\\uDF4E` do not have any meaning\n * outside the pair (are rendered as ? when alone). Position between them would be incorrect. In this case, selection\n * extension will include whole \"surrogate pair\".\n * * `'word'` - moves selection by a whole word.\n *\n * **Note:** if you extend a forward selection in a backward direction you will in fact shrink it.\n *\n * **Note:** Use {@link module:engine/model/model~Model#modifySelection} instead of this function.\n * This function is only exposed to be reusable in algorithms\n * which change the {@link module:engine/model/model~Model#modifySelection}\n * method's behavior.\n *\n * @param {module:engine/model/model~Model} model The model in context of which\n * the selection modification should be performed.\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * The selection to modify.\n * @param {Object} [options]\n * @param {'forward'|'backward'} [options.direction='forward'] The direction in which the selection should be modified.\n * @param {'character'|'codePoint'|'word'} [options.unit='character'] The unit by which selection should be modified.\n */\nexport default function modifySelection( model, selection, options = {} ) {\n\tconst schema = model.schema;\n\tconst isForward = options.direction != 'backward';\n\tconst unit = options.unit ? options.unit : 'character';\n\n\tconst focus = selection.focus;\n\n\tconst walker = new TreeWalker( {\n\t\tboundaries: getSearchRange( focus, isForward ),\n\t\tsingleCharacters: true,\n\t\tdirection: isForward ? 'forward' : 'backward'\n\t} );\n\n\tconst data = { walker, schema, isForward, unit };\n\n\tlet next;\n\n\twhile ( ( next = walker.next() ) ) {\n\t\tif ( next.done ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst position = tryExtendingTo( data, next.value );\n\n\t\tif ( position ) {\n\t\t\tif ( selection instanceof DocumentSelection ) {\n\t\t\t\tmodel.change( writer => {\n\t\t\t\t\twriter.setSelectionFocus( position );\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tselection.setFocus( position );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n// Checks whether the selection can be extended to the the walker's next value (next position).\n// @param {{ walker, unit, isForward, schema }} data\n// @param {module:engine/view/treewalker~TreeWalkerValue} value\nfunction tryExtendingTo( data, value ) {\n\t// If found text, we can certainly put the focus in it. Let's just find a correct position\n\t// based on the unit.\n\tif ( value.type == 'text' ) {\n\t\tif ( data.unit === 'word' ) {\n\t\t\treturn getCorrectWordBreakPosition( data.walker, data.isForward );\n\t\t}\n\n\t\treturn getCorrectPosition( data.walker, data.unit, data.isForward );\n\t}\n\n\t// Entering an element.\n\tif ( value.type == ( data.isForward ? 'elementStart' : 'elementEnd' ) ) {\n\t\t// If it's an object, we can select it now.\n\t\tif ( data.schema.isObject( value.item ) ) {\n\t\t\treturn Position._createAt( value.item, data.isForward ? 'after' : 'before' );\n\t\t}\n\n\t\t// If text allowed on this position, extend to this place.\n\t\tif ( data.schema.checkChild( value.nextPosition, '$text' ) ) {\n\t\t\treturn value.nextPosition;\n\t\t}\n\t}\n\t// Leaving an element.\n\telse {\n\t\t// If leaving a limit element, stop.\n\t\tif ( data.schema.isLimit( value.item ) ) {\n\t\t\t// NOTE: Fast-forward the walker until the end.\n\t\t\tdata.walker.skip( () => true );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// If text allowed on this position, extend to this place.\n\t\tif ( data.schema.checkChild( value.nextPosition, '$text' ) ) {\n\t\t\treturn value.nextPosition;\n\t\t}\n\t}\n}\n\n// Finds a correct position by walking in a text node and checking whether selection can be extended to given position\n// or should be extended further.\n//\n// @param {module:engine/model/treewalker~TreeWalker} walker\n// @param {String} unit The unit by which selection should be modified.\nfunction getCorrectPosition( walker, unit ) {\n\tconst textNode = walker.position.textNode;\n\n\tif ( textNode ) {\n\t\tconst data = textNode.data;\n\t\tlet offset = walker.position.offset - textNode.startOffset;\n\n\t\twhile ( isInsideSurrogatePair( data, offset ) || ( unit == 'character' && isInsideCombinedSymbol( data, offset ) ) ) {\n\t\t\twalker.next();\n\n\t\t\toffset = walker.position.offset - textNode.startOffset;\n\t\t}\n\t}\n\n\treturn walker.position;\n}\n\n// Finds a correct position of a word break by walking in a text node and checking whether selection can be extended to given position\n// or should be extended further.\n//\n// @param {module:engine/model/treewalker~TreeWalker} walker\n// @param {Boolean} isForward Is the direction in which the selection should be modified is forward.\nfunction getCorrectWordBreakPosition( walker, isForward ) {\n\tlet textNode = walker.position.textNode;\n\n\tif ( textNode ) {\n\t\tlet offset = walker.position.offset - textNode.startOffset;\n\n\t\twhile ( !isAtWordBoundary( textNode.data, offset, isForward ) && !isAtNodeBoundary( textNode, offset, isForward ) ) {\n\t\t\twalker.next();\n\n\t\t\t// Check of adjacent text nodes with different attributes (like BOLD).\n\t\t\t// Example : 'foofoo []bar<$text bold=\"true\">bar</$text> bazbaz'\n\t\t\t// should expand to : 'foofoo [bar<$text bold=\"true\">bar</$text>] bazbaz'.\n\t\t\tconst nextNode = isForward ? walker.position.nodeAfter : walker.position.nodeBefore;\n\n\t\t\t// Scan only text nodes. Ignore inline elements (like `<softBreak>`).\n\t\t\tif ( nextNode && nextNode.is( 'text' ) ) {\n\t\t\t\t// Check boundary char of an adjacent text node.\n\t\t\t\tconst boundaryChar = nextNode.data.charAt( isForward ? 0 : nextNode.data.length - 1 );\n\n\t\t\t\t// Go to the next node if the character at the boundary of that node belongs to the same word.\n\t\t\t\tif ( !wordBoundaryCharacters.includes( boundaryChar ) ) {\n\t\t\t\t\t// If adjacent text node belongs to the same word go to it & reset values.\n\t\t\t\t\twalker.next();\n\n\t\t\t\t\ttextNode = walker.position.textNode;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toffset = walker.position.offset - textNode.startOffset;\n\t\t}\n\t}\n\n\treturn walker.position;\n}\n\nfunction getSearchRange( start, isForward ) {\n\tconst root = start.root;\n\tconst searchEnd = Position._createAt( root, isForward ? 'end' : 0 );\n\n\tif ( isForward ) {\n\t\treturn new Range( start, searchEnd );\n\t} else {\n\t\treturn new Range( searchEnd, start );\n\t}\n}\n\n// Checks if selection is on word boundary.\n//\n// @param {String} data The text node value to investigate.\n// @param {Number} offset Position offset.\n// @param {Boolean} isForward Is the direction in which the selection should be modified is forward.\nfunction isAtWordBoundary( data, offset, isForward ) {\n\t// The offset to check depends on direction.\n\tconst offsetToCheck = offset + ( isForward ? 0 : -1 );\n\n\treturn wordBoundaryCharacters.includes( data.charAt( offsetToCheck ) );\n}\n\n// Checks if selection is on node boundary.\n//\n// @param {module:engine/model/text~Text} textNode The text node to investigate.\n// @param {Number} offset Position offset.\n// @param {Boolean} isForward Is the direction in which the selection should be modified is forward.\nfunction isAtNodeBoundary( textNode, offset, isForward ) {\n\treturn offset === ( isForward ? textNode.endOffset : 0 );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/utils/getselectedcontent\n */\n\n/**\n * Gets a clone of the selected content.\n *\n * For example, for the following selection:\n *\n * ```html\n * <p>x</p><quote><p>y</p><h>fir[st</h></quote><p>se]cond</p><p>z</p>\n * ```\n *\n * It will return a document fragment with such a content:\n *\n * ```html\n * <quote><h>st</h></quote><p>se</p>\n * ```\n *\n * @param {module:engine/model/model~Model} model The model in context of which\n * the selection modification should be performed.\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * The selection of which content will be returned.\n * @returns {module:engine/model/documentfragment~DocumentFragment}\n */\nexport default function getSelectedContent( model, selection ) {\n\treturn model.change( writer => {\n\t\tconst frag = writer.createDocumentFragment();\n\t\tconst range = selection.getFirstRange();\n\n\t\tif ( !range || range.isCollapsed ) {\n\t\t\treturn frag;\n\t\t}\n\n\t\tconst root = range.start.root;\n\t\tconst commonPath = range.start.getCommonPath( range.end );\n\t\tconst commonParent = root.getNodeByPath( commonPath );\n\n\t\t// ## 1st step\n\t\t//\n\t\t// First, we'll clone a fragment represented by a minimal flat range\n\t\t// containing the original range to be cloned.\n\t\t// E.g. let's consider such a range:\n\t\t//\n\t\t// <p>x</p><quote><p>y</p><h>fir[st</h></quote><p>se]cond</p><p>z</p>\n\t\t//\n\t\t// A minimal flat range containing this one is:\n\t\t//\n\t\t// <p>x</p>[<quote><p>y</p><h>first</h></quote><p>second</p>]<p>z</p>\n\t\t//\n\t\t// We can easily clone this structure, preserving e.g. the <quote> element.\n\t\tlet flatSubtreeRange;\n\n\t\tif ( range.start.parent == range.end.parent ) {\n\t\t\t// The original range is flat, so take it.\n\t\t\tflatSubtreeRange = range;\n\t\t} else {\n\t\t\tflatSubtreeRange = writer.createRange(\n\t\t\t\twriter.createPositionAt( commonParent, range.start.path[ commonPath.length ] ),\n\t\t\t\twriter.createPositionAt( commonParent, range.end.path[ commonPath.length ] + 1 )\n\t\t\t);\n\t\t}\n\n\t\tconst howMany = flatSubtreeRange.end.offset - flatSubtreeRange.start.offset;\n\n\t\t// Clone the whole contents.\n\t\tfor ( const item of flatSubtreeRange.getItems( { shallow: true } ) ) {\n\t\t\tif ( item.is( 'textProxy' ) ) {\n\t\t\t\twriter.appendText( item.data, item.getAttributes(), frag );\n\t\t\t} else {\n\t\t\t\twriter.append( item._clone( true ), frag );\n\t\t\t}\n\t\t}\n\n\t\t// ## 2nd step\n\t\t//\n\t\t// If the original range wasn't flat, then we need to remove the excess nodes from the both ends of the cloned fragment.\n\t\t//\n\t\t// For example, for the range shown in the 1st step comment, we need to remove these pieces:\n\t\t//\n\t\t// <quote>[<p>y</p>]<h>[fir]st</h></quote><p>se[cond]</p>\n\t\t//\n\t\t// So this will be the final copied content:\n\t\t//\n\t\t// <quote><h>st</h></quote><p>se</p>\n\t\t//\n\t\t// In order to do that, we remove content from these two ranges:\n\t\t//\n\t\t// [<quote><p>y</p><h>fir]st</h></quote><p>se[cond</p>]\n\t\tif ( flatSubtreeRange != range ) {\n\t\t\t// Find the position of the original range in the cloned fragment.\n\t\t\tconst newRange = range._getTransformedByMove( flatSubtreeRange.start, writer.createPositionAt( frag, 0 ), howMany )[ 0 ];\n\n\t\t\tconst leftExcessRange = writer.createRange( writer.createPositionAt( frag, 0 ), newRange.start );\n\t\t\tconst rightExcessRange = writer.createRange( newRange.end, writer.createPositionAt( frag, 'end' ) );\n\n\t\t\tremoveRangeContent( rightExcessRange, writer );\n\t\t\tremoveRangeContent( leftExcessRange, writer );\n\t\t}\n\n\t\treturn frag;\n\t} );\n}\n\n// After https://github.com/ckeditor/ckeditor5-engine/issues/690 is fixed,\n// this function will, most likely, be able to rewritten using getMinimalFlatRanges().\nfunction removeRangeContent( range, writer ) {\n\tconst parentsToCheck = [];\n\n\tArray.from( range.getItems( { direction: 'backward' } ) )\n\t\t// We should better store ranges because text proxies will lose integrity\n\t\t// with the text nodes when we'll start removing content.\n\t\t.map( item => writer.createRangeOn( item ) )\n\t\t// Filter only these items which are fully contained in the passed range.\n\t\t//\n\t\t// E.g. for the following range: [<quote><p>y</p><h>fir]st</h>\n\t\t// the walker will return the entire <h> element, when only the \"fir\" item inside it is fully contained.\n\t\t.filter( itemRange => {\n\t\t\t// We should be able to use Range.containsRange, but https://github.com/ckeditor/ckeditor5-engine/issues/691.\n\t\t\tconst contained =\n\t\t\t\t( itemRange.start.isAfter( range.start ) || itemRange.start.isEqual( range.start ) ) &&\n\t\t\t\t( itemRange.end.isBefore( range.end ) || itemRange.end.isEqual( range.end ) );\n\n\t\t\treturn contained;\n\t\t} )\n\t\t.forEach( itemRange => {\n\t\t\tparentsToCheck.push( itemRange.start.parent );\n\n\t\t\twriter.remove( itemRange );\n\t\t} );\n\n\t// Remove ancestors of the removed items if they turned to be empty now\n\t// (their whole content was contained in the range).\n\tparentsToCheck.forEach( parentToCheck => {\n\t\tlet parent = parentToCheck;\n\n\t\twhile ( parent.parent && parent.isEmpty ) {\n\t\t\tconst removeRange = writer.createRangeOn( parent );\n\n\t\t\tparent = parent.parent;\n\n\t\t\twriter.remove( removeRange );\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/utils/selection-post-fixer\n */\n\nimport Range from '../range';\nimport Position from '../position';\n\n/**\n * Injects selection post-fixer to the model.\n *\n * The role of the selection post-fixer is to ensure that the selection is in a correct place\n * after a {@link module:engine/model/model~Model#change `change()`} block was executed.\n *\n * The correct position means that:\n *\n * * All collapsed selection ranges are in a place where the {@link module:engine/model/schema~Schema}\n * allows a `$text`.\n * * None of the selection's non-collapsed ranges crosses a {@link module:engine/model/schema~Schema#isLimit limit element}\n * boundary (a range must be rooted within one limit element).\n * * Only {@link module:engine/model/schema~Schema#isObject object elements} can be selected from the outside\n * (e.g. `[<paragraph>foo</paragraph>]` is invalid). This rule applies independently to both selection ends, so this\n * selection is correct: `<paragraph>f[oo</paragraph><image></image>]`.\n *\n * If the position is not correct, the post-fixer will automatically correct it.\n *\n * ## Fixing a non-collapsed selection\n *\n * See as an example a selection that starts in a P1 element and ends inside the text of a TD element\n * (`[` and `]` are range boundaries and `(l)` denotes an element defined as `isLimit=true`):\n *\n *\t\troot\n *\t\t |- element P1\n *\t\t | |- \"foo\" root\n *\t\t |- element TABLE (l) P1 TABLE P2\n *\t\t | |- element TR (l) f o[o TR TR b a r\n *\t\t | | |- element TD (l) TD TD\n *\t\t | | |- \"aaa\" a]a a b b b\n *\t\t | |- element TR (l)\n *\t\t | | |- element TD (l) ||\n *\t\t | | |- \"bbb\" ||\n *\t\t |- element P2 VV\n *\t\t | |- \"bar\"\n *\t\t root\n *\t\t P1 TABLE] P2\n *\t\t f o[o TR TR b a r\n *\t\t TD TD\n *\t\t a a a b b b\n *\n * In the example above, the TABLE, TR and TD are defined as `isLimit=true` in the schema. The range which is not contained within\n * a single limit element must be expanded to select the outermost limit element. The range end is inside the text node of the TD element.\n * As the TD element is a child of the TR and TABLE elements, where both are defined as `isLimit=true` in the schema, the range must be\n * expanded to select the whole TABLE element.\n *\n * **Note** If the selection contains multiple ranges, the method returns a minimal set of ranges that are not intersecting after expanding\n * them to select `isLimit=true` elements.\n *\n * @param {module:engine/model/model~Model} model\n */\nexport function injectSelectionPostFixer( model ) {\n\tmodel.document.registerPostFixer( writer => selectionPostFixer( writer, model ) );\n}\n\n// The selection post-fixer.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/model~Model} model\nfunction selectionPostFixer( writer, model ) {\n\tconst selection = model.document.selection;\n\tconst schema = model.schema;\n\n\tconst ranges = [];\n\n\tlet wasFixed = false;\n\n\tfor ( const modelRange of selection.getRanges() ) {\n\t\t// Go through all ranges in selection and try fixing each of them.\n\t\t// Those ranges might overlap but will be corrected later.\n\t\tconst correctedRange = tryFixingRange( modelRange, schema );\n\n\t\tif ( correctedRange ) {\n\t\t\tranges.push( correctedRange );\n\t\t\twasFixed = true;\n\t\t} else {\n\t\t\tranges.push( modelRange );\n\t\t}\n\t}\n\n\t// If any of ranges were corrected update the selection.\n\tif ( wasFixed ) {\n\t\twriter.setSelection( mergeIntersectingRanges( ranges ), { backward: selection.isBackward } );\n\t}\n}\n\n// Tries fixing a range if it's incorrect.\n//\n// @param {module:engine/model/range~Range} range\n// @param {module:engine/model/schema~Schema} schema\n// @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid.\nfunction tryFixingRange( range, schema ) {\n\tif ( range.isCollapsed ) {\n\t\treturn tryFixingCollapsedRange( range, schema );\n\t}\n\n\treturn tryFixingNonCollapsedRage( range, schema );\n}\n\n// Tries to fix collapsed ranges.\n//\n// * Fixes situation when a range is in a place where $text is not allowed\n//\n// @param {module:engine/model/range~Range} range Collapsed range to fix.\n// @param {module:engine/model/schema~Schema} schema\n// @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid.\nfunction tryFixingCollapsedRange( range, schema ) {\n\tconst originalPosition = range.start;\n\n\tconst nearestSelectionRange = schema.getNearestSelectionRange( originalPosition );\n\n\t// This might be null ie when editor data is empty.\n\t// In such cases there is no need to fix the selection range.\n\tif ( !nearestSelectionRange ) {\n\t\treturn null;\n\t}\n\n\tif ( !nearestSelectionRange.isCollapsed ) {\n\t\treturn nearestSelectionRange;\n\t}\n\n\tconst fixedPosition = nearestSelectionRange.start;\n\n\t// Fixed position is the same as original - no need to return corrected range.\n\tif ( originalPosition.isEqual( fixedPosition ) ) {\n\t\treturn null;\n\t}\n\n\treturn new Range( fixedPosition );\n}\n\n// Tries to fix an expanded range.\n//\n// @param {module:engine/model/range~Range} range Expanded range to fix.\n// @param {module:engine/model/schema~Schema} schema\n// @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid.\nfunction tryFixingNonCollapsedRage( range, schema ) {\n\tconst start = range.start;\n\tconst end = range.end;\n\n\tconst isTextAllowedOnStart = schema.checkChild( start, '$text' );\n\tconst isTextAllowedOnEnd = schema.checkChild( end, '$text' );\n\n\tconst startLimitElement = schema.getLimitElement( start );\n\tconst endLimitElement = schema.getLimitElement( end );\n\n\t// Ranges which both end are inside the same limit element (or root) might needs only minor fix.\n\tif ( startLimitElement === endLimitElement ) {\n\t\t// Range is valid when both position allows to place a text:\n\t\t// - <block>f[oobarba]z</block>\n\t\t// This would be \"fixed\" by a next check but as it will be the same it's better to return null so the selection stays the same.\n\t\tif ( isTextAllowedOnStart && isTextAllowedOnEnd ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Range that is on non-limit element (or is partially) must be fixed so it is placed inside the block around $text:\n\t\t// - [<block>foo</block>] -> <block>[foo]</block>\n\t\t// - [<block>foo]</block> -> <block>[foo]</block>\n\t\t// - <block>f[oo</block>] -> <block>f[oo]</block>\n\t\t// - [<block>foo</block><object></object>] -> <block>[foo</block><object></object>]\n\t\tif ( checkSelectionOnNonLimitElements( start, end, schema ) ) {\n\t\t\tconst isStartObject = start.nodeAfter && schema.isObject( start.nodeAfter );\n\t\t\tconst fixedStart = isStartObject ? null : schema.getNearestSelectionRange( start, 'forward' );\n\n\t\t\tconst isEndObject = end.nodeBefore && schema.isObject( end.nodeBefore );\n\t\t\tconst fixedEnd = isEndObject ? null : schema.getNearestSelectionRange( end, 'backward' );\n\n\t\t\t// The schema.getNearestSelectionRange might return null - if that happens use original position.\n\t\t\tconst rangeStart = fixedStart ? fixedStart.start : start;\n\t\t\tconst rangeEnd = fixedEnd ? fixedEnd.start : end;\n\n\t\t\treturn new Range( rangeStart, rangeEnd );\n\t\t}\n\t}\n\n\tconst isStartInLimit = startLimitElement && !startLimitElement.is( 'rootElement' );\n\tconst isEndInLimit = endLimitElement && !endLimitElement.is( 'rootElement' );\n\n\t// At this point we eliminated valid positions on text nodes so if one of range positions is placed inside a limit element\n\t// then the range crossed limit element boundaries and needs to be fixed.\n\tif ( isStartInLimit || isEndInLimit ) {\n\t\tconst bothInSameParent = ( start.nodeAfter && end.nodeBefore ) && start.nodeAfter.parent === end.nodeBefore.parent;\n\n\t\tconst expandStart = isStartInLimit && ( !bothInSameParent || !isInObject( start.nodeAfter, schema ) );\n\t\tconst expandEnd = isEndInLimit && ( !bothInSameParent || !isInObject( end.nodeBefore, schema ) );\n\n\t\t// Although we've already found limit element on start/end positions we must find the outer-most limit element.\n\t\t// as limit elements might be nested directly inside (ie table > tableRow > tableCell).\n\t\tlet fixedStart = start;\n\t\tlet fixedEnd = end;\n\n\t\tif ( expandStart ) {\n\t\t\tfixedStart = Position._createBefore( findOutermostLimitAncestor( startLimitElement, schema ) );\n\t\t}\n\n\t\tif ( expandEnd ) {\n\t\t\tfixedEnd = Position._createAfter( findOutermostLimitAncestor( endLimitElement, schema ) );\n\t\t}\n\n\t\treturn new Range( fixedStart, fixedEnd );\n\t}\n\n\t// Range was not fixed at this point so it is valid - ie it was placed around limit element already.\n\treturn null;\n}\n\n// Finds the outer-most ancestor.\n//\n// @param {module:engine/model/node~Node} startingNode\n// @param {module:engine/model/schema~Schema} schema\n// @param {String} expandToDirection Direction of expansion - either 'start' or 'end' of the range.\n// @returns {module:engine/model/node~Node}\nfunction findOutermostLimitAncestor( startingNode, schema ) {\n\tlet isLimitNode = startingNode;\n\tlet parent = isLimitNode;\n\n\t// Find outer most isLimit block as such blocks might be nested (ie. in tables).\n\twhile ( schema.isLimit( parent ) && parent.parent ) {\n\t\tisLimitNode = parent;\n\t\tparent = parent.parent;\n\t}\n\n\treturn isLimitNode;\n}\n\n// Checks whether any of range boundaries is placed around non-limit elements.\n//\n// @param {module:engine/model/position~Position} start\n// @param {module:engine/model/position~Position} end\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction checkSelectionOnNonLimitElements( start, end, schema ) {\n\tconst startIsOnBlock = ( start.nodeAfter && !schema.isLimit( start.nodeAfter ) ) || schema.checkChild( start, '$text' );\n\tconst endIsOnBlock = ( end.nodeBefore && !schema.isLimit( end.nodeBefore ) ) || schema.checkChild( end, '$text' );\n\n\t// We should fix such selection when one of those nodes needs fixing.\n\treturn startIsOnBlock || endIsOnBlock;\n}\n\n// Returns a minimal non-intersecting array of ranges.\n//\n// @param {Array.<module:engine/model/range~Range>} ranges\n// @returns {Array.<module:engine/model/range~Range>}\nfunction mergeIntersectingRanges( ranges ) {\n\tconst nonIntersectingRanges = [];\n\n\t// First range will always be fine.\n\tnonIntersectingRanges.push( ranges.shift() );\n\n\tfor ( const range of ranges ) {\n\t\tconst previousRange = nonIntersectingRanges.pop();\n\n\t\tif ( range.isIntersecting( previousRange ) ) {\n\t\t\t// Get the sum of two ranges.\n\t\t\tconst start = previousRange.start.isAfter( range.start ) ? range.start : previousRange.start;\n\t\t\tconst end = previousRange.end.isAfter( range.end ) ? previousRange.end : range.end;\n\n\t\t\tconst merged = new Range( start, end );\n\t\t\tnonIntersectingRanges.push( merged );\n\t\t} else {\n\t\t\tnonIntersectingRanges.push( previousRange );\n\t\t\tnonIntersectingRanges.push( range );\n\t\t}\n\t}\n\n\treturn nonIntersectingRanges;\n}\n\n// Checks if node exists and if it's an object.\n//\n// @param {module:engine/model/node~Node} node\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction isInObject( node, schema ) {\n\treturn node && schema.isObject( node );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/model/model\n */\n\nimport Batch from './batch';\nimport Writer from './writer';\nimport Schema from './schema';\nimport Document from './document';\nimport MarkerCollection from './markercollection';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ModelElement from './element';\nimport ModelRange from './range';\nimport ModelPosition from './position';\nimport ModelSelection from './selection';\nimport OperationFactory from './operation/operationfactory';\n\nimport insertContent from './utils/insertcontent';\nimport deleteContent from './utils/deletecontent';\nimport modifySelection from './utils/modifyselection';\nimport getSelectedContent from './utils/getselectedcontent';\nimport { injectSelectionPostFixer } from './utils/selection-post-fixer';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// @if CK_DEBUG_ENGINE // const { dumpTrees } = require( '../dev-utils/utils' );\n// @if CK_DEBUG_ENGINE // const { OperationReplayer } = require( '../dev-utils/operationreplayer' ).default;\n\n/**\n * Editor's data model. Read about the model in the\n * {@glink framework/guides/architecture/editing-engine engine architecture guide}.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Model {\n\tconstructor() {\n\t\t/**\n\t\t * Model's marker collection.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/markercollection~MarkerCollection}\n\t\t */\n\t\tthis.markers = new MarkerCollection();\n\n\t\t/**\n\t\t * Model's document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/document~Document}\n\t\t */\n\t\tthis.document = new Document( this );\n\n\t\t/**\n\t\t * Model's schema.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/schema~Schema}\n\t\t */\n\t\tthis.schema = new Schema();\n\n\t\t/**\n\t\t * All callbacks added by {@link module:engine/model/model~Model#change} or\n\t\t * {@link module:engine/model/model~Model#enqueueChange} methods waiting to be executed.\n\t\t *\n\t\t * @private\n\t\t * @type {Array.<Function>}\n\t\t */\n\t\tthis._pendingChanges = [];\n\n\t\t/**\n\t\t * The last created and currently used writer instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/writer~Writer}\n\t\t */\n\t\tthis._currentWriter = null;\n\n\t\t[ 'insertContent', 'deleteContent', 'modifySelection', 'getSelectedContent', 'applyOperation' ]\n\t\t\t.forEach( methodName => this.decorate( methodName ) );\n\n\t\t// Adding operation validation with `highest` priority, so it is called before any other feature would like\n\t\t// to do anything with the operation. If the operation has incorrect parameters it should throw on the earliest occasion.\n\t\tthis.on( 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\toperation._validate();\n\t\t}, { priority: 'highest' } );\n\n\t\t// Register some default abstract entities.\n\t\tthis.schema.register( '$root', {\n\t\t\tisLimit: true\n\t\t} );\n\t\tthis.schema.register( '$block', {\n\t\t\tallowIn: '$root',\n\t\t\tisBlock: true\n\t\t} );\n\t\tthis.schema.register( '$text', {\n\t\t\tallowIn: '$block',\n\t\t\tisInline: true\n\t\t} );\n\t\tthis.schema.register( '$clipboardHolder', {\n\t\t\tallowContentOf: '$root',\n\t\t\tisLimit: true\n\t\t} );\n\t\tthis.schema.extend( '$text', { allowIn: '$clipboardHolder' } );\n\n\t\t// An element needed by the `upcastElementToMarker` converter.\n\t\t// This element temporarily represents a marker boundary during the conversion process and is removed\n\t\t// at the end of the conversion. `UpcastDispatcher` or at least `Conversion` class looks like a\n\t\t// better place for this registration but both know nothing about `Schema`.\n\t\tthis.schema.register( '$marker' );\n\t\tthis.schema.addChildCheck( ( context, childDefinition ) => {\n\t\t\tif ( childDefinition.name === '$marker' ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} );\n\n\t\tinjectSelectionPostFixer( this );\n\n\t\t// @if CK_DEBUG_ENGINE // this.on( 'applyOperation', () => {\n\t\t// @if CK_DEBUG_ENGINE // \tdumpTrees( this.document, this.document.version );\n\t\t// @if CK_DEBUG_ENGINE // }, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * The `change()` method is the primary way of changing the model. You should use it to modify all document nodes\n\t * (including detached nodes – i.e. nodes not added to the {@link module:engine/model/model~Model#document model document}),\n\t * the {@link module:engine/model/document~Document#selection document's selection}, and\n\t * {@link module:engine/model/model~Model#markers model markers}.\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\twriter.insertText( 'foo', paragraph, 'end' );\n\t *\t\t} );\n\t *\n\t * All changes inside the change block use the same {@link module:engine/model/batch~Batch} so they are combined\n\t * into a single undo step.\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\twriter.insertText( 'foo', paragraph, 'end' ); // foo.\n\t *\n\t *\t\t\tmodel.change( writer => {\n\t *\t\t\t\twriter.insertText( 'bar', paragraph, 'end' ); // foobar.\n\t *\t\t\t} );\n\t *\n\t * \t\t\twriter.insertText( 'bom', paragraph, 'end' ); // foobarbom.\n\t *\t\t} );\n\t *\n\t * The callback of the `change()` block is executed synchronously.\n\t *\n\t * You can also return a value from the change block.\n\t *\n\t *\t\tconst img = model.change( writer => {\n\t *\t\t\treturn writer.createElement( 'img' );\n\t *\t\t} );\n\t *\n\t * @see #enqueueChange\n\t * @param {Function} callback Callback function which may modify the model.\n\t * @returns {*} Value returned by the callback.\n\t */\n\tchange( callback ) {\n\t\ttry {\n\t\t\tif ( this._pendingChanges.length === 0 ) {\n\t\t\t\t// If this is the outermost block, create a new batch and start `_runPendingChanges` execution flow.\n\t\t\t\tthis._pendingChanges.push( { batch: new Batch(), callback } );\n\n\t\t\t\treturn this._runPendingChanges()[ 0 ];\n\t\t\t} else {\n\t\t\t\t// If this is not the outermost block, just execute the callback.\n\t\t\t\treturn callback( this._currentWriter );\n\t\t\t}\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t}\n\n\t/**\n\t * The `enqueueChange()` method performs similar task as the {@link #change `change()` method}, with two major differences.\n\t *\n\t * First, the callback of `enqueueChange()` is executed when all other enqueued changes are done. It might be executed\n\t * immediately if it is not nested in any other change block, but if it is nested in another (enqueue)change block,\n\t * it will be delayed and executed after the outermost block.\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\tconsole.log( 1 );\n\t *\n\t *\t\t\tmodel.enqueueChange( writer => {\n\t *\t\t\t\tconsole.log( 2 );\n\t *\t\t\t} );\n\t *\n\t * \t\t\tconsole.log( 3 );\n\t *\t\t} ); // Will log: 1, 3, 2.\n\t *\n\t * Second, it lets you define the {@link module:engine/model/batch~Batch} into which you want to add your changes.\n\t * By default, a new batch is created. In the sample above, `change` and `enqueueChange` blocks use a different\n\t * batch (and different {@link module:engine/model/writer~Writer} since each of them operates on the separate batch).\n\t *\n\t * When using the `enqueueChange()` block you can also add some changes to the batch you used before.\n\t *\n\t *\t\tmodel.enqueueChange( batch, writer => {\n\t *\t\t\twriter.insertText( 'foo', paragraph, 'end' );\n\t *\t\t} );\n\t *\n\t * The batch instance can be obtained from {@link module:engine/model/writer~Writer#batch the writer}.\n\t *\n\t * @param {module:engine/model/batch~Batch|'transparent'|'default'} batchOrType Batch or batch type should be used in the callback.\n\t * If not defined, a new batch will be created.\n\t * @param {Function} callback Callback function which may modify the model.\n\t */\n\tenqueueChange( batchOrType, callback ) {\n\t\ttry {\n\t\t\tif ( typeof batchOrType === 'string' ) {\n\t\t\t\tbatchOrType = new Batch( batchOrType );\n\t\t\t} else if ( typeof batchOrType == 'function' ) {\n\t\t\t\tcallback = batchOrType;\n\t\t\t\tbatchOrType = new Batch();\n\t\t\t}\n\n\t\t\tthis._pendingChanges.push( { batch: batchOrType, callback } );\n\n\t\t\tif ( this._pendingChanges.length == 1 ) {\n\t\t\t\tthis._runPendingChanges();\n\t\t\t}\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t}\n\n\t/**\n\t * {@link module:utils/observablemixin~ObservableMixin#decorate Decorated} function for applying\n\t * {@link module:engine/model/operation/operation~Operation operations} to the model.\n\t *\n\t * This is a low-level way of changing the model. It is exposed for very specific use cases (like the undo feature).\n\t * Normally, to modify the model, you will want to use {@link module:engine/model/writer~Writer `Writer`}.\n\t * See also {@glink framework/guides/architecture/editing-engine#changing-the-model Changing the model} section\n\t * of the {@glink framework/guides/architecture/editing-engine Editing architecture} guide.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation The operation to apply.\n\t */\n\tapplyOperation( operation ) {\n\t\t// @if CK_DEBUG_ENGINE // console.log( 'Applying ' + operation );\n\n\t\t// @if CK_DEBUG_ENGINE // if ( !this._operationLogs ) {\n\t\t// @if CK_DEBUG_ENGINE //\tthis._operationLogs = [];\n\t\t// @if CK_DEBUG_ENGINE // }\n\n\t\t// @if CK_DEBUG_ENGINE // this._operationLogs.push( JSON.stringify( operation ) );\n\n\t\t// @if CK_DEBUG_ENGINE //if ( !this._appliedOperations ) {\n\t\t// @if CK_DEBUG_ENGINE //\tthis._appliedOperations = [];\n\t\t// @if CK_DEBUG_ENGINE //}\n\n\t\t// @if CK_DEBUG_ENGINE //this._appliedOperations.push( operation );\n\n\t\toperation._execute();\n\t}\n\n\t// @if CK_DEBUG_ENGINE // getAppliedOperation() {\n\t// @if CK_DEBUG_ENGINE //\tif ( !this._appliedOperations ) {\n\t// @if CK_DEBUG_ENGINE //\t\treturn '';\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\treturn this._appliedOperations.map( JSON.stringify ).join( '-------' );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // createReplayer( stringifiedOperations ) {\n\t// @if CK_DEBUG_ENGINE //\treturn new OperationReplayer( this, '-------', stringifiedOperations );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t/**\n\t * Inserts content at the position in the editor specified by the selection, as one would expect the paste\n\t * functionality to work.\n\t *\n\t * This is a high-level method. It takes the {@link #schema schema} into consideration when inserting\n\t * the content, clears the given selection's content before inserting nodes and moves the selection\n\t * to its target position at the end of the process.\n\t * It can split elements, merge them, wrap bare text nodes with paragraphs, etc. — just like the\n\t * pasting feature should do.\n\t *\n\t * For lower-level methods see {@link module:engine/model/writer~Writer `Writer`}.\n\t *\n\t * This method, unlike {@link module:engine/model/writer~Writer `Writer`}'s methods, does not have to be used\n\t * inside a {@link #change `change()` block}.\n\t *\n\t * # Conversion and schema\n\t *\n\t * Inserting elements and text nodes into the model is not enough to make CKEditor 5 render that content\n\t * to the user. CKEditor 5 implements a model-view-controller architecture and what `model.insertContent()` does\n\t * is only adding nodes to the model. Additionally, you need to define\n\t * {@glink framework/guides/architecture/editing-engine#conversion converters} between the model and view\n\t * and define those nodes in the {@glink framework/guides/architecture/editing-engine#schema schema}.\n\t *\n\t * So, while this method may seem similar to CKEditor 4 `editor.insertHtml()` (in fact, both methods\n\t * are used for paste-like content insertion), the CKEditor 5 method cannot be use to insert arbitrary HTML\n\t * unless converters are defined for all elements and attributes in that HTML.\n\t *\n\t * # Examples\n\t *\n\t * Using `insertContent()` with a manually created model structure:\n\t *\n\t *\t\t// Let's create a document fragment containing such content as:\n\t *\t\t//\n\t *\t\t// <paragraph>foo</paragraph>\n\t *\t\t// <blockQuote>\n\t *\t\t// <paragraph>bar</paragraph>\n\t *\t\t// </blockQuote>\n\t *\t\tconst docFrag = editor.model.change( writer => {\n\t *\t\t\tconst p1 = writer.createElement( 'paragraph' );\n\t *\t\t\tconst p2 = writer.createElement( 'paragraph' );\n\t *\t\t\tconst blockQuote = writer.createElement( 'blockQuote' );\n\t *\t\t\tconst docFrag = writer.createDocumentFragment();\n\t *\n\t *\t\t\twriter.append( p1, docFrag );\n\t *\t\t\twriter.append( blockQuote, docFrag );\n\t *\t\t\twriter.append( p2, blockQuote );\n\t *\t\t\twriter.insertText( 'foo', p1 );\n\t *\t\t\twriter.insertText( 'bar', p2 );\n\t *\n\t *\t\t\treturn docFrag;\n\t *\t\t} );\n\t *\n\t *\t\t// insertContent() does not have to be used in a change() block. It can, though,\n\t *\t\t// so this code could be moved to the callback defined above.\n\t *\t\teditor.model.insertContent( docFrag );\n\t *\n\t * Using `insertContent()` with an HTML string converted to a model document fragment (similar to the pasting mechanism):\n\t *\n\t *\t\t// You can create your own HtmlDataProcessor instance or use editor.data.processor\n\t *\t\t// if you have not overridden the default one (which is the HtmlDataProcessor instance).\n\t *\t\tconst htmlDP = new HtmlDataProcessor();\n\t *\n\t *\t\t// Convert an HTML string to a view document fragment:\n\t *\t\tconst viewFragment = htmlDP.toView( htmlString );\n\t *\n\t *\t\t// Convert the view document fragment to a model document fragment\n\t *\t\t// in the context of $root. This conversion takes the schema into\n\t *\t\t// account so if, for example, the view document fragment contained a bare text node,\n\t *\t\t// this text node cannot be a child of $root, so it will be automatically\n\t *\t\t// wrapped with a <paragraph>. You can define the context yourself (in the second parameter),\n\t *\t\t// and e.g. convert the content like it would happen in a <paragraph>.\n\t *\t\t// Note: The clipboard feature uses a custom context called $clipboardHolder\n\t *\t\t// which has a loosened schema.\n\t *\t\tconst modelFragment = editor.data.toModel( viewFragment );\n\t *\n\t *\t\teditor.model.insertContent( modelFragment );\n\t *\n\t * By default this method will use the document selection but it can also be used with a position, range or selection instance.\n\t *\n\t *\t\t// Insert text at the current document selection position.\n\t *\t\teditor.model.change( writer => {\n\t *\t\t\teditor.model.insertContent( writer.createText( 'x' ) );\n\t *\t\t} );\n\t *\n\t *\t\t// Insert text at a given position - the document selection will not be modified.\n\t *\t\teditor.model.change( writer => {\n\t *\t\t\teditor.model.insertContent( writer.createText( 'x' ), doc.getRoot(), 2 );\n\t *\n\t *\t\t\t// Which is a shorthand for:\n\t *\t\t\teditor.model.insertContent( writer.createText( 'x' ), writer.createPositionAt( doc.getRoot(), 2 ) );\n\t *\t\t} );\n\t *\n\t * If an instance of {@link module:engine/model/selection~Selection} is passed as `selectable`\n\t * it will be moved to the target position (where the document selection should be moved after the insertion).\n\t *\n\t *\t\teditor.model.change( writer => {\n\t *\t\t\t// Insert text replacing the given selection instance.\n\t *\t\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t\teditor.model.insertContent( writer.createText( 'x' ), selection );\n\t *\n\t *\t\t\t// insertContent() modifies the passed selection instance so it can be used to set the document selection.\n\t *\t\t\t// Note: This is not necessary when you passed the document selection to insertContent().\n\t *\t\t\twriter.setSelection( selection );\n\t *\t\t} );\n\t *\n\t * @fires insertContent\n\t * @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.\n\t * @param {module:engine/model/selection~Selectable} [selectable=model.document.selection]\n\t * The selection into which the content should be inserted. If not provided the current model document selection will be used.\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] To be used when a model item was passed as `selectable`.\n\t * This param defines a position in relation to that item.\n\t * @returns {module:engine/model/range~Range} Range which contains all the performed changes. This is a range that, if removed,\n\t * would return the model to the state before the insertion. If no changes were preformed by `insertContent`, returns a range collapsed\n\t * at the insertion position.\n\t */\n\tinsertContent( content, selectable, placeOrOffset ) {\n\t\treturn insertContent( this, content, selectable, placeOrOffset );\n\t}\n\n\t/**\n\t * Deletes content of the selection and merge siblings. The resulting selection is always collapsed.\n\t *\n\t * **Note:** For the sake of predictability, the resulting selection should always be collapsed.\n\t * In cases where a feature wants to modify deleting behavior so selection isn't collapsed\n\t * (e.g. a table feature may want to keep row selection after pressing <kbd>Backspace</kbd>),\n\t * then that behavior should be implemented in the view's listener. At the same time, the table feature\n\t * will need to modify this method's behavior too, e.g. to \"delete contents and then collapse\n\t * the selection inside the last selected cell\" or \"delete the row and collapse selection somewhere near\".\n\t * That needs to be done in order to ensure that other features which use `deleteContent()` will work well with tables.\n\t *\n\t * @fires deleteContent\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * Selection of which the content should be deleted.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.leaveUnmerged=false] Whether to merge elements after removing the content of the selection.\n\t *\n\t * For example `<heading1>x[x</heading1><paragraph>y]y</paragraph>` will become:\n\t *\n\t * * `<heading1>x^y</heading1>` with the option disabled (`leaveUnmerged == false`)\n\t * * `<heading1>x^</heading1><paragraph>y</paragraph>` with enabled (`leaveUnmerged == true`).\n\t *\n\t * Note: {@link module:engine/model/schema~Schema#isObject object} and {@link module:engine/model/schema~Schema#isLimit limit}\n\t * elements will not be merged.\n\t *\n\t * @param {Boolean} [options.doNotResetEntireContent=false] Whether to skip replacing the entire content with a\n\t * paragraph when the entire content was selected.\n\t *\n\t * For example `<heading1>[x</heading1><paragraph>y]</paragraph>` will become:\n\t *\n\t * * `<paragraph>^</paragraph>` with the option disabled (`doNotResetEntireContent == false`)\n\t * * `<heading1>^</heading1>` with enabled (`doNotResetEntireContent == true`)\n\t *\n\t * @param {Boolean} [options.doNotAutoparagraph=false] Whether to create a paragraph if after content deletion selection is moved\n\t * to a place where text cannot be inserted.\n\t *\n\t * For example `<paragraph>x</paragraph>[<image src=\"foo.jpg\"></image>]` will become:\n\t *\n\t * * `<paragraph>x</paragraph><paragraph>[]</paragraph>` with the option disabled (`doNotAutoparagraph == false`)\n\t * * `<paragraph>x[]</paragraph>` with the option enabled (`doNotAutoparagraph == true`).\n\t *\n\t * **Note:** if there is no valid position for the selection, the paragraph will always be created:\n\t *\n\t * `[<image src=\"foo.jpg\"></image>]` -> `<paragraph>[]</paragraph>`.\n\t */\n\tdeleteContent( selection, options ) {\n\t\tdeleteContent( this, selection, options );\n\t}\n\n\t/**\n\t * Modifies the selection. Currently, the supported modifications are:\n\t *\n\t * * Extending. The selection focus is moved in the specified `options.direction` with a step specified in `options.unit`.\n\t * Possible values for `unit` are:\n\t * * `'character'` (default) - moves selection by one user-perceived character. In most cases this means moving by one\n\t * character in `String` sense. However, unicode also defines \"combing marks\". These are special symbols, that combines\n\t * with a symbol before it (\"base character\") to create one user-perceived character. For example, `q̣̇` is a normal\n\t * letter `q` with two \"combining marks\": upper dot (`Ux0307`) and lower dot (`Ux0323`). For most actions, i.e. extending\n\t * selection by one position, it is correct to include both \"base character\" and all of it's \"combining marks\". That is\n\t * why `'character'` value is most natural and common method of modifying selection.\n\t * * `'codePoint'` - moves selection by one unicode code point. In contrary to, `'character'` unit, this will insert\n\t * selection between \"base character\" and \"combining mark\", because \"combining marks\" have their own unicode code points.\n\t * However, for technical reasons, unicode code points with values above `UxFFFF` are represented in native `String` by\n\t * two characters, called \"surrogate pairs\". Halves of \"surrogate pairs\" have a meaning only when placed next to each other.\n\t * For example `𨭎` is represented in `String` by `\\uD862\\uDF4E`. Both `\\uD862` and `\\uDF4E` do not have any meaning\n\t * outside the pair (are rendered as ? when alone). Position between them would be incorrect. In this case, selection\n\t * extension will include whole \"surrogate pair\".\n\t * * `'word'` - moves selection by a whole word.\n\t *\n\t * **Note:** if you extend a forward selection in a backward direction you will in fact shrink it.\n\t *\n\t * @fires modifySelection\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * The selection to modify.\n\t * @param {Object} [options]\n\t * @param {'forward'|'backward'} [options.direction='forward'] The direction in which the selection should be modified.\n\t * @param {'character'|'codePoint'|'word'} [options.unit='character'] The unit by which selection should be modified.\n\t */\n\tmodifySelection( selection, options ) {\n\t\tmodifySelection( this, selection, options );\n\t}\n\n\t/**\n\t * Gets a clone of the selected content.\n\t *\n\t * For example, for the following selection:\n\t *\n\t * ```html\n\t * <paragraph>x</paragraph>\n\t * <blockQuote>\n\t *\t<paragraph>y</paragraph>\n\t *\t<heading1>fir[st</heading1>\n\t * </blockQuote>\n\t * <paragraph>se]cond</paragraph>\n\t * <paragraph>z</paragraph>\n\t * ```\n\t *\n\t * It will return a document fragment with such a content:\n\t *\n\t * ```html\n\t * <blockQuote>\n\t *\t<heading1>st</heading1>\n\t * </blockQuote>\n\t * <paragraph>se</paragraph>\n\t * ```\n\t *\n\t * @fires getSelectedContent\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * The selection of which content will be returned.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tgetSelectedContent( selection ) {\n\t\treturn getSelectedContent( this, selection );\n\t}\n\n\t/**\n\t * Checks whether the given {@link module:engine/model/range~Range range} or\n\t * {@link module:engine/model/element~Element element} has any meaningful content.\n\t *\n\t * Meaningful content is:\n\t *\n\t * * any text node (`options.ignoreWhitespaces` allows controlling whether this text node must also contain\n\t * any non-whitespace characters),\n\t * * or any {@link module:engine/model/schema~Schema#isObject object element},\n\t * * or any {@link module:engine/model/markercollection~Marker marker} which\n\t * {@link module:engine/model/markercollection~Marker#_affectsData affects data}.\n\t *\n\t * This means that a range containing an empty `<paragraph></paragraph>` is not considered to have a meaningful content.\n\t * However, a range containing an `<image></image>` (which would normally be marked in the schema as an object element)\n\t * is considered non-empty.\n\t *\n\t * @param {module:engine/model/range~Range|module:engine/model/element~Element} rangeOrElement Range or element to check.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.ignoreWhitespaces] Whether text node with whitespaces only should be considered empty.\n\t * @returns {Boolean}\n\t */\n\thasContent( rangeOrElement, options ) {\n\t\tconst range = rangeOrElement instanceof ModelElement ? ModelRange._createIn( rangeOrElement ) : rangeOrElement;\n\n\t\tif ( range.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if there are any markers which affects data in this given range.\n\t\tfor ( const intersectingMarker of this.markers.getMarkersIntersectingRange( range ) ) {\n\t\t\tif ( intersectingMarker.affectsData ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\tconst { ignoreWhitespaces = false } = options || {};\n\n\t\tfor ( const item of range.getItems() ) {\n\t\t\tif ( item.is( 'textProxy' ) ) {\n\t\t\t\tif ( !ignoreWhitespaces ) {\n\t\t\t\t\treturn true;\n\t\t\t\t} else if ( item.data.search( /\\S/ ) !== -1 ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} else if ( this.schema.isObject( item ) ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Creates a position from the given root and path in that root.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createPositionFromPath `Writer#createPositionFromPath()`}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} root Root of the position.\n\t * @param {Array.<Number>} path Position path. See {@link module:engine/model/position~Position#path}.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * See {@link module:engine/model/position~PositionStickiness}.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionFromPath( root, path, stickiness ) {\n\t\treturn new ModelPosition( root, path, stickiness );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/model/position~Position position},\n\t * * a parent element and offset in that element,\n\t * * a parent element and `'end'` (the position will be set at the end of that element),\n\t * * a {@link module:engine/model/item~Item model item} and `'before'` or `'after'`\n\t * (the position will be set before or after the given model item).\n\t *\n\t * This method is a shortcut to other factory methods such as:\n\t *\n\t * * {@link module:engine/model/model~Model#createPositionBefore `createPositionBefore()`},\n\t * * {@link module:engine/model/model~Model#createPositionAfter `createPositionAfter()`}.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createPositionAt `Writer#createPositionAt()`},\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn ModelPosition._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after the given {@link module:engine/model/item~Item model item}.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createPositionAfter `Writer#createPositionAfter()`}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item after which the position should be placed.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn ModelPosition._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before the given {@link module:engine/model/item~Item model item}.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createPositionBefore `Writer#createPositionBefore()`}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item before which the position should be placed.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn ModelPosition._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from the `start` position to the `end` position.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createRange `Writer#createRange()`}:\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\tconst range = writer.createRange( start, end );\n\t *\t\t} );\n\t *\n\t * @param {module:engine/model/position~Position} start Start position.\n\t * @param {module:engine/model/position~Position} [end] End position. If not set, the range will be collapsed\n\t * to the `start` position.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new ModelRange( start, end );\n\t}\n\n\t/**\n\t * Creates a range inside the given element which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createRangeIn `Writer#createRangeIn()`}:\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\tconst range = writer.createRangeIn( paragraph );\n\t *\t\t} );\n\t *\n\t * @param {module:engine/model/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn ModelRange._createIn( element );\n\t}\n\n\t/**\n\t * Creates a range that starts before the given {@link module:engine/model/item~Item model item} and ends after it.\n\t *\n\t * Note: This method is also available on `writer` instance as\n\t * {@link module:engine/model/writer~Writer#createRangeOn `Writer.createRangeOn()`}:\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\tconst range = writer.createRangeOn( paragraph );\n\t *\t\t} );\n\t *\n\t * @param {module:engine/model/item~Item} item\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn ModelRange._createOn( item );\n\t}\n\n\t/**\n\t * Creates a new selection instance based on the given {@link module:engine/model/selection~Selectable selectable}\n\t * or creates an empty selection if no arguments were passed.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createSelection `Writer#createSelection()`}.\n\t *\n\t *\t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t *\t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the given document selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst documentSelection = model.document.selection;\n\t *\t\tconst selection = writer.createSelection( documentSelection );\n\t *\n\t *\t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates selection at the given offset in the given element.\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/model/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t *\t\t// Additional options (`'backward'`) can be specified as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @returns {module:engine/model/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn new ModelSelection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/batch~Batch} instance.\n\t *\n\t * **Note:** In most cases creating a batch instance is not necessary as they are created when using:\n\t *\n\t * * {@link #change `change()`},\n\t * * {@link #enqueueChange `enqueueChange()`}.\n\t *\n\t * @param {'transparent'|'default'} [type='default'] The type of the batch.\n\t * @returns {module:engine/model/batch~Batch}\n\t */\n\tcreateBatch( type ) {\n\t\treturn new Batch( type );\n\t}\n\n\t/**\n\t * Creates an operation instance from a JSON object (parsed JSON string).\n\t *\n\t * This is an alias for {@link module:engine/model/operation/operationfactory~OperationFactory.fromJSON `OperationFactory.fromJSON()`}.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @returns {module:engine/model/operation/operation~Operation}\n\t */\n\tcreateOperationFromJSON( json ) {\n\t\treturn OperationFactory.fromJSON( json, this.document );\n\t}\n\n\t/**\n\t * Removes all events listeners set by model instance and destroys {@link module:engine/model/document~Document}.\n\t */\n\tdestroy() {\n\t\tthis.document.destroy();\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Common part of {@link module:engine/model/model~Model#change} and {@link module:engine/model/model~Model#enqueueChange}\n\t * which calls callbacks and returns array of values returned by these callbacks.\n\t *\n\t * @private\n\t * @returns {Array.<*>} Array of values returned by callbacks.\n\t */\n\t_runPendingChanges() {\n\t\tconst ret = [];\n\n\t\tthis.fire( '_beforeChanges' );\n\n\t\twhile ( this._pendingChanges.length ) {\n\t\t\t// Create a new writer using batch instance created for this chain of changes.\n\t\t\tconst currentBatch = this._pendingChanges[ 0 ].batch;\n\t\t\tthis._currentWriter = new Writer( this, currentBatch );\n\n\t\t\t// Execute changes callback and gather the returned value.\n\t\t\tconst callbackReturnValue = this._pendingChanges[ 0 ].callback( this._currentWriter );\n\t\t\tret.push( callbackReturnValue );\n\n\t\t\tthis.document._handleChangeBlock( this._currentWriter );\n\n\t\t\tthis._pendingChanges.shift();\n\t\t\tthis._currentWriter = null;\n\t\t}\n\n\t\tthis.fire( '_afterChanges' );\n\n\t\treturn ret;\n\t}\n\n\t/**\n\t * Fired when entering the outermost {@link module:engine/model/model~Model#enqueueChange} or\n\t * {@link module:engine/model/model~Model#change} block.\n\t *\n\t * @protected\n\t * @event _beforeChanges\n\t */\n\n\t/**\n\t * Fired when leaving the outermost {@link module:engine/model/model~Model#enqueueChange} or\n\t * {@link module:engine/model/model~Model#change} block.\n\t *\n\t * @protected\n\t * @event _afterChanges\n\t */\n\n\t/**\n\t * Fired every time any {@link module:engine/model/operation/operation~Operation operation} is applied on the model\n\t * using {@link #applyOperation}.\n\t *\n\t * Note that this event is suitable only for very specific use-cases. Use it if you need to listen to every single operation\n\t * applied on the document. However, in most cases {@link module:engine/model/document~Document#event:change} should\n\t * be used.\n\t *\n\t * A few callbacks are already added to this event by engine internal classes:\n\t *\n\t * * with `highest` priority operation is validated,\n\t * * with `normal` priority operation is executed,\n\t * * with `low` priority the {@link module:engine/model/document~Document} updates its version,\n\t * * with `low` priority {@link module:engine/model/liveposition~LivePosition} and {@link module:engine/model/liverange~LiveRange}\n\t * update themselves.\n\t *\n\t * @event applyOperation\n\t * @param {Array} args Arguments of the `applyOperation` which is an array with a single element - applied\n\t * {@link module:engine/model/operation/operation~Operation operation}.\n\t */\n\n\t/**\n\t * Event fired when {@link #insertContent} method is called.\n\t *\n\t * The {@link #insertContent default action of that method} is implemented as a\n\t * listener to this event so it can be fully customized by the features.\n\t *\n\t * **Note** The `selectable` parameter for the {@link #insertContent} is optional. When `undefined` value is passed the method uses\n\t * `model.document.selection`.\n\t *\n\t * @event insertContent\n\t * @param {Array} args The arguments passed to the original method.\n\t */\n\n\t/**\n\t * Event fired when {@link #deleteContent} method is called.\n\t *\n\t * The {@link #deleteContent default action of that method} is implemented as a\n\t * listener to this event so it can be fully customized by the features.\n\t *\n\t * @event deleteContent\n\t * @param {Array} args The arguments passed to the original method.\n\t */\n\n\t/**\n\t * Event fired when {@link #modifySelection} method is called.\n\t *\n\t * The {@link #modifySelection default action of that method} is implemented as a\n\t * listener to this event so it can be fully customized by the features.\n\t *\n\t * @event modifySelection\n\t * @param {Array} args The arguments passed to the original method.\n\t */\n\n\t/**\n\t * Event fired when {@link #getSelectedContent} method is called.\n\t *\n\t * The {@link #getSelectedContent default action of that method} is implemented as a\n\t * listener to this event so it can be fully customized by the features.\n\t *\n\t * @event getSelectedContent\n\t * @param {Array} args The arguments passed to the original method.\n\t */\n}\n\nmix( Model, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/keystrokehandler\n */\n\nimport DomEmitterMixin from './dom/emittermixin';\nimport { getCode, parseKeystroke } from './keyboard';\n\n/**\n * Keystroke handler allows registering callbacks for given keystrokes.\n *\n * The most frequent use of this class is through the {@link module:core/editor/editor~Editor#keystrokes `editor.keystrokes`}\n * property. It allows listening to keystrokes executed in the editing view:\n *\n *\t\teditor.keystrokes.set( 'Ctrl+A', ( keyEvtData, cancel ) => {\n *\t\t\tconsole.log( 'Ctrl+A has been pressed' );\n *\t\t\tcancel();\n *\t\t} );\n *\n * However, this utility class can be used in various part of the UI. For instance, a certain {@link module:ui/view~View}\n * can use it like this:\n *\n *\t\tclass MyView extends View {\n *\t\t\tconstructor() {\n *\t\t\t\tthis.keystrokes = new KeystrokeHandler();\n *\n * \t\t\t\tthis.keystrokes.set( 'tab', handleTabKey );\n *\t\t\t}\n *\n *\t\t\trender() {\n *\t\t\t\tsuper.render();\n *\n *\t\t\t\tthis.keystrokes.listenTo( this.element );\n *\t\t\t}\n *\t\t}\n *\n * That keystroke handler will listen to `keydown` events fired in this view's main element.\n *\n */\nexport default class KeystrokeHandler {\n\t/**\n\t * Creates an instance of the keystroke handler.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Listener used to listen to events for easier keystroke handler destruction.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:utils/dom/emittermixin~Emitter}\n\t\t */\n\t\tthis._listener = Object.create( DomEmitterMixin );\n\t}\n\n\t/**\n\t * Starts listening for `keydown` events from a given emitter.\n\t *\n\t * @param {module:utils/emittermixin~Emitter} emitter\n\t */\n\tlistenTo( emitter ) {\n\t\t// The #_listener works here as a kind of dispatcher. It groups the events coming from the same\n\t\t// keystroke so the listeners can be attached to them with different priorities.\n\t\t//\n\t\t// E.g. all the keystrokes with the `keyCode` of 42 coming from the `emitter` are propagated\n\t\t// as a `_keydown:42` event by the `_listener`. If there's a callback created by the `set`\n\t\t// method for this 42 keystroke, it listens to the `_listener#_keydown:42` event only and interacts\n\t\t// only with other listeners of this particular event, thus making it possible to prioritize\n\t\t// the listeners and safely cancel execution, when needed. Instead of duplicating the Emitter logic,\n\t\t// the KeystrokeHandler re–uses it to do its job.\n\t\tthis._listener.listenTo( emitter, 'keydown', ( evt, keyEvtData ) => {\n\t\t\tthis._listener.fire( '_keydown:' + getCode( keyEvtData ), keyEvtData );\n\t\t} );\n\t}\n\n\t/**\n\t * Registers a handler for the specified keystroke.\n\t *\n\t * @param {String|Array.<String|Number>} keystroke Keystroke defined in a format accepted by\n\t * the {@link module:utils/keyboard~parseKeystroke} function.\n\t * @param {Function} callback A function called with the\n\t * {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and\n\t * a helper funcion to call both `preventDefault()` and `stopPropagation()` on the underlying event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of the keystroke\n\t * callback. The higher the priority value the sooner the callback will be executed. Keystrokes having the same priority\n\t * are called in the order they were added.\n\t */\n\tset( keystroke, callback, options = {} ) {\n\t\tconst keyCode = parseKeystroke( keystroke );\n\t\tconst priority = options.priority;\n\n\t\t// Execute the passed callback on KeystrokeHandler#_keydown.\n\t\t// TODO: https://github.com/ckeditor/ckeditor5-utils/issues/144\n\t\tthis._listener.listenTo( this._listener, '_keydown:' + keyCode, ( evt, keyEvtData ) => {\n\t\t\tcallback( keyEvtData, () => {\n\t\t\t\t// Stop the event in the DOM: no listener in the web page\n\t\t\t\t// will be triggered by this event.\n\t\t\t\tkeyEvtData.preventDefault();\n\t\t\t\tkeyEvtData.stopPropagation();\n\n\t\t\t\t// Stop the event in the KeystrokeHandler: no more callbacks\n\t\t\t\t// will be executed for this keystroke.\n\t\t\t\tevt.stop();\n\t\t\t} );\n\n\t\t\t// Mark this keystroke as handled by the callback. See: #press.\n\t\t\tevt.return = true;\n\t\t}, { priority } );\n\t}\n\n\t/**\n\t * Triggers a keystroke handler for a specified key combination, if such a keystroke was {@link #set defined}.\n\t *\n\t * @param {module:engine/view/observer/keyobserver~KeyEventData} keyEvtData Key event data.\n\t * @returns {Boolean} Whether the keystroke was handled.\n\t */\n\tpress( keyEvtData ) {\n\t\treturn !!this._listener.fire( '_keydown:' + getCode( keyEvtData ), keyEvtData );\n\t}\n\n\t/**\n\t * Destroys the keystroke handler.\n\t */\n\tdestroy() {\n\t\tthis._listener.stopListening();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 core/editingkeystrokehandler\n */\n\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\n\n/**\n * A keystroke handler for editor editing. Its instance is available\n * in {@link module:core/editor/editor~Editor#keystrokes} so plugins\n * can register their keystrokes.\n *\n * E.g. an undo plugin would do this:\n *\n *\t\teditor.keystrokes.set( 'Ctrl+Z', 'undo' );\n *\t\teditor.keystrokes.set( 'Ctrl+Shift+Z', 'redo' );\n *\t\teditor.keystrokes.set( 'Ctrl+Y', 'redo' );\n *\n * @extends module:utils/keystrokehandler~KeystrokeHandler\n */\nexport default class EditingKeystrokeHandler extends KeystrokeHandler {\n\t/**\n\t * Creates an instance of the keystroke handler.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t */\n\tconstructor( editor ) {\n\t\tsuper();\n\n\t\t/**\n\t\t * The editor instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.editor = editor;\n\t}\n\n\t/**\n\t * Registers a handler for the specified keystroke.\n\t *\n\t * The handler can be specified as a command name or a callback.\n\t *\n\t * @param {String|Array.<String|Number>} keystroke Keystroke defined in a format accepted by\n\t * the {@link module:utils/keyboard~parseKeystroke} function.\n\t * @param {Function|String} callback If a string is passed, then the keystroke will\n\t * {@link module:core/editor/editor~Editor#execute execute a command}.\n\t * If a function, then it will be called with the\n\t * {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and\n\t * a `cancel()` helper to both `preventDefault()` and `stopPropagation()` of the event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of the keystroke\n\t * callback. The higher the priority value the sooner the callback will be executed. Keystrokes having the same priority\n\t * are called in the order they were added.\n\t */\n\tset( keystroke, callback, options = {} ) {\n\t\tif ( typeof callback == 'string' ) {\n\t\t\tconst commandName = callback;\n\n\t\t\tcallback = ( evtData, cancel ) => {\n\t\t\t\tthis.editor.execute( commandName );\n\t\t\t\tcancel();\n\t\t\t};\n\t\t}\n\n\t\tsuper.set( keystroke, callback, options );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 core/editor/editor\n */\n\nimport Context from '../context';\nimport Config from '@ckeditor/ckeditor5-utils/src/config';\nimport EditingController from '@ckeditor/ckeditor5-engine/src/controller/editingcontroller';\nimport PluginCollection from '../plugincollection';\nimport CommandCollection from '../commandcollection';\nimport DataController from '@ckeditor/ckeditor5-engine/src/controller/datacontroller';\nimport Conversion from '@ckeditor/ckeditor5-engine/src/conversion/conversion';\nimport Model from '@ckeditor/ckeditor5-engine/src/model/model';\nimport EditingKeystrokeHandler from '../editingkeystrokehandler';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * The class representing a basic, generic editor.\n *\n * Check out the list of its subclasses to learn about specific editor implementations.\n *\n * All editor implementations (like {@link module:editor-classic/classiceditor~ClassicEditor} or\n * {@link module:editor-inline/inlineeditor~InlineEditor}) should extend this class. They can add their\n * own methods and properties.\n *\n * When you are implementing a plugin, this editor represents the API\n * which your plugin can expect to get when using its {@link module:core/plugin~Plugin#editor} property.\n *\n * This API should be sufficient in order to implement the \"editing\" part of your feature\n * (schema definition, conversion, commands, keystrokes, etc.).\n * It does not define the editor UI, which is available only if\n * the specific editor implements also the {@link module:core/editor/editorwithui~EditorWithUI} interface\n * (as most editor implementations do).\n *\n * @abstract\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Editor {\n\t/**\n\t * Creates a new instance of the editor class.\n\t *\n\t * Usually, not to be used directly. See the static {@link module:core/editor/editor~Editor.create `create()`} method.\n\t *\n\t * @param {Object} [config={}] The editor configuration.\n\t */\n\tconstructor( config = {} ) {\n\t\t/**\n\t\t * The editor context.\n\t\t * When it is not provided through the configuration, the editor creates it.\n\t\t *\n\t\t * @protected\n\t\t * @type {module:core/context~Context}\n\t\t */\n\t\tthis._context = config.context || new Context( { language: config.language } );\n\t\tthis._context._addEditor( this, !config.context );\n\n\t\t// Clone the plugins to make sure that the plugin array will not be shared\n\t\t// between editors and make the watchdog feature work correctly.\n\t\tconst availablePlugins = Array.from( this.constructor.builtinPlugins || [] );\n\n\t\t/**\n\t\t * Stores all configurations specific to this editor instance.\n\t\t *\n\t\t *\t\teditor.config.get( 'image.toolbar' );\n\t\t *\t\t// -> [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ]\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/config~Config}\n\t\t */\n\t\tthis.config = new Config( config, this.constructor.defaultConfig );\n\t\tthis.config.define( 'plugins', availablePlugins );\n\t\tthis.config.define( this._context._getEditorConfig() );\n\n\t\t/**\n\t\t * The plugins loaded and in use by this editor instance.\n\t\t *\n\t\t *\t\teditor.plugins.get( 'Clipboard' ); // -> An instance of the clipboard plugin.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/plugincollection~PluginCollection}\n\t\t */\n\t\tthis.plugins = new PluginCollection( this, availablePlugins, this._context.plugins );\n\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = this._context.locale;\n\n\t\t/**\n\t\t * Shorthand for {@link module:utils/locale~Locale#t}.\n\t\t *\n\t\t * @see module:utils/locale~Locale#t\n\t\t * @method #t\n\t\t */\n\t\tthis.t = this.locale.t;\n\n\t\t/**\n\t\t * Commands registered to the editor.\n\t\t *\n\t\t * Use the shorthand {@link #execute `editor.execute()`} method to execute commands:\n\t\t *\n\t\t *\t\t// Execute the bold command:\n\t\t *\t\teditor.execute( 'bold' );\n\t\t *\n\t\t *\t\t// Check the state of the bold command:\n\t\t *\t\teditor.commands.get( 'bold' ).value;\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/commandcollection~CommandCollection}\n\t\t */\n\t\tthis.commands = new CommandCollection();\n\n\t\t/**\n\t\t * Indicates the editor life-cycle state.\n\t\t *\n\t\t * The editor is in one of the following states:\n\t\t *\n\t\t * * `initializing` – During the editor initialization (before\n\t\t * {@link module:core/editor/editor~Editor.create `Editor.create()`}) finished its job.\n\t\t * * `ready` – After the promise returned by the {@link module:core/editor/editor~Editor.create `Editor.create()`}\n\t\t * method is resolved.\n\t\t * * `destroyed` – Once the {@link #destroy `editor.destroy()`} method was called.\n\t\t *\n\t\t * @observable\n\t\t * @member {'initializing'|'ready'|'destroyed'} #state\n\t\t */\n\t\tthis.set( 'state', 'initializing' );\n\t\tthis.once( 'ready', () => ( this.state = 'ready' ), { priority: 'high' } );\n\t\tthis.once( 'destroy', () => ( this.state = 'destroyed' ), { priority: 'high' } );\n\n\t\t/**\n\t\t * Defines whether this editor is in read-only mode.\n\t\t *\n\t\t * In read-only mode the editor {@link #commands commands} are disabled so it is not possible\n\t\t * to modify the document by using them. Also, the editable element(s) become non-editable.\n\t\t *\n\t\t * In order to make the editor read-only, you can set this value directly:\n\t\t *\n\t\t *\t\teditor.isReadOnly = true;\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * The editor's model.\n\t\t *\n\t\t * The central point of the editor's abstract data model.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = new Model();\n\n\t\t/**\n\t\t * The {@link module:engine/controller/datacontroller~DataController data controller}.\n\t\t * Used e.g. for setting and retrieving the editor data.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/controller/datacontroller~DataController}\n\t\t */\n\t\tthis.data = new DataController( this.model );\n\n\t\t/**\n\t\t * The {@link module:engine/controller/editingcontroller~EditingController editing controller}.\n\t\t * Controls user input and rendering the content for editing.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/controller/editingcontroller~EditingController}\n\t\t */\n\t\tthis.editing = new EditingController( this.model );\n\t\tthis.editing.view.document.bind( 'isReadOnly' ).to( this );\n\n\t\t/**\n\t\t * Conversion manager through which you can register model-to-view and view-to-model converters.\n\t\t *\n\t\t * See the {@link module:engine/conversion/conversion~Conversion} documentation to learn how to add converters.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/conversion~Conversion}\n\t\t */\n\t\tthis.conversion = new Conversion( [ this.editing.downcastDispatcher, this.data.downcastDispatcher ], this.data.upcastDispatcher );\n\t\tthis.conversion.addAlias( 'dataDowncast', this.data.downcastDispatcher );\n\t\tthis.conversion.addAlias( 'editingDowncast', this.editing.downcastDispatcher );\n\n\t\t/**\n\t\t * An instance of the {@link module:core/editingkeystrokehandler~EditingKeystrokeHandler}.\n\t\t *\n\t\t * It allows setting simple keystrokes:\n\t\t *\n\t\t *\t\t// Execute the bold command on Ctrl+E:\n\t\t *\t\teditor.keystrokes.set( 'Ctrl+E', 'bold' );\n\t\t *\n\t\t *\t\t// Execute your own callback:\n\t\t *\t\teditor.keystrokes.set( 'Ctrl+E', ( data, cancel ) => {\n\t\t *\t\t\tconsole.log( data.keyCode );\n\t\t *\n\t\t *\t\t\t// Prevent the default (native) action and stop the underlying keydown event\n\t\t *\t\t\t// so no other editor feature will interfere.\n\t\t *\t\t\tcancel();\n\t\t *\t\t} );\n\t\t *\n\t\t * Note: Certain typing-oriented keystrokes (like <kbd>Backspace</kbd> or <kbd>Enter</kbd>) are handled\n\t\t * by a low-level mechanism and trying to listen to them via the keystroke handler will not work reliably.\n\t\t * To handle these specific keystrokes, see the events fired by the\n\t\t * {@link module:engine/view/document~Document editing view document} (`editor.editing.view.document`).\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editingkeystrokehandler~EditingKeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new EditingKeystrokeHandler( this );\n\t\tthis.keystrokes.listenTo( this.editing.view.document );\n\t}\n\n\t/**\n\t * Loads and initializes plugins specified in the configuration.\n\t *\n\t * @returns {Promise.<module:core/plugin~LoadedPlugins>} A promise which resolves\n\t * once the initialization is completed, providing an array of loaded plugins.\n\t */\n\tinitPlugins() {\n\t\tconst config = this.config;\n\t\tconst plugins = config.get( 'plugins' );\n\t\tconst removePlugins = config.get( 'removePlugins' ) || [];\n\t\tconst extraPlugins = config.get( 'extraPlugins' ) || [];\n\n\t\treturn this.plugins.init( plugins.concat( extraPlugins ), removePlugins );\n\t}\n\n\t/**\n\t * Destroys the editor instance, releasing all resources used by it.\n\t *\n\t * **Note** The editor cannot be destroyed during the initialization phase so if it is called\n\t * while the editor {@link #state is being initialized}, it will wait for the editor initialization before destroying it.\n\t *\n\t * @fires destroy\n\t * @returns {Promise} A promise that resolves once the editor instance is fully destroyed.\n\t */\n\tdestroy() {\n\t\tlet readyPromise = Promise.resolve();\n\n\t\tif ( this.state == 'initializing' ) {\n\t\t\treadyPromise = new Promise( resolve => this.once( 'ready', resolve ) );\n\t\t}\n\n\t\treturn readyPromise\n\t\t\t.then( () => {\n\t\t\t\tthis.fire( 'destroy' );\n\t\t\t\tthis.stopListening();\n\t\t\t\tthis.commands.destroy();\n\t\t\t} )\n\t\t\t.then( () => this.plugins.destroy() )\n\t\t\t.then( () => {\n\t\t\t\tthis.model.destroy();\n\t\t\t\tthis.data.destroy();\n\t\t\t\tthis.editing.destroy();\n\t\t\t\tthis.keystrokes.destroy();\n\t\t\t} )\n\t\t\t// Remove the editor from the context.\n\t\t\t// When the context was created by this editor, the context will be destroyed.\n\t\t\t.then( () => this._context._removeEditor( this ) );\n\t}\n\n\t/**\n\t * Executes the specified command with given parameters.\n\t *\n\t * Shorthand for:\n\t *\n\t *\t\teditor.commands.get( commandName ).execute( ... );\n\t *\n\t * @param {String} commandName The name of the command to execute.\n\t * @param {*} [...commandParams] Command parameters.\n\t */\n\texecute( ...args ) {\n\t\ttry {\n\t\t\tthis.commands.execute( ...args );\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t}\n\n\t/**\n\t * Creates and initializes a new editor instance.\n\t *\n\t * This is an abstract method. Every editor type needs to implement its own initialization logic.\n\t *\n\t * See the `create()` methods of the existing editor types to learn how to use them:\n\t *\n\t * * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`}\n\t * * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`}\n\t * * {@link module:editor-decoupled/decouplededitor~DecoupledEditor.create `DecoupledEditor.create()`}\n\t * * {@link module:editor-inline/inlineeditor~InlineEditor.create `InlineEditor.create()`}\n\t *\n\t * @abstract\n\t * @method module:core/editor/editor~Editor.create\n\t */\n}\n\nmix( Editor, ObservableMixin );\n\n/**\n * Fired when the {@link module:engine/controller/datacontroller~DataController#event:ready data} and all additional\n * editor components are ready.\n *\n * Note: This event is most useful for plugin developers. When integrating the editor with your website or\n * application, you do not have to listen to `editor#ready` because when the promise returned by the static\n * {@link module:core/editor/editor~Editor.create `Editor.create()`} event is resolved, the editor is already ready.\n * In fact, since the first moment when the editor instance is available to you is inside `then()`'s callback,\n * you cannot even add a listener to the `editor#ready` event.\n *\n * See also the {@link #state `editor.state`} property.\n *\n * @event ready\n */\n\n/**\n * Fired when this editor instance is destroyed. The editor at this point is not usable and this event should be used to\n * perform the clean-up in any plugin.\n *\n *\n * See also the {@link #state `editor.state`} property.\n *\n * @event destroy\n */\n\n/**\n * This error is thrown when trying to pass a `<textarea>` element to a `create()` function of an editor class.\n *\n * The only editor type which can be initialized on `<textarea>` elements is {@glink builds/guides/overview#classic-editor classic editor}.\n * This editor hides the passed element and inserts its own UI next to it. Other types of editors reuse the passed element as their root\n * editable element and therefore `<textarea>` is not appropriate for them. Use a `<div>` or another text container instead:\n *\n *\t\t<div id=\"editor\">\n *\t\t\t<p>Initial content.</p>\n *\t\t</div>\n *\n * @error editor-wrong-element\n */\n\n/**\n * An array of plugins built into this editor class.\n *\n * It is used in CKEditor 5 builds to provide a list of plugins which are later automatically initialized\n * during the editor initialization.\n *\n * They will be automatically initialized by the editor, unless listed in `config.removePlugins` and\n * unless `config.plugins` is passed.\n *\n *\t\t// Build some plugins into the editor class first.\n *\t\tClassicEditor.builtinPlugins = [ FooPlugin, BarPlugin ];\n *\n *\t\t// Normally, you need to define config.plugins, but since ClassicEditor.builtinPlugins was\n *\t\t// defined, now you can call create() without any configuration.\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.plugins.get( FooPlugin ); // -> An instance of the Foo plugin.\n *\t\t\t\teditor.plugins.get( BarPlugin ); // -> An instance of the Bar plugin.\n *\t\t\t} );\n *\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement, {\n *\t\t\t\t// Do not initialize these plugins (note: it is defined by a string):\n *\t\t\t\tremovePlugins: [ 'Foo' ]\n *\t\t\t} )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.plugins.get( FooPlugin ); // -> Undefined.\n *\t\t\t\teditor.config.get( BarPlugin ); // -> An instance of the Bar plugin.\n *\t\t\t} );\n *\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement, {\n *\t\t\t\t// Load only this plugin. It can also be defined by a string if\n *\t\t\t\t// this plugin was built into the editor class.\n *\t\t\t\tplugins: [ FooPlugin ]\n *\t\t\t} )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.plugins.get( FooPlugin ); // -> An instance of the Foo plugin.\n *\t\t\t\teditor.config.get( BarPlugin ); // -> Undefined.\n *\t\t\t} );\n *\n * See also {@link module:core/editor/editor~Editor.defaultConfig}.\n *\n * @static\n * @member {Array.<Function>} module:core/editor/editor~Editor.builtinPlugins\n */\n\n/**\n * The default configuration which is built into the editor class.\n *\n * It is used in CKEditor 5 builds to provide the default configuration options which are later used during the editor initialization.\n *\n *\t\tClassicEditor.defaultConfig = {\n *\t\t\tfoo: 1,\n *\t\t\tbar: 2\n *\t\t};\n *\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.config.get( 'foo' ); // -> 1\n *\t\t\t\teditor.config.get( 'bar' ); // -> 2\n *\t\t\t} );\n *\n *\t\t// The default options can be overridden by the configuration passed to create().\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement, { bar: 3 } )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.config.get( 'foo' ); // -> 1\n *\t\t\t\teditor.config.get( 'bar' ); // -> 3\n *\t\t\t} );\n *\n * See also {@link module:core/editor/editor~Editor.builtinPlugins}.\n *\n * @static\n * @member {Object} module:core/editor/editor~Editor.defaultConfig\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 core/editor/utils/dataapimixin\n */\n\n/**\n * Implementation of the {@link module:core/editor/utils/dataapimixin~DataApi}.\n *\n * @mixin DataApiMixin\n * @implements module:core/editor/utils/dataapimixin~DataApi\n */\nconst DataApiMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\tsetData( data ) {\n\t\tthis.data.set( data );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tgetData( options ) {\n\t\treturn this.data.get( options );\n\t}\n};\n\nexport default DataApiMixin;\n\n/**\n * Interface defining editor methods for setting and getting data to and from the editor's main root element\n * using the {@link module:core/editor/editor~Editor#data data pipeline}.\n *\n * This interface is not a part of the {@link module:core/editor/editor~Editor} class because one may want to implement\n * an editor with multiple root elements, in which case the methods for setting and getting data will need to be implemented\n * differently.\n *\n * @interface DataApi\n */\n\n/**\n * Sets the data in the editor.\n *\n *\t\teditor.setData( '<p>This is editor!</p>' );\n *\n * By default the editor accepts HTML. This can be controlled by injecting a different data processor.\n * See the {@glink features/markdown Markdown output} guide for more details.\n *\n * Note: Not only is the format of the data configurable, but the type of the `setData()`'s parameter does not\n * have to be a string either. You can e.g. accept an object or a DOM `DocumentFragment` if you consider this\n * the right format for you.\n *\n * @method #setData\n * @param {String} data Input data.\n */\n\n/**\n * Gets the data from the editor.\n *\n *\t\teditor.getData(); // -> '<p>This is editor!</p>'\n *\n * By default the editor outputs HTML. This can be controlled by injecting a different data processor.\n * See the {@glink features/markdown Markdown output} guide for more details.\n *\n * Note: Not only is the format of the data configurable, but the type of the `getData()`'s return value does not\n * have to be a string either. You can e.g. return an object or a DOM `DocumentFragment` if you consider this\n * the right format for you.\n *\n * @method #getData\n * @param {Object} [options]\n * @param {String} [options.rootName='main'] Root name.\n * @param {String} [options.trim='empty'] Whether returned data should be trimmed. This option is set to `'empty'` by default,\n * which means that whenever editor content is considered empty, an empty string is returned. To turn off trimming\n * use `'none'`. In such cases exact content will be returned (for example `'<p> </p>'` for an empty editor).\n * @returns {String} Output data.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport setDataInElement from '@ckeditor/ckeditor5-utils/src/dom/setdatainelement';\n\n/**\n * @module core/editor/utils/elementapimixin\n */\n\n/**\n * Implementation of the {@link module:core/editor/utils/elementapimixin~ElementApi}.\n *\n * @mixin ElementApiMixin\n * @implements module:core/editor/utils/elementapimixin~ElementApi\n */\nconst ElementApiMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\tupdateSourceElement() {\n\t\tif ( !this.sourceElement ) {\n\t\t\t/**\n\t\t\t * Cannot update the source element of a detached editor.\n\t\t\t *\n\t\t\t * The {@link ~ElementApi#updateSourceElement `updateSourceElement()`} method cannot be called if you did not\n\t\t\t * pass an element to `Editor.create()`.\n\t\t\t *\n\t\t\t * @error editor-missing-sourceelement\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'editor-missing-sourceelement: Cannot update the source element of a detached editor.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tsetDataInElement( this.sourceElement, this.data.get() );\n\t}\n};\n\nexport default ElementApiMixin;\n\n/**\n * Interface describing an editor that replaced a DOM element (was \"initialized on an element\").\n *\n * Such an editor should provide a method to\n * {@link module:core/editor/utils/elementapimixin~ElementApi#updateSourceElement update the replaced element with the current data}.\n *\n * @interface ElementApi\n */\n\n/**\n * The element on which the editor has been initialized.\n *\n * @readonly\n * @member {HTMLElement} #sourceElement\n */\n\n/**\n * Updates the {@link #sourceElement editor source element}'s content with the data.\n *\n * @method #updateSourceElement\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/setdatainelement\n */\n\n/* globals HTMLTextAreaElement */\n\n/**\n * Sets data in a given element.\n *\n * @param {HTMLElement} el The element in which the data will be set.\n * @param {String} data The data string.\n */\nexport default function setDataInElement( el, data ) {\n\tif ( el instanceof HTMLTextAreaElement ) {\n\t\tel.value = data;\n\t}\n\n\tel.innerHTML = data;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/dataprocessor/basichtmlwriter\n */\n\n/* globals document */\n\n/**\n * Basic HTML writer. It uses the native `innerHTML` property for basic conversion\n * from a document fragment to an HTML string.\n *\n * @implements module:engine/dataprocessor/htmlwriter~HtmlWriter\n */\nexport default class BasicHtmlWriter {\n\t/**\n\t * Returns an HTML string created from the document fragment.\n\t *\n\t * @param {DocumentFragment} fragment\n\t * @returns {String}\n\t */\n\tgetHtml( fragment ) {\n\t\tconst doc = document.implementation.createHTMLDocument( '' );\n\t\tconst container = doc.createElement( 'div' );\n\t\tcontainer.appendChild( fragment );\n\n\t\treturn container.innerHTML;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/dataprocessor/htmldataprocessor\n */\n\n/* globals document, DOMParser */\n\nimport BasicHtmlWriter from './basichtmlwriter';\nimport DomConverter from '../view/domconverter';\n\n/**\n * The HTML data processor class.\n * This data processor implementation uses HTML as input and output data.\n *\n * @implements module:engine/dataprocessor/dataprocessor~DataProcessor\n */\nexport default class HtmlDataProcessor {\n\t/**\n\t * Creates a new instance of the HTML data processor class.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * A DOM parser instance used to parse an HTML string to an HTML document.\n\t\t *\n\t\t * @private\n\t\t * @member {DOMParser}\n\t\t */\n\t\tthis._domParser = new DOMParser();\n\n\t\t/**\n\t\t * A DOM converter used to convert DOM elements to view elements.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/domconverter~DomConverter}\n\t\t */\n\t\tthis._domConverter = new DomConverter( { blockFillerMode: 'nbsp' } );\n\n\t\t/**\n\t\t * A basic HTML writer instance used to convert DOM elements to an HTML string.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/dataprocessor/basichtmlwriter~BasicHtmlWriter}\n\t\t */\n\t\tthis._htmlWriter = new BasicHtmlWriter();\n\t}\n\n\t/**\n\t * Converts a provided {@link module:engine/view/documentfragment~DocumentFragment document fragment}\n\t * to data format — in this case to an HTML string.\n\t *\n\t * @param {module:engine/view/documentfragment~DocumentFragment} viewFragment\n\t * @returns {String} HTML string.\n\t */\n\ttoData( viewFragment ) {\n\t\t// Convert view DocumentFragment to DOM DocumentFragment.\n\t\tconst domFragment = this._domConverter.viewToDom( viewFragment, document );\n\n\t\t// Convert DOM DocumentFragment to HTML output.\n\t\treturn this._htmlWriter.getHtml( domFragment );\n\t}\n\n\t/**\n\t * Converts the provided HTML string to a view tree.\n\t *\n\t * @param {String} data An HTML string.\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null} A converted view element.\n\t */\n\ttoView( data ) {\n\t\t// Convert input HTML data to DOM DocumentFragment.\n\t\tconst domFragment = this._toDom( data );\n\n\t\t// Convert DOM DocumentFragment to view DocumentFragment.\n\t\treturn this._domConverter.domToView( domFragment );\n\t}\n\n\t/**\n\t * Converts an HTML string to its DOM representation. Returns a document fragment containing nodes parsed from\n\t * the provided data.\n\t *\n\t * @private\n\t * @param {String} data\n\t * @returns {DocumentFragment}\n\t */\n\t_toDom( data ) {\n\t\tconst document = this._domParser.parseFromString( data, 'text/html' );\n\t\tconst fragment = document.createDocumentFragment();\n\t\tconst nodes = document.body.childNodes;\n\n\t\twhile ( nodes.length > 0 ) {\n\t\t\tfragment.appendChild( nodes[ 0 ] );\n\t\t}\n\n\t\treturn fragment;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/componentfactory\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * A helper class implementing the UI component ({@link module:ui/view~View view}) factory.\n *\n * It allows functions producing specific UI components to be registered under their unique names\n * in the factory. A registered component can be then instantiated by providing its name.\n * Note that names are case insensitive.\n *\n *\t\t// The editor provides localization tools for the factory.\n *\t\tconst factory = new ComponentFactory( editor );\n *\n *\t\tfactory.add( 'foo', locale => new FooView( locale ) );\n *\t\tfactory.add( 'bar', locale => new BarView( locale ) );\n *\n *\t\t// An instance of FooView.\n *\t\tconst fooInstance = factory.create( 'foo' );\n *\n *\t\t// Names are case insensitive so this is also allowed:\n *\t\tconst barInstance = factory.create( 'Bar' );\n *\n * The {@link module:core/editor/editor~Editor#locale editor locale} is passed to the factory\n * function when {@link module:ui/componentfactory~ComponentFactory#create} is called.\n */\nexport default class ComponentFactory {\n\t/**\n\t * Creates an instance of the factory.\n\t *\n\t * @constructor\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor instance that the factory belongs to.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * Registered component factories.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._components = new Map();\n\t}\n\n\t/**\n\t * Returns an iterator of registered component names. Names are returned in lower case.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\t* names() {\n\t\tfor ( const value of this._components.values() ) {\n\t\t\tyield value.originalName;\n\t\t}\n\t}\n\n\t/**\n\t * Registers a component factory function that will be used by the\n\t * {@link #create create} method and called with the\n\t * {@link module:core/editor/editor~Editor#locale editor locale} as an argument,\n\t * allowing localization of the {@link module:ui/view~View view}.\n\t *\n\t * @param {String} name The name of the component.\n\t * @param {Function} callback The callback that returns the component.\n\t */\n\tadd( name, callback ) {\n\t\tif ( this.has( name ) ) {\n\t\t\t/**\n\t\t\t * The item already exists in the component factory.\n\t\t\t *\n\t\t\t * @error componentfactory-item-exists\n\t\t\t * @param {String} name The name of the component.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'componentfactory-item-exists: The item already exists in the component factory.',\n\t\t\t\tthis,\n\t\t\t\t{ name }\n\t\t\t);\n\t\t}\n\n\t\tthis._components.set( getNormalized( name ), { callback, originalName: name } );\n\t}\n\n\t/**\n\t * Creates an instance of a component registered in the factory under a specific name.\n\t *\n\t * When called, the {@link module:core/editor/editor~Editor#locale editor locale} is passed to\n\t * the previously {@link #add added} factory function, allowing localization of the\n\t * {@link module:ui/view~View view}.\n\t *\n\t * @param {String} name The name of the component.\n\t * @returns {module:ui/view~View} The instantiated component view.\n\t */\n\tcreate( name ) {\n\t\tif ( !this.has( name ) ) {\n\t\t\t/**\n\t\t\t * The required component is not registered in the component factory. Please make sure\n\t\t\t * the provided name is correct and the component has been correctly\n\t\t\t * {@link #add added} to the factory.\n\t\t\t *\n\t\t\t * @error componentfactory-item-missing\n\t\t\t * @param {String} name The name of the missing component.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'componentfactory-item-missing: The required component is not registered in the factory.',\n\t\t\t\tthis,\n\t\t\t\t{ name }\n\t\t\t);\n\t\t}\n\n\t\treturn this._components.get( getNormalized( name ) ).callback( this.editor.locale );\n\t}\n\n\t/**\n\t * Checks if a component of a given name is registered in the factory.\n\t *\n\t * @param {String} name The name of the component.\n\t * @returns {Boolean}\n\t */\n\thas( name ) {\n\t\treturn this._components.has( getNormalized( name ) );\n\t}\n}\n\n//\n// Ensures that the component name used as the key in the internal map is in lower case.\n//\n// @private\n// @param {String} name\n// @returns {String}\nfunction getNormalized( name ) {\n\treturn String( name ).toLowerCase();\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* global setTimeout, clearTimeout */\n\n/**\n * @module utils/focustracker\n */\n\nimport DomEmitterMixin from './dom/emittermixin';\nimport ObservableMixin from './observablemixin';\nimport CKEditorError from './ckeditorerror';\nimport mix from './mix';\n\n/**\n * Allows observing a group of `HTMLElement`s whether at least one of them is focused.\n *\n * Used by the {@link module:core/editor/editor~Editor} in order to track whether the focus is still within the application,\n * or were used outside of its UI.\n *\n * **Note** `focus` and `blur` listeners use event capturing, so it is only needed to register wrapper `HTMLElement`\n * which contain other `focusable` elements. But note that this wrapper element has to be focusable too\n * (have e.g. `tabindex=\"-1\"`).\n *\n * @mixes module:utils/dom/emittermixin~EmitterMixin\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class FocusTracker {\n\tconstructor() {\n\t\t/**\n\t\t * True when one of the registered elements is focused.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * The currently focused element.\n\t\t *\n\t\t * While {@link #isFocused `isFocused`} remains `true`, the focus can\n\t\t * move between different UI elements. This property tracks those\n\t\t * elements and tells which one is currently focused.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {HTMLElement|null}\n\t\t */\n\t\tthis.set( 'focusedElement', null );\n\n\t\t/**\n\t\t * List of registered elements.\n\t\t *\n\t\t * @private\n\t\t * @member {Set.<HTMLElement>}\n\t\t */\n\t\tthis._elements = new Set();\n\n\t\t/**\n\t\t * Event loop timeout.\n\t\t *\n\t\t * @private\n\t\t * @member {Number}\n\t\t */\n\t\tthis._nextEventLoopTimeout = null;\n\t}\n\n\t/**\n\t * Starts tracking the specified element.\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tadd( element ) {\n\t\tif ( this._elements.has( element ) ) {\n\t\t\tthrow new CKEditorError( 'focusTracker-add-element-already-exist', this );\n\t\t}\n\n\t\tthis.listenTo( element, 'focus', () => this._focus( element ), { useCapture: true } );\n\t\tthis.listenTo( element, 'blur', () => this._blur(), { useCapture: true } );\n\t\tthis._elements.add( element );\n\t}\n\n\t/**\n\t * Stops tracking the specified element and stops listening on this element.\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tremove( element ) {\n\t\tif ( element === this.focusedElement ) {\n\t\t\tthis._blur( element );\n\t\t}\n\n\t\tif ( this._elements.has( element ) ) {\n\t\t\tthis.stopListening( element );\n\t\t\tthis._elements.delete( element );\n\t\t}\n\t}\n\n\t/**\n\t * Destroys the focus tracker by:\n\t * - Disabling all event listeners attached to tracked elements.\n\t * - Removing all tracked elements that were previously added.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Stores currently focused element and set {#isFocused} as `true`.\n\t *\n\t * @private\n\t * @param {HTMLElement} element Element which has been focused.\n\t */\n\t_focus( element ) {\n\t\tclearTimeout( this._nextEventLoopTimeout );\n\n\t\tthis.focusedElement = element;\n\t\tthis.isFocused = true;\n\t}\n\n\t/**\n\t * Clears currently focused element and set {@link #isFocused} as `false`.\n\t * This method uses `setTimeout` to change order of fires `blur` and `focus` events.\n\t *\n\t * @private\n\t * @fires blur\n\t */\n\t_blur() {\n\t\tclearTimeout( this._nextEventLoopTimeout );\n\n\t\tthis._nextEventLoopTimeout = setTimeout( () => {\n\t\t\tthis.focusedElement = null;\n\t\t\tthis.isFocused = false;\n\t\t}, 0 );\n\t}\n\n\t/**\n\t * @event focus\n\t */\n\n\t/**\n\t * @event blur\n\t */\n}\n\nmix( FocusTracker, DomEmitterMixin );\nmix( FocusTracker, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 core/editor/editorui\n */\n\n/* globals console */\n\nimport ComponentFactory from '@ckeditor/ckeditor5-ui/src/componentfactory';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * A class providing the minimal interface that is required to successfully bootstrap any editor UI.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class EditorUI {\n\t/**\n\t * Creates an instance of the editor UI class.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor that the UI belongs to.\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 * An instance of the {@link module:ui/componentfactory~ComponentFactory}, a registry used by plugins\n\t\t * to register factories of specific UI components.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/componentfactory~ComponentFactory} #componentFactory\n\t\t */\n\t\tthis.componentFactory = new ComponentFactory( editor );\n\n\t\t/**\n\t\t * Stores the information about the editor UI focus and propagates it so various plugins and components\n\t\t * are unified as a focus group.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker} #focusTracker\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Stores all editable elements used by the editor instance.\n\t\t *\n\t\t * @private\n\t\t * @member {Map.<String,HTMLElement>}\n\t\t */\n\t\tthis._editableElementsMap = new Map();\n\n\t\t// Informs UI components that should be refreshed after layout change.\n\t\tthis.listenTo( editor.editing.view.document, 'layoutChanged', () => this.update() );\n\t}\n\n\t/**\n\t * The main (outermost) DOM element of the editor UI.\n\t *\n\t * For example, in {@link module:editor-classic/classiceditor~ClassicEditor} it is a `<div>` which\n\t * wraps the editable element and the toolbar. In {@link module:editor-inline/inlineeditor~InlineEditor}\n\t * it is the editable element itself (as there is no other wrapper). However, in\n\t * {@link module:editor-decoupled/decouplededitor~DecoupledEditor} it is set to `null` because this editor does not\n\t * come with a single \"main\" HTML element (its editable element and toolbar are separate).\n\t *\n\t * This property can be understood as a shorthand for retrieving the element that a specific editor integration\n\t * considers to be its main DOM element.\n\t *\n\t * @readonly\n\t * @member {HTMLElement|null} #element\n\t */\n\tget element() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Fires the {@link module:core/editor/editorui~EditorUI#event:update `update`} event.\n\t *\n\t * This method should be called when the editor UI (e.g. positions of its balloons) needs to be updated due to\n\t * some environmental change which CKEditor 5 is not aware of (e.g. resize of a container in which it is used).\n\t */\n\tupdate() {\n\t\tthis.fire( 'update' );\n\t}\n\n\t/**\n\t * Destroys the UI.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\n\t\tthis.focusTracker.destroy();\n\n\t\t// Clean–up the references to the CKEditor instance stored in the native editable DOM elements.\n\t\tfor ( const domElement of this._editableElementsMap.values() ) {\n\t\t\tdomElement.ckeditorInstance = null;\n\t\t}\n\n\t\tthis._editableElementsMap = new Map();\n\t}\n\n\t/**\n\t * Store the native DOM editable element used by the editor under\n\t * a unique name.\n\t *\n\t * @param {String} rootName The unique name of the editable element.\n\t * @param {HTMLElement} domElement The native DOM editable element.\n\t */\n\tsetEditableElement( rootName, domElement ) {\n\t\tthis._editableElementsMap.set( rootName, domElement );\n\n\t\t// Put a reference to the CKEditor instance in the editable native DOM element.\n\t\t// It helps 3rd–party software (browser extensions, other libraries) access and recognize\n\t\t// CKEditor 5 instances (editing roots) and use their API (there is no global editor\n\t\t// instance registry).\n\t\tif ( !domElement.ckeditorInstance ) {\n\t\t\tdomElement.ckeditorInstance = this.editor;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the editable editor element with the given name or null if editable does not exist.\n\t *\n\t * @param {String} [rootName=main] The editable name.\n\t * @returns {HTMLElement|undefined}\n\t */\n\tgetEditableElement( rootName = 'main' ) {\n\t\treturn this._editableElementsMap.get( rootName );\n\t}\n\n\t/**\n\t * Returns array of names of all editor editable elements.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetEditableElementsNames() {\n\t\treturn this._editableElementsMap.keys();\n\t}\n\n\t/**\n\t * Stores all editable elements used by the editor instance.\n\t *\n\t * @protected\n\t * @deprecated\n\t * @member {Map.<String,HTMLElement>}\n\t */\n\tget _editableElements() {\n\t\t/**\n\t\t * The {@link module:core/editor/editorui~EditorUI#_editableElements `EditorUI#_editableElements`} property has been\n\t\t * deprecated and will be removed in the near future. Please use {@link #setEditableElement `setEditableElement()`} and\n\t\t * {@link #getEditableElement `getEditableElement()`} methods instead.\n\t\t *\n\t\t * @error editor-ui-deprecated-editable-elements\n\t\t * @param {module:core/editor/editorui~EditorUI} editorUI Editor UI instance the deprecated property belongs to.\n\t\t */\n\t\tconsole.warn(\n\t\t\t'editor-ui-deprecated-editable-elements: ' +\n\t\t\t'The EditorUI#_editableElements property has been deprecated and will be removed in the near future.',\n\t\t\t{ editorUI: this } );\n\n\t\treturn this._editableElementsMap;\n\t}\n\n\t/**\n\t * Fired when the editor UI is ready.\n\t *\n\t * Fired before {@link module:engine/controller/datacontroller~DataController#event:ready}.\n\t *\n\t * @event ready\n\t */\n\n\t/**\n\t * Fired whenever the UI (all related components) should be refreshed.\n\t *\n\t * **Note:**: The event is fired after each {@link module:engine/view/document~Document#event:layoutChanged}.\n\t * It can also be fired manually via the {@link module:core/editor/editorui~EditorUI#update} method.\n\t *\n\t * @event update\n\t */\n}\n\nmix( EditorUI, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/placeholder\n */\n\nimport '../../theme/placeholder.css';\n\n// Each document stores information about its placeholder elements and check functions.\nconst documentPlaceholders = new WeakMap();\n\n/**\n * A helper that enables a placeholder on the provided view element (also updates its visibility).\n * The placeholder is a CSS pseudo–element (with a text content) attached to the element.\n *\n * To change the placeholder text, simply call this method again with new options.\n *\n * To disable the placeholder, use {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} helper.\n *\n * @param {Object} [options] Configuration options of the placeholder.\n * @param {module:engine/view/view~View} options.view Editing view instance.\n * @param {module:engine/view/element~Element} options.element Element that will gain a placeholder.\n * See `options.isDirectHost` to learn more.\n * @param {String} options.text Placeholder text.\n * @param {Boolean} [options.isDirectHost=true] If set `false`, the placeholder will not be enabled directly\n * in the passed `element` but in one of its children (selected automatically, i.e. a first empty child element).\n * Useful when attaching placeholders to elements that can host other elements (not just text), for instance,\n * editable root elements.\n */\nexport function enablePlaceholder( options ) {\n\tconst { view, element, text, isDirectHost = true } = options;\n\tconst doc = view.document;\n\n\t// Use a single a single post fixer per—document to update all placeholders.\n\tif ( !documentPlaceholders.has( doc ) ) {\n\t\tdocumentPlaceholders.set( doc, new Map() );\n\n\t\t// If a post-fixer callback makes a change, it should return `true` so other post–fixers\n\t\t// can re–evaluate the document again.\n\t\tdoc.registerPostFixer( writer => updateDocumentPlaceholders( doc, writer ) );\n\t}\n\n\t// Store information about the element placeholder under its document.\n\tdocumentPlaceholders.get( doc ).set( element, {\n\t\ttext,\n\t\tisDirectHost\n\t} );\n\n\t// Update the placeholders right away.\n\tview.change( writer => updateDocumentPlaceholders( doc, writer ) );\n}\n\n/**\n * Disables the placeholder functionality from a given element.\n *\n * See {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} to learn more.\n *\n * @param {module:engine/view/view~View} view\n * @param {module:engine/view/element~Element} element\n */\nexport function disablePlaceholder( view, element ) {\n\tconst doc = element.document;\n\n\tview.change( writer => {\n\t\tif ( !documentPlaceholders.has( doc ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst placeholders = documentPlaceholders.get( doc );\n\t\tconst config = placeholders.get( element );\n\n\t\twriter.removeAttribute( 'data-placeholder', config.hostElement );\n\t\thidePlaceholder( writer, config.hostElement );\n\n\t\tplaceholders.delete( element );\n\t} );\n}\n\n/**\n * Shows a placeholder in the provided element by changing related attributes and CSS classes.\n *\n * **Note**: This helper will not update the placeholder visibility nor manage the\n * it in any way in the future. What it does is a one–time state change of an element. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} and\n * {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} for full\n * placeholder functionality.\n *\n * **Note**: This helper will blindly show the placeholder directly in the root editable element if\n * one is passed, which could result in a visual clash if the editable element has some children\n * (for instance, an empty paragraph). Use {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`}\n * in that case or make sure the correct element is passed to the helper.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/view/element~Element} element\n * @returns {Boolean} `true`, if any changes were made to the `element`.\n */\nexport function showPlaceholder( writer, element ) {\n\tif ( !element.hasClass( 'ck-placeholder' ) ) {\n\t\twriter.addClass( 'ck-placeholder', element );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Hides a placeholder in the element by changing related attributes and CSS classes.\n *\n * **Note**: This helper will not update the placeholder visibility nor manage the\n * it in any way in the future. What it does is a one–time state change of an element. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} and\n * {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} for full\n * placeholder functionality.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/view/element~Element} element\n * @returns {Boolean} `true`, if any changes were made to the `element`.\n */\nexport function hidePlaceholder( writer, element ) {\n\tif ( element.hasClass( 'ck-placeholder' ) ) {\n\t\twriter.removeClass( 'ck-placeholder', element );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Checks if a placeholder should be displayed in the element.\n *\n * **Note**: This helper will blindly check the possibility of showing a placeholder directly in the\n * root editable element if one is passed, which may not be the expected result. If an element can\n * host other elements (not just text), most likely one of its children should be checked instead\n * because it will be the final host for the placeholder. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} in that case or make\n * sure the correct element is passed to the helper.\n *\n * @param {module:engine/view/element~Element} element\n * @returns {Boolean}\n */\nexport function needsPlaceholder( element ) {\n\tconst doc = element.document;\n\n\t// The element was removed from document.\n\tif ( !doc ) {\n\t\treturn false;\n\t}\n\n\t// The element is empty only as long as it contains nothing but uiElements.\n\tconst isEmptyish = !Array.from( element.getChildren() )\n\t\t.some( element => !element.is( 'uiElement' ) );\n\n\t// If the element is empty and the document is blurred.\n\tif ( !doc.isFocused && isEmptyish ) {\n\t\treturn true;\n\t}\n\n\tconst viewSelection = doc.selection;\n\tconst selectionAnchor = viewSelection.anchor;\n\n\t// If document is focused and the element is empty but the selection is not anchored inside it.\n\tif ( isEmptyish && selectionAnchor && selectionAnchor.parent !== element ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// Updates all placeholders associated with a document in a post–fixer callback.\n//\n// @private\n// @param { module:engine/view/document~Document} doc\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {Boolean} True if any changes were made to the view document.\nfunction updateDocumentPlaceholders( doc, writer ) {\n\tconst placeholders = documentPlaceholders.get( doc );\n\tlet wasViewModified = false;\n\n\tfor ( const [ element, config ] of placeholders ) {\n\t\tif ( updatePlaceholder( writer, element, config ) ) {\n\t\t\twasViewModified = true;\n\t\t}\n\t}\n\n\treturn wasViewModified;\n}\n\n// Updates a single placeholder in a post–fixer callback.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:engine/view/element~Element} element\n// @param {Object} config Configuration of the placeholder\n// @param {String} config.text\n// @param {Boolean} config.isDirectHost\n// @returns {Boolean} True if any changes were made to the view document.\nfunction updatePlaceholder( writer, element, config ) {\n\tconst { text, isDirectHost } = config;\n\tconst hostElement = isDirectHost ? element : getChildPlaceholderHostSubstitute( element );\n\tlet wasViewModified = false;\n\n\t// When not a direct host, it could happen that there is no child element\n\t// capable of displaying a placeholder.\n\tif ( !hostElement ) {\n\t\treturn false;\n\t}\n\n\t// Cache the host element. It will be necessary for disablePlaceholder() to know\n\t// which element should have class and attribute removed because, depending on\n\t// the config.isDirectHost value, it could be the element or one of its descendants.\n\tconfig.hostElement = hostElement;\n\n\t// This may be necessary when updating the placeholder text to something else.\n\tif ( hostElement.getAttribute( 'data-placeholder' ) !== text ) {\n\t\twriter.setAttribute( 'data-placeholder', text, hostElement );\n\t\twasViewModified = true;\n\t}\n\n\tif ( needsPlaceholder( hostElement ) ) {\n\t\tif ( showPlaceholder( writer, hostElement ) ) {\n\t\t\twasViewModified = true;\n\t\t}\n\t} else if ( hidePlaceholder( writer, hostElement ) ) {\n\t\twasViewModified = true;\n\t}\n\n\treturn wasViewModified;\n}\n\n// Gets a child element capable of displaying a placeholder if a parent element can host more\n// than just text (for instance, when it is a root editable element). The child element\n// can then be used in other placeholder helpers as a substitute of its parent.\n//\n// @private\n// @param {module:engine/view/element~Element} parent\n// @returns {module:engine/view/element~Element|null}\nfunction getChildPlaceholderHostSubstitute( parent ) {\n\tif ( parent.childCount === 1 ) {\n\t\tconst firstChild = parent.getChild( 0 );\n\n\t\tif ( firstChild.is( 'element' ) && !firstChild.is( 'uiElement' ) ) {\n\t\t\treturn firstChild;\n\t\t}\n\t}\n\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/elementreplacer\n */\n\n/**\n * Utility class allowing to hide existing HTML elements or replace them with given ones in a way that doesn't remove\n * the original elements from the DOM.\n */\nexport default class ElementReplacer {\n\tconstructor() {\n\t\t/**\n\t\t * The elements replaced by {@link #replace} and their replacements.\n\t\t *\n\t\t * @private\n\t\t * @member {Array.<Object>}\n\t\t */\n\t\tthis._replacedElements = [];\n\t}\n\n\t/**\n\t * Hides the `element` and, if specified, inserts the the given element next to it.\n\t *\n\t * The effect of this method can be reverted by {@link #restore}.\n\t *\n\t * @param {HTMLElement} element The element to replace.\n\t * @param {HTMLElement} [newElement] The replacement element. If not passed, then the `element` will just be hidden.\n\t */\n\treplace( element, newElement ) {\n\t\tthis._replacedElements.push( { element, newElement } );\n\n\t\telement.style.display = 'none';\n\n\t\tif ( newElement ) {\n\t\t\telement.parentNode.insertBefore( newElement, element.nextSibling );\n\t\t}\n\t}\n\n\t/**\n\t * Restores what {@link #replace} did.\n\t */\n\trestore() {\n\t\tthis._replacedElements.forEach( ( { element, newElement } ) => {\n\t\t\telement.style.display = '';\n\n\t\t\tif ( newElement ) {\n\t\t\t\tnewElement.remove();\n\t\t\t}\n\t\t} );\n\n\t\tthis._replacedElements = [];\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 editor-classic/classiceditorui\n */\n\nimport EditorUI from '@ckeditor/ckeditor5-core/src/editor/editorui';\nimport enableToolbarKeyboardFocus from '@ckeditor/ckeditor5-ui/src/toolbar/enabletoolbarkeyboardfocus';\nimport normalizeToolbarConfig from '@ckeditor/ckeditor5-ui/src/toolbar/normalizetoolbarconfig';\nimport { enablePlaceholder } from '@ckeditor/ckeditor5-engine/src/view/placeholder';\nimport ElementReplacer from '@ckeditor/ckeditor5-utils/src/elementreplacer';\n\n/**\n * The classic editor UI class.\n *\n * @extends module:core/editor/editorui~EditorUI\n */\nexport default class ClassicEditorUI extends EditorUI {\n\t/**\n\t * Creates an instance of the classic editor UI class.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {module:ui/editorui/editoruiview~EditorUIView} view The view of the UI.\n\t */\n\tconstructor( editor, view ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The main (top–most) view of the editor UI.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/editorui/editoruiview~EditorUIView} #view\n\t\t */\n\t\tthis.view = view;\n\n\t\t/**\n\t\t * A normalized `config.toolbar` object.\n\t\t *\n\t\t * @private\n\t\t * @member {Object}\n\t\t */\n\t\tthis._toolbarConfig = normalizeToolbarConfig( editor.config.get( 'toolbar' ) );\n\n\t\t/**\n\t\t * The element replacer instance used to hide the editor's source element.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:utils/elementreplacer~ElementReplacer}\n\t\t */\n\t\tthis._elementReplacer = new ElementReplacer();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget element() {\n\t\treturn this.view.element;\n\t}\n\n\t/**\n\t * Initializes the UI.\n\t *\n\t * @param {HTMLElement|null} replacementElement The DOM element that will be the source for the created editor.\n\t */\n\tinit( replacementElement ) {\n\t\tconst editor = this.editor;\n\t\tconst view = this.view;\n\t\tconst editingView = editor.editing.view;\n\t\tconst editable = view.editable;\n\t\tconst editingRoot = editingView.document.getRoot();\n\n\t\t// The editable UI and editing root should share the same name. Then name is used\n\t\t// to recognize the particular editable, for instance in ARIA attributes.\n\t\teditable.name = editingRoot.rootName;\n\n\t\tview.render();\n\n\t\t// The editable UI element in DOM is available for sure only after the editor UI view has been rendered.\n\t\t// But it can be available earlier if a DOM element has been passed to BalloonEditor.create().\n\t\tconst editableElement = editable.element;\n\n\t\t// Register the editable UI view in the editor. A single editor instance can aggregate multiple\n\t\t// editable areas (roots) but the classic editor has only one.\n\t\tthis.setEditableElement( editable.name, editableElement );\n\n\t\t// Let the global focus tracker know that the editable UI element is focusable and\n\t\t// belongs to the editor. From now on, the focus tracker will sustain the editor focus\n\t\t// as long as the editable is focused (e.g. the user is typing).\n\t\tthis.focusTracker.add( editableElement );\n\n\t\t// Let the editable UI element respond to the changes in the global editor focus\n\t\t// tracker. It has been added to the same tracker a few lines above but, in reality, there are\n\t\t// many focusable areas in the editor, like balloons, toolbars or dropdowns and as long\n\t\t// as they have focus, the editable should act like it is focused too (although technically\n\t\t// it isn't), e.g. by setting the proper CSS class, visually announcing focus to the user.\n\t\t// Doing otherwise will result in editable focus styles disappearing, once e.g. the\n\t\t// toolbar gets focused.\n\t\tview.editable.bind( 'isFocused' ).to( this.focusTracker );\n\n\t\t// Bind the editable UI element to the editing view, making it an end– and entry–point\n\t\t// of the editor's engine. This is where the engine meets the UI.\n\t\teditingView.attachDomRoot( editableElement );\n\n\t\t// If an element containing the initial data of the editor was provided, replace it with\n\t\t// an editor instance's UI in DOM until the editor is destroyed. For instance, a <textarea>\n\t\t// can be such element.\n\t\tif ( replacementElement ) {\n\t\t\tthis._elementReplacer.replace( replacementElement, this.element );\n\t\t}\n\n\t\tthis._initPlaceholder();\n\t\tthis._initToolbar();\n\t\tthis.fire( 'ready' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tconst view = this.view;\n\t\tconst editingView = this.editor.editing.view;\n\n\t\tthis._elementReplacer.restore();\n\t\teditingView.detachDomRoot( view.editable.name );\n\t\tview.destroy();\n\n\t\tsuper.destroy();\n\t}\n\n\t/**\n\t * Initializes the editor toolbar.\n\t *\n\t * @private\n\t */\n\t_initToolbar() {\n\t\tconst editor = this.editor;\n\t\tconst view = this.view;\n\t\tconst editingView = editor.editing.view;\n\n\t\t// Set–up the sticky panel with toolbar.\n\t\tview.stickyPanel.bind( 'isActive' ).to( this.focusTracker, 'isFocused' );\n\t\tview.stickyPanel.limiterElement = view.element;\n\n\t\tif ( this._toolbarConfig.viewportTopOffset ) {\n\t\t\tview.stickyPanel.viewportTopOffset = this._toolbarConfig.viewportTopOffset;\n\t\t}\n\n\t\tview.toolbar.fillFromConfig( this._toolbarConfig.items, this.componentFactory );\n\n\t\tenableToolbarKeyboardFocus( {\n\t\t\torigin: editingView,\n\t\t\toriginFocusTracker: this.focusTracker,\n\t\t\toriginKeystrokeHandler: editor.keystrokes,\n\t\t\ttoolbar: view.toolbar\n\t\t} );\n\t}\n\n\t/**\n\t * Enable the placeholder text on the editing root, if any was configured.\n\t *\n\t * @private\n\t */\n\t_initPlaceholder() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\t\tconst editingRoot = editingView.document.getRoot();\n\t\tconst sourceElement = editor.sourceElement;\n\n\t\tconst placeholderText = editor.config.get( 'placeholder' ) ||\n\t\t\tsourceElement && sourceElement.tagName.toLowerCase() === 'textarea' && sourceElement.getAttribute( 'placeholder' );\n\n\t\tif ( placeholderText ) {\n\t\t\tenablePlaceholder( {\n\t\t\t\tview: editingView,\n\t\t\t\telement: editingRoot,\n\t\t\t\ttext: placeholderText,\n\t\t\t\tisDirectHost: false\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/toolbar/normalizetoolbarconfig\n */\n\n/**\n * Normalizes the toolbar configuration (`config.toolbar`), which:\n *\n * * may be defined as an `Array`:\n *\n * \t\ttoolbar: [ 'heading', 'bold', 'italic', 'link', ... ]\n *\n * * or an `Object`:\n *\n *\t\ttoolbar: {\n *\t\t\titems: [ 'heading', 'bold', 'italic', 'link', ... ],\n *\t\t\t...\n *\t\t}\n *\n * * or may not be defined at all (`undefined`)\n *\n * and returns it in the object form.\n *\n * @param {Array|Object|undefined} config The value of `config.toolbar`.\n * @returns {Object} A normalized toolbar config object.\n */\nexport default function normalizeToolbarConfig( config ) {\n\tif ( Array.isArray( config ) ) {\n\t\treturn {\n\t\t\titems: config\n\t\t};\n\t}\n\n\tif ( !config ) {\n\t\treturn {\n\t\t\titems: []\n\t\t};\n\t}\n\n\treturn Object.assign( {\n\t\titems: []\n\t}, config );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/toolbar/enabletoolbarkeyboardfocus\n */\n\n/**\n * Enables focus/blur toolbar navigation using `Alt+F10` and `Esc` keystrokes.\n *\n * @param {Object} options Options of the utility.\n * @param {*} options.origin A view to which the focus will return when `Esc` is pressed and\n * `options.toolbar` is focused.\n * @param {module:utils/keystrokehandler~KeystrokeHandler} options.originKeystrokeHandler A keystroke\n * handler to register `Alt+F10` keystroke.\n * @param {module:utils/focustracker~FocusTracker} options.originFocusTracker A focus tracker\n * for `options.origin`.\n * @param {module:ui/toolbar/toolbarview~ToolbarView} options.toolbar A toolbar which is to gain\n * focus when `Alt+F10` is pressed.\n * @param {Function} [options.beforeFocus] A callback executed before the `options.toolbar` gains focus\n * upon the `Alt+F10` keystroke.\n * @param {Function} [options.afterBlur] A callback executed after `options.toolbar` loses focus upon\n * `Esc` keystroke but before the focus goes back to `options.origin`.\n */\nexport default function enableToolbarKeyboardFocus( {\n\torigin,\n\toriginKeystrokeHandler,\n\toriginFocusTracker,\n\ttoolbar,\n\tbeforeFocus,\n\tafterBlur\n} ) {\n\t// Because toolbar items can get focus, the overall state of the toolbar must\n\t// also be tracked.\n\toriginFocusTracker.add( toolbar.element );\n\n\t// Focus the toolbar on the keystroke, if not already focused.\n\toriginKeystrokeHandler.set( 'Alt+F10', ( data, cancel ) => {\n\t\tif ( originFocusTracker.isFocused && !toolbar.focusTracker.isFocused ) {\n\t\t\tif ( beforeFocus ) {\n\t\t\t\tbeforeFocus();\n\t\t\t}\n\n\t\t\ttoolbar.focus();\n\n\t\t\tcancel();\n\t\t}\n\t} );\n\n\t// Blur the toolbar and bring the focus back to origin.\n\ttoolbar.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\tif ( toolbar.focusTracker.isFocused ) {\n\t\t\torigin.focus();\n\n\t\t\tif ( afterBlur ) {\n\t\t\t\tafterBlur();\n\t\t\t}\n\n\t\t\tcancel();\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/viewcollection\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\n\n/**\n * Collects {@link module:ui/view~View} instances.\n *\n *\t\tconst parentView = new ParentView( locale );\n *\t\tconst collection = new ViewCollection( locale );\n *\n *\t\tcollection.setParent( parentView.element );\n *\n *\t\tconst viewA = new ChildView( locale );\n *\t\tconst viewB = new ChildView( locale );\n *\n * View collection renders and manages view {@link module:ui/view~View#element elements}:\n *\n *\t\tcollection.add( viewA );\n *\t\tcollection.add( viewB );\n *\n *\t\tconsole.log( parentView.element.firsChild ); // -> viewA.element\n *\t\tconsole.log( parentView.element.lastChild ); // -> viewB.element\n *\n * It {@link module:ui/viewcollection~ViewCollection#delegate propagates} DOM events too:\n *\n *\t\t// Delegate #click and #keydown events from viewA and viewB to the parentView.\n *\t\tcollection.delegate( 'click' ).to( parentView );\n *\n *\t\tparentView.on( 'click', ( evt ) => {\n *\t\t\tconsole.log( `${ evt.source } has been clicked.` );\n *\t\t} );\n *\n *\t\t// This event will be delegated to the parentView.\n *\t\tviewB.fire( 'click' );\n *\n * **Note**: A view collection can be used directly in the {@link module:ui/template~TemplateDefinition definition}\n * of a {@link module:ui/template~Template template}.\n *\n * @extends module:utils/collection~Collection\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class ViewCollection extends Collection {\n\t/**\n\t * Creates a new instance of the {@link module:ui/viewcollection~ViewCollection}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The {@link module:core/editor/editor~Editor editor's locale} instance.\n\t */\n\tconstructor( locale ) {\n\t\tsuper( {\n\t\t\t// An #id Number attribute should be legal and not break the `ViewCollection` instance.\n\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/93\n\t\t\tidProperty: 'viewUid'\n\t\t} );\n\n\t\t// Handle {@link module:ui/view~View#element} in DOM when a new view is added to the collection.\n\t\tthis.on( 'add', ( evt, view, index ) => {\n\t\t\tif ( !view.isRendered ) {\n\t\t\t\tview.render();\n\t\t\t}\n\n\t\t\tif ( view.element && this._parentElement ) {\n\t\t\t\tthis._parentElement.insertBefore( view.element, this._parentElement.children[ index ] );\n\t\t\t}\n\t\t} );\n\n\t\t// Handle {@link module:ui/view~View#element} in DOM when a view is removed from the collection.\n\t\tthis.on( 'remove', ( evt, view ) => {\n\t\t\tif ( view.element && this._parentElement ) {\n\t\t\t\tview.element.remove();\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * The {@link module:core/editor/editor~Editor#locale editor's locale} instance.\n\t\t * See the view {@link module:ui/view~View#locale locale} property.\n\t\t *\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = locale;\n\n\t\t/**\n\t\t * A parent element within which child views are rendered and managed in DOM.\n\t\t *\n\t\t * @protected\n\t\t * @member {HTMLElement}\n\t\t */\n\t\tthis._parentElement = null;\n\t}\n\n\t/**\n\t * Destroys the view collection along with child views.\n\t * See the view {@link module:ui/view~View#destroy} method.\n\t */\n\tdestroy() {\n\t\tthis.map( view => view.destroy() );\n\t}\n\n\t/**\n\t * Sets the parent HTML element of this collection. When parent is set, {@link #add adding} and\n\t * {@link #remove removing} views in the collection synchronizes their\n\t * {@link module:ui/view~View#element elements} in the parent element.\n\t *\n\t * @param {HTMLElement} element A new parent element.\n\t */\n\tsetParent( elementOrDocFragment ) {\n\t\tthis._parentElement = elementOrDocFragment;\n\t}\n\n\t/**\n\t * Delegates selected events coming from within views in the collection to any\n\t * {@link module:utils/emittermixin~Emitter}.\n\t *\n\t * For the following views and collection:\n\t *\n\t *\t\tconst viewA = new View();\n\t *\t\tconst viewB = new View();\n\t *\t\tconst viewC = new View();\n\t *\n\t *\t\tconst views = parentView.createCollection();\n\t *\n\t *\t\tviews.delegate( 'eventX' ).to( viewB );\n\t *\t\tviews.delegate( 'eventX', 'eventY' ).to( viewC );\n\t *\n\t *\t\tviews.add( viewA );\n\t *\n\t * the `eventX` is delegated (fired by) `viewB` and `viewC` along with `customData`:\n\t *\n\t *\t\tviewA.fire( 'eventX', customData );\n\t *\n\t * and `eventY` is delegated (fired by) `viewC` along with `customData`:\n\t *\n\t *\t\tviewA.fire( 'eventY', customData );\n\t *\n\t * See {@link module:utils/emittermixin~Emitter#delegate}.\n\t *\n\t * @param {...String} events {@link module:ui/view~View} event names to be delegated to another\n\t * {@link module:utils/emittermixin~Emitter}.\n\t * @returns {Object}\n\t * @returns {Function} return.to A function which accepts the destination of\n\t * {@link module:utils/emittermixin~Emitter#delegate delegated} events.\n\t */\n\tdelegate( ...events ) {\n\t\tif ( !events.length || !isStringArray( events ) ) {\n\t\t\t/**\n\t\t\t * All event names must be strings.\n\t\t\t *\n\t\t\t * @error ui-viewcollection-delegate-wrong-events\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-viewcollection-delegate-wrong-events: All event names must be strings.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\t/**\n\t\t\t * Selects destination for {@link module:utils/emittermixin~Emitter#delegate} events.\n\t\t\t *\n\t\t\t * @memberOf module:ui/viewcollection~ViewCollection#delegate\n\t\t\t * @function module:ui/viewcollection~ViewCollection#delegate.to\n\t\t\t * @param {module:utils/emittermixin~Emitter} dest An `Emitter` instance which is\n\t\t\t * the destination for delegated events.\n\t\t\t */\n\t\t\tto: dest => {\n\t\t\t\t// Activate delegating on existing views in this collection.\n\t\t\t\tfor ( const view of this ) {\n\t\t\t\t\tfor ( const evtName of events ) {\n\t\t\t\t\t\tview.delegate( evtName ).to( dest );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Activate delegating on future views in this collection.\n\t\t\t\tthis.on( 'add', ( evt, view ) => {\n\t\t\t\t\tfor ( const evtName of events ) {\n\t\t\t\t\t\tview.delegate( evtName ).to( dest );\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\t// Deactivate delegating when view is removed from this collection.\n\t\t\t\tthis.on( 'remove', ( evt, view ) => {\n\t\t\t\t\tfor ( const evtName of events ) {\n\t\t\t\t\t\tview.stopDelegating( evtName, dest );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Removes a child view from the collection. If the {@link #setParent parent element} of the\n\t * collection has been set, the {@link module:ui/view~View#element element} of the view is also removed\n\t * in DOM, reflecting the order of the collection.\n\t *\n\t * See the {@link #add} method.\n\t *\n\t * @method #remove\n\t * @param {module:ui/view~View|Number|String} subject The view to remove, its id or index in the collection.\n\t * @returns {Object} The removed view.\n\t */\n}\n\n// Check if all entries of the array are of `String` type.\n//\n// @private\n// @param {Array} arr An array to be checked.\n// @returns {Boolean}\nfunction isStringArray( arr ) {\n\treturn arr.every( a => typeof a == 'string' );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/template\n */\n\n/* global document */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport View from './view';\nimport ViewCollection from './viewcollection';\nimport isNode from '@ckeditor/ckeditor5-utils/src/dom/isnode';\nimport { isObject, cloneDeepWith } from 'lodash-es';\n\nconst xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n/**\n * A basic Template class. It renders a DOM HTML element or text from a\n * {@link module:ui/template~TemplateDefinition definition} and supports element attributes, children,\n * bindings to {@link module:utils/observablemixin~Observable observables} and DOM event propagation.\n *\n * A simple template can look like this:\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tattributes: {\n *\t\t\t\tclass: 'foo',\n *\t\t\t\tstyle: {\n *\t\t\t\t\tbackgroundColor: 'yellow'\n *\t\t\t\t}\n *\t\t\t},\n *\t\t\ton: {\n *\t\t\t\tclick: bind.to( 'clicked' )\n *\t\t\t},\n *\t\t\tchildren: [\n *\t\t\t\t'A paragraph.'\n *\t\t\t]\n *\t\t} ).render();\n *\n * and it will render the following HTML element:\n *\n *\t\t<p class=\"foo\" style=\"background-color: yellow;\">A paragraph.</p>\n *\n * Additionally, the `observable` will always fire `clicked` upon clicking `<p>` in the DOM.\n *\n * See {@link module:ui/template~TemplateDefinition} to know more about templates and complex\n * template definitions.\n *\n* @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Template {\n\t/**\n\t * Creates an instance of the {@link ~Template} class.\n\t *\n\t * @param {module:ui/template~TemplateDefinition} def The definition of the template.\n\t */\n\tconstructor( def ) {\n\t\tObject.assign( this, normalize( clone( def ) ) );\n\n\t\t/**\n\t\t * Indicates whether this particular Template instance has been\n\t\t * {@link #render rendered}.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._isRendered = false;\n\n\t\t/**\n\t\t * The tag (`tagName`) of this template, e.g. `div`. It also indicates that the template\n\t\t * renders to an HTML element.\n\t\t *\n\t\t * @member {String} #tag\n\t\t */\n\n\t\t/**\n\t\t * The text of the template. It also indicates that the template renders to a DOM text node.\n\t\t *\n\t\t * @member {Array.<String|module:ui/template~TemplateValueSchema>} #text\n\t\t */\n\n\t\t/**\n\t\t * The attributes of the template, e.g. `{ id: [ 'ck-id' ] }`, corresponding with\n\t\t * the attributes of an HTML element.\n\t\t *\n\t\t * **Note**: This property only makes sense when {@link #tag} is defined.\n\t\t *\n\t\t * @member {Object} #attributes\n\t\t */\n\n\t\t/**\n\t\t * The children of the template. They can be either:\n\t\t * * independent instances of {@link ~Template} (sub–templates),\n\t\t * * native DOM Nodes.\n\t\t *\n\t\t * **Note**: This property only makes sense when {@link #tag} is defined.\n\t\t *\n\t\t * @member {Array.<module:ui/template~Template|Node>} #children\n\t\t */\n\n\t\t/**\n\t\t * The DOM event listeners of the template.\n\t\t *\n\t\t * @member {Object} #eventListeners\n\t\t */\n\n\t\t/**\n\t\t * The data used by the {@link #revert} method to restore a node to its original state.\n\t\t *\n\t\t * See: {@link #apply}.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/template~RenderData}\n\t\t */\n\t\tthis._revertData = null;\n\t}\n\n\t/**\n\t * Renders a DOM Node (an HTML element or text) out of the template.\n\t *\n\t *\t\tconst domNode = new Template( { ... } ).render();\n\t *\n\t * See: {@link #apply}.\n\t *\n\t * @returns {HTMLElement|Text}\n\t */\n\trender() {\n\t\tconst node = this._renderNode( {\n\t\t\tintoFragment: true\n\t\t} );\n\n\t\tthis._isRendered = true;\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Applies the template to an existing DOM Node, either HTML element or text.\n\t *\n\t * **Note:** No new DOM nodes will be created. Applying extends:\n\t *\n\t * {@link module:ui/template~TemplateDefinition attributes},\n\t * {@link module:ui/template~TemplateDefinition event listeners}, and\n\t * `textContent` of {@link module:ui/template~TemplateDefinition children} only.\n\t *\n\t * **Note:** Existing `class` and `style` attributes are extended when a template\n\t * is applied to an HTML element, while other attributes and `textContent` are overridden.\n\t *\n\t * **Note:** The process of applying a template can be easily reverted using the\n\t * {@link module:ui/template~Template#revert} method.\n\t *\n\t *\t\tconst element = document.createElement( 'div' );\n\t *\t\tconst observable = new Model( { divClass: 'my-div' } );\n\t *\t\tconst emitter = Object.create( EmitterMixin );\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tid: 'first-div',\n\t *\t\t\t\tclass: bind.to( 'divClass' )\n\t *\t\t\t},\n\t *\t\t\ton: {\n\t *\t\t\t\tclick: bind( 'elementClicked' ) // Will be fired by the observable.\n\t *\t\t\t},\n\t *\t\t\tchildren: [\n\t *\t\t\t\t'Div text.'\n\t *\t\t\t]\n\t *\t\t} ).apply( element );\n\t *\n\t *\t\tconsole.log( element.outerHTML ); // -> '<div id=\"first-div\" class=\"my-div\"></div>'\n\t *\n\t * @see module:ui/template~Template#render\n\t * @see module:ui/template~Template#revert\n\t * @param {Node} node Root node for the template to apply.\n\t */\n\tapply( node ) {\n\t\tthis._revertData = getEmptyRevertData();\n\n\t\tthis._renderNode( {\n\t\t\tnode,\n\t\t\tisApplying: true,\n\t\t\trevertData: this._revertData\n\t\t} );\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Reverts a template {@link module:ui/template~Template#apply applied} to a DOM node.\n\t *\n\t * @param {Node} node The root node for the template to revert. In most of the cases, it is the\n\t * same node used by {@link module:ui/template~Template#apply}.\n\t */\n\trevert( node ) {\n\t\tif ( !this._revertData ) {\n\t\t\t/**\n\t\t\t * Attempting to revert a template which has not been applied yet.\n\t\t\t *\n\t\t\t * @error ui-template-revert-not-applied\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-template-revert-not-applied: Attempting to revert a template which has not been applied yet.',\n\t\t\t\t[ this, node ]\n\t\t\t);\n\t\t}\n\n\t\tthis._revertTemplateFromNode( node, this._revertData );\n\t}\n\n\t/**\n\t * Returns an iterator which traverses the template in search of {@link module:ui/view~View}\n\t * instances and returns them one by one.\n\t *\n\t *\t\tconst viewFoo = new View();\n\t *\t\tconst viewBar = new View();\n\t *\t\tconst viewBaz = new View();\n\t *\t\tconst template = new Template( {\n\t *\t\t\ttag: 'div',\n\t *\t\t\tchildren: [\n\t *\t\t\t\tviewFoo,\n\t *\t\t\t\t{\n\t *\t\t\t\t\ttag: 'div',\n\t *\t\t\t\t\tchildren: [\n\t *\t\t\t\t\t\tviewBar\n\t *\t\t\t\t\t]\n\t *\t\t\t\t},\n\t *\t\t\t\tviewBaz\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// Logs: viewFoo, viewBar, viewBaz\n\t *\t\tfor ( const view of template.getViews() ) {\n\t *\t\t\tconsole.log( view );\n\t *\t\t}\n\t *\n\t * @returns {Iterable.<module:ui/view~View>}\n\t */\n\t* getViews() {\n\t\tfunction* search( def ) {\n\t\t\tif ( def.children ) {\n\t\t\t\tfor ( const child of def.children ) {\n\t\t\t\t\tif ( isView( child ) ) {\n\t\t\t\t\t\tyield child;\n\t\t\t\t\t} else if ( isTemplate( child ) ) {\n\t\t\t\t\t\tyield* search( child );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tyield* search( this );\n\t}\n\n\t/**\n\t * An entry point to the interface which binds DOM nodes to\n\t * {@link module:utils/observablemixin~Observable observables}.\n\t * There are two types of bindings:\n\t *\n\t * * HTML element attributes or text `textContent` synchronized with attributes of an\n\t * {@link module:utils/observablemixin~Observable}. Learn more about {@link module:ui/template~BindChain#to}\n\t * and {@link module:ui/template~BindChain#if}.\n\t *\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\tattributes: {\n\t *\t\t\t\t// Binds the element \"class\" attribute to observable#classAttribute.\n\t *\t\t\t\tclass: bind.to( 'classAttribute' )\n\t *\t\t\t}\n\t *\t\t} ).render();\n\t *\n\t * * DOM events fired on HTML element propagated through\n\t * {@link module:utils/observablemixin~Observable}. Learn more about {@link module:ui/template~BindChain#to}.\n\t *\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\ton: {\n\t *\t\t\t\t// Will be fired by the observable.\n\t *\t\t\t\tclick: bind( 'elementClicked' )\n\t *\t\t\t}\n\t *\t\t} ).render();\n\t *\n\t * Also see {@link module:ui/view~View#bindTemplate}.\n\t *\n\t * @param {module:utils/observablemixin~Observable} observable An observable which provides boundable attributes.\n\t * @param {module:utils/emittermixin~Emitter} emitter An emitter that listens to observable attribute\n\t * changes or DOM Events (depending on the kind of the binding). Usually, a {@link module:ui/view~View} instance.\n\t * @returns {module:ui/template~BindChain}\n\t */\n\tstatic bind( observable, emitter ) {\n\t\treturn {\n\t\t\tto( eventNameOrFunctionOrAttribute, callback ) {\n\t\t\t\treturn new TemplateToBinding( {\n\t\t\t\t\teventNameOrFunction: eventNameOrFunctionOrAttribute,\n\t\t\t\t\tattribute: eventNameOrFunctionOrAttribute,\n\t\t\t\t\tobservable, emitter, callback\n\t\t\t\t} );\n\t\t\t},\n\n\t\t\tif( attribute, valueIfTrue, callback ) {\n\t\t\t\treturn new TemplateIfBinding( {\n\t\t\t\t\tobservable, emitter, attribute, valueIfTrue, callback\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Extends an existing {@link module:ui/template~Template} instance with some additional content\n\t * from another {@link module:ui/template~TemplateDefinition}.\n\t *\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tconst template = new Template( {\n\t *\t\t\ttag: 'p',\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: 'a',\n\t *\t\t\t\tdata-x: bind.to( 'foo' )\n\t *\t\t\t},\n\t *\t\t\tchildren: [\n\t *\t\t\t\t{\n\t *\t\t\t\t\ttag: 'span',\n\t *\t\t\t\t\tattributes: {\n\t *\t\t\t\t\t\tclass: 'b'\n\t *\t\t\t\t\t},\n\t *\t\t\t\t\tchildren: [\n\t *\t\t\t\t\t\t'Span'\n\t *\t\t\t\t\t]\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t } );\n\t *\n\t *\t\t// Instance-level extension.\n\t *\t\tTemplate.extend( template, {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: 'b',\n\t *\t\t\t\tdata-x: bind.to( 'bar' )\n\t *\t\t\t},\n\t *\t\t\tchildren: [\n\t *\t\t\t\t{\n\t *\t\t\t\t\tattributes: {\n\t *\t\t\t\t\t\tclass: 'c'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// Child extension.\n\t *\t\tTemplate.extend( template.children[ 0 ], {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: 'd'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * the `outerHTML` of `template.render()` is:\n\t *\n\t *\t\t<p class=\"a b\" data-x=\"{ observable.foo } { observable.bar }\">\n\t *\t\t\t<span class=\"b c d\">Span</span>\n\t *\t\t</p>\n\t *\n\t * @param {module:ui/template~Template} template An existing template instance to be extended.\n\t * @param {module:ui/template~TemplateDefinition} def Additional definition to be applied to a template.\n\t */\n\tstatic extend( template, def ) {\n\t\tif ( template._isRendered ) {\n\t\t\t/**\n\t\t\t * Extending a template after rendering may not work as expected. To make sure\n\t\t\t * the {@link module:ui/template~Template.extend extending} works for an element,\n\t\t\t * make sure it happens before {@link #render} is called.\n\t\t\t *\n\t\t\t * @error template-extend-render\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'template-extend-render: Attempting to extend a template which has already been rendered.',\n\t\t\t\t[ this, template ]\n\t\t\t);\n\t\t}\n\n\t\textendTemplate( template, normalize( clone( def ) ) );\n\t}\n\n\t/**\n\t * Renders a DOM Node (either an HTML element or text) out of the template.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderNode( data ) {\n\t\tlet isInvalid;\n\n\t\tif ( data.node ) {\n\t\t\t// When applying, a definition cannot have \"tag\" and \"text\" at the same time.\n\t\t\tisInvalid = this.tag && this.text;\n\t\t} else {\n\t\t\t// When rendering, a definition must have either \"tag\" or \"text\": XOR( this.tag, this.text ).\n\t\t\tisInvalid = this.tag ? this.text : !this.text;\n\t\t}\n\n\t\tif ( isInvalid ) {\n\t\t\t/**\n\t\t\t * Node definition cannot have the \"tag\" and \"text\" properties at the same time.\n\t\t\t * Node definition must have either \"tag\" or \"text\" when rendering a new Node.\n\t\t\t *\n\t\t\t * @error ui-template-wrong-syntax\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-template-wrong-syntax: Node definition must have either \"tag\" or \"text\" when rendering a new Node.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tif ( this.text ) {\n\t\t\treturn this._renderText( data );\n\t\t} else {\n\t\t\treturn this._renderElement( data );\n\t\t}\n\t}\n\n\t/**\n\t * Renders an HTML element out of the template.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderElement( data ) {\n\t\tlet node = data.node;\n\n\t\tif ( !node ) {\n\t\t\tnode = data.node = document.createElementNS( this.ns || xhtmlNs, this.tag );\n\t\t}\n\n\t\tthis._renderAttributes( data );\n\t\tthis._renderElementChildren( data );\n\t\tthis._setUpListeners( data );\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Renders a text node out of {@link module:ui/template~Template#text}.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderText( data ) {\n\t\tlet node = data.node;\n\n\t\t// Save the original textContent to revert it in #revert().\n\t\tif ( node ) {\n\t\t\tdata.revertData.text = node.textContent;\n\t\t} else {\n\t\t\tnode = data.node = document.createTextNode( '' );\n\t\t}\n\n\t\t// Check if this Text Node is bound to Observable. Cases:\n\t\t//\n\t\t//\t\ttext: [ Template.bind( ... ).to( ... ) ]\n\t\t//\n\t\t//\t\ttext: [\n\t\t//\t\t\t'foo',\n\t\t//\t\t\tTemplate.bind( ... ).to( ... ),\n\t\t//\t\t\t...\n\t\t//\t\t]\n\t\t//\n\t\tif ( hasTemplateBinding( this.text ) ) {\n\t\t\tthis._bindToObservable( {\n\t\t\t\tschema: this.text,\n\t\t\t\tupdater: getTextUpdater( node ),\n\t\t\t\tdata\n\t\t\t} );\n\t\t}\n\t\t// Simply set text. Cases:\n\t\t//\n\t\t//\t\ttext: [ 'all', 'are', 'static' ]\n\t\t//\n\t\t//\t\ttext: [ 'foo' ]\n\t\t//\n\t\telse {\n\t\t\tnode.textContent = this.text.join( '' );\n\t\t}\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Renders HTML element attributes out of {@link module:ui/template~Template#attributes}.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderAttributes( data ) {\n\t\tlet attrName, attrValue, domAttrValue, attrNs;\n\n\t\tif ( !this.attributes ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst node = data.node;\n\t\tconst revertData = data.revertData;\n\n\t\tfor ( attrName in this.attributes ) {\n\t\t\t// Current attribute value in DOM.\n\t\t\tdomAttrValue = node.getAttribute( attrName );\n\n\t\t\t// The value to be set.\n\t\t\tattrValue = this.attributes[ attrName ];\n\n\t\t\t// Save revert data.\n\t\t\tif ( revertData ) {\n\t\t\t\trevertData.attributes[ attrName ] = domAttrValue;\n\t\t\t}\n\n\t\t\t// Detect custom namespace:\n\t\t\t//\n\t\t\t//\t\tclass: {\n\t\t\t//\t\t\tns: 'abc',\n\t\t\t//\t\t\tvalue: Template.bind( ... ).to( ... )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\tattrNs = ( isObject( attrValue[ 0 ] ) && attrValue[ 0 ].ns ) ? attrValue[ 0 ].ns : null;\n\n\t\t\t// Activate binding if one is found. Cases:\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\tTemplate.bind( ... ).to( ... )\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\t'bar',\n\t\t\t//\t\t\tTemplate.bind( ... ).to( ... ),\n\t\t\t//\t\t\t'baz'\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\t//\t\tclass: {\n\t\t\t//\t\t\tns: 'abc',\n\t\t\t//\t\t\tvalue: Template.bind( ... ).to( ... )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\tif ( hasTemplateBinding( attrValue ) ) {\n\t\t\t\t// Normalize attributes with additional data like namespace:\n\t\t\t\t//\n\t\t\t\t//\t\tclass: {\n\t\t\t\t//\t\t\tns: 'abc',\n\t\t\t\t//\t\t\tvalue: [ ... ]\n\t\t\t\t//\t\t}\n\t\t\t\t//\n\t\t\t\tconst valueToBind = attrNs ? attrValue[ 0 ].value : attrValue;\n\n\t\t\t\t// Extend the original value of attributes like \"style\" and \"class\",\n\t\t\t\t// don't override them.\n\t\t\t\tif ( revertData && shouldExtend( attrName ) ) {\n\t\t\t\t\tvalueToBind.unshift( domAttrValue );\n\t\t\t\t}\n\n\t\t\t\tthis._bindToObservable( {\n\t\t\t\t\tschema: valueToBind,\n\t\t\t\t\tupdater: getAttributeUpdater( node, attrName, attrNs ),\n\t\t\t\t\tdata\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Style attribute could be an Object so it needs to be parsed in a specific way.\n\t\t\t//\n\t\t\t//\t\tstyle: {\n\t\t\t//\t\t\twidth: '100px',\n\t\t\t//\t\t\theight: Template.bind( ... ).to( ... )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\telse if ( attrName == 'style' && typeof attrValue[ 0 ] !== 'string' ) {\n\t\t\t\tthis._renderStyleAttribute( attrValue[ 0 ], data );\n\t\t\t}\n\n\t\t\t// Otherwise simply set the static attribute:\n\t\t\t//\n\t\t\t//\t\tclass: [ 'foo' ]\n\t\t\t//\n\t\t\t//\t\tclass: [ 'all', 'are', 'static' ]\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\t{\n\t\t\t//\t\t\t\tns: 'abc',\n\t\t\t//\t\t\t\tvalue: [ 'foo' ]\n\t\t\t//\t\t\t}\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\telse {\n\t\t\t\t// Extend the original value of attributes like \"style\" and \"class\",\n\t\t\t\t// don't override them.\n\t\t\t\tif ( revertData && domAttrValue && shouldExtend( attrName ) ) {\n\t\t\t\t\tattrValue.unshift( domAttrValue );\n\t\t\t\t}\n\n\t\t\t\tattrValue = attrValue\n\t\t\t\t\t// Retrieve \"values\" from:\n\t\t\t\t\t//\n\t\t\t\t\t//\t\tclass: [\n\t\t\t\t\t//\t\t\t{\n\t\t\t\t\t//\t\t\t\tns: 'abc',\n\t\t\t\t\t//\t\t\t\tvalue: [ ... ]\n\t\t\t\t\t//\t\t\t}\n\t\t\t\t\t//\t\t]\n\t\t\t\t\t//\n\t\t\t\t\t.map( val => val ? ( val.value || val ) : val )\n\t\t\t\t\t// Flatten the array.\n\t\t\t\t\t.reduce( ( prev, next ) => prev.concat( next ), [] )\n\t\t\t\t\t// Convert into string.\n\t\t\t\t\t.reduce( arrayValueReducer, '' );\n\n\t\t\t\tif ( !isFalsy( attrValue ) ) {\n\t\t\t\t\tnode.setAttributeNS( attrNs, attrName, attrValue );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Renders the `style` attribute of an HTML element based on\n\t * {@link module:ui/template~Template#attributes}.\n\t *\n\t * A style attribute is an {Object} with static values:\n\t *\n\t *\t\tattributes: {\n\t *\t\t\tstyle: {\n\t *\t\t\t\tcolor: 'red'\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * or values bound to {@link module:ui/model~Model} properties:\n\t *\n\t *\t\tattributes: {\n\t *\t\t\tstyle: {\n\t *\t\t\t\tcolor: bind.to( ... )\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * Note: The `style` attribute is rendered without setting the namespace. It does not seem to be\n\t * needed.\n\t *\n\t * @private\n\t * @param {Object} styles Styles located in `attributes.style` of {@link module:ui/template~TemplateDefinition}.\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderStyleAttribute( styles, data ) {\n\t\tconst node = data.node;\n\n\t\tfor ( const styleName in styles ) {\n\t\t\tconst styleValue = styles[ styleName ];\n\n\t\t\t// Cases:\n\t\t\t//\n\t\t\t//\t\tstyle: {\n\t\t\t//\t\t\tcolor: bind.to( 'attribute' )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\tif ( hasTemplateBinding( styleValue ) ) {\n\t\t\t\tthis._bindToObservable( {\n\t\t\t\t\tschema: [ styleValue ],\n\t\t\t\t\tupdater: getStyleUpdater( node, styleName ),\n\t\t\t\t\tdata\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Cases:\n\t\t\t//\n\t\t\t//\t\tstyle: {\n\t\t\t//\t\t\tcolor: 'red'\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\telse {\n\t\t\t\tnode.style[ styleName ] = styleValue;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Recursively renders HTML element's children from {@link module:ui/template~Template#children}.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderElementChildren( data ) {\n\t\tconst node = data.node;\n\t\tconst container = data.intoFragment ? document.createDocumentFragment() : node;\n\t\tconst isApplying = data.isApplying;\n\t\tlet childIndex = 0;\n\n\t\tfor ( const child of this.children ) {\n\t\t\tif ( isViewCollection( child ) ) {\n\t\t\t\tif ( !isApplying ) {\n\t\t\t\t\tchild.setParent( node );\n\n\t\t\t\t\t// Note: ViewCollection renders its children.\n\t\t\t\t\tfor ( const view of child ) {\n\t\t\t\t\t\tcontainer.appendChild( view.element );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if ( isView( child ) ) {\n\t\t\t\tif ( !isApplying ) {\n\t\t\t\t\tif ( !child.isRendered ) {\n\t\t\t\t\t\tchild.render();\n\t\t\t\t\t}\n\n\t\t\t\t\tcontainer.appendChild( child.element );\n\t\t\t\t}\n\t\t\t} else if ( isNode( child ) ) {\n\t\t\t\tcontainer.appendChild( child );\n\t\t\t} else {\n\t\t\t\tif ( isApplying ) {\n\t\t\t\t\tconst revertData = data.revertData;\n\t\t\t\t\tconst childRevertData = getEmptyRevertData();\n\n\t\t\t\t\trevertData.children.push( childRevertData );\n\n\t\t\t\t\tchild._renderNode( {\n\t\t\t\t\t\tnode: container.childNodes[ childIndex++ ],\n\t\t\t\t\t\tisApplying: true,\n\t\t\t\t\t\trevertData: childRevertData\n\t\t\t\t\t} );\n\t\t\t\t} else {\n\t\t\t\t\tcontainer.appendChild( child.render() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( data.intoFragment ) {\n\t\t\tnode.appendChild( container );\n\t\t}\n\t}\n\n\t/**\n\t * Activates `on` event listeners from the {@link module:ui/template~TemplateDefinition}\n\t * on an HTML element.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_setUpListeners( data ) {\n\t\tif ( !this.eventListeners ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const key in this.eventListeners ) {\n\t\t\tconst revertBindings = this.eventListeners[ key ].map( schemaItem => {\n\t\t\t\tconst [ domEvtName, domSelector ] = key.split( '@' );\n\n\t\t\t\treturn schemaItem.activateDomEventListener( domEvtName, domSelector, data );\n\t\t\t} );\n\n\t\t\tif ( data.revertData ) {\n\t\t\t\tdata.revertData.bindings.push( revertBindings );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * For a given {@link module:ui/template~TemplateValueSchema} containing {@link module:ui/template~TemplateBinding}\n\t * activates the binding and sets its initial value.\n\t *\n\t * Note: {@link module:ui/template~TemplateValueSchema} can be for HTML element attributes or\n\t * text node `textContent`.\n\t *\n\t * @protected\n\t * @param {Object} options Binding options.\n\t * @param {module:ui/template~TemplateValueSchema} options.schema\n\t * @param {Function} options.updater A function which updates the DOM (like attribute or text).\n\t * @param {module:ui/template~RenderData} options.data Rendering data.\n\t */\n\t_bindToObservable( { schema, updater, data } ) {\n\t\tconst revertData = data.revertData;\n\n\t\t// Set initial values.\n\t\tsyncValueSchemaValue( schema, updater, data );\n\n\t\tconst revertBindings = schema\n\t\t\t// Filter \"falsy\" (false, undefined, null, '') value schema components out.\n\t\t\t.filter( item => !isFalsy( item ) )\n\t\t\t// Filter inactive bindings from schema, like static strings ('foo'), numbers (42), etc.\n\t\t\t.filter( item => item.observable )\n\t\t\t// Once only the actual binding are left, let the emitter listen to observable change:attribute event.\n\t\t\t// TODO: Reduce the number of listeners attached as many bindings may listen\n\t\t\t// to the same observable attribute.\n\t\t\t.map( templateBinding => templateBinding.activateAttributeListener( schema, updater, data ) );\n\n\t\tif ( revertData ) {\n\t\t\trevertData.bindings.push( revertBindings );\n\t\t}\n\t}\n\n\t/**\n\t * Reverts {@link module:ui/template~RenderData#revertData template data} from a node to\n\t * return it to the original state.\n\t *\n\t * @protected\n\t * @param {HTMLElement|Text} node A node to be reverted.\n\t * @param {Object} revertData An object that stores information about what changes have been made by\n\t * {@link #apply} to the node. See {@link module:ui/template~RenderData#revertData} for more information.\n\t */\n\t_revertTemplateFromNode( node, revertData ) {\n\t\tfor ( const binding of revertData.bindings ) {\n\t\t\t// Each binding may consist of several observable+observable#attribute.\n\t\t\t// like the following has 2:\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\t'x',\n\t\t\t//\t\t\tbind.to( 'foo' ),\n\t\t\t//\t\t\t'y',\n\t\t\t//\t\t\tbind.to( 'bar' )\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\tfor ( const revertBinding of binding ) {\n\t\t\t\trevertBinding();\n\t\t\t}\n\t\t}\n\n\t\tif ( revertData.text ) {\n\t\t\tnode.textContent = revertData.text;\n\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const attrName in revertData.attributes ) {\n\t\t\tconst attrValue = revertData.attributes[ attrName ];\n\n\t\t\t// When the attribute has **not** been set before #apply().\n\t\t\tif ( attrValue === null ) {\n\t\t\t\tnode.removeAttribute( attrName );\n\t\t\t} else {\n\t\t\t\tnode.setAttribute( attrName, attrValue );\n\t\t\t}\n\t\t}\n\n\t\tfor ( let i = 0; i < revertData.children.length; ++i ) {\n\t\t\tthis._revertTemplateFromNode( node.childNodes[ i ], revertData.children[ i ] );\n\t\t}\n\t}\n}\n\nmix( Template, EmitterMixin );\n\n/**\n * Describes a binding created by the {@link module:ui/template~Template.bind} interface.\n *\n * @protected\n */\nexport class TemplateBinding {\n\t/**\n\t * Creates an instance of the {@link module:ui/template~TemplateBinding} class.\n\t *\n\t * @param {module:ui/template~TemplateDefinition} def The definition of the binding.\n\t */\n\tconstructor( def ) {\n\t\tObject.assign( this, def );\n\n\t\t/**\n\t\t * An observable instance of the binding. It either:\n\t\t *\n\t\t * * provides the attribute with the value,\n\t\t * * or passes the event when a corresponding DOM event is fired.\n\t\t *\n\t\t * @member {module:utils/observablemixin~ObservableMixin} module:ui/template~TemplateBinding#observable\n\t\t */\n\n\t\t/**\n\t\t * An {@link module:utils/emittermixin~Emitter} used by the binding to:\n\t\t *\n\t\t * * listen to the attribute change in the {@link module:ui/template~TemplateBinding#observable},\n\t\t * * or listen to the event in the DOM.\n\t\t *\n\t\t * @member {module:utils/emittermixin~EmitterMixin} module:ui/template~TemplateBinding#emitter\n\t\t */\n\n\t\t/**\n\t\t * The name of the {@link module:ui/template~TemplateBinding#observable observed attribute}.\n\t\t *\n\t\t * @member {String} module:ui/template~TemplateBinding#attribute\n\t\t */\n\n\t\t/**\n\t\t * A custom function to process the value of the {@link module:ui/template~TemplateBinding#attribute}.\n\t\t *\n\t\t * @member {Function} [module:ui/template~TemplateBinding#callback]\n\t\t */\n\t}\n\n\t/**\n\t * Returns the value of the binding. It is the value of the {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable}. The value may be processed by the\n\t * {@link module:ui/template~TemplateBinding#callback}, if such has been passed to the binding.\n\t *\n\t * @param {Node} [node] A native DOM node, passed to the custom {@link module:ui/template~TemplateBinding#callback}.\n\t * @returns {*} The value of {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable}.\n\t */\n\tgetValue( node ) {\n\t\tconst value = this.observable[ this.attribute ];\n\n\t\treturn this.callback ? this.callback( value, node ) : value;\n\t}\n\n\t/**\n\t * Activates the listener which waits for changes of the {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable}, then updates the DOM with the aggregated\n\t * value of {@link module:ui/template~TemplateValueSchema}.\n\t *\n\t * @param {module:ui/template~TemplateValueSchema} schema A full schema to generate an attribute or text in the DOM.\n\t * @param {Function} updater A DOM updater function used to update the native DOM attribute or text.\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t * @returns {Function} A function to sever the listener binding.\n\t */\n\tactivateAttributeListener( schema, updater, data ) {\n\t\tconst callback = () => syncValueSchemaValue( schema, updater, data );\n\n\t\tthis.emitter.listenTo( this.observable, 'change:' + this.attribute, callback );\n\n\t\t// Allows revert of the listener.\n\t\treturn () => {\n\t\t\tthis.emitter.stopListening( this.observable, 'change:' + this.attribute, callback );\n\t\t};\n\t}\n}\n\n/**\n * Describes either:\n *\n * * a binding to an {@link module:utils/observablemixin~Observable},\n * * or a native DOM event binding.\n *\n * It is created by the {@link module:ui/template~BindChain#to} method.\n *\n * @protected\n */\nexport class TemplateToBinding extends TemplateBinding {\n\t/**\n\t * Activates the listener for the native DOM event, which when fired, is propagated by\n\t * the {@link module:ui/template~TemplateBinding#emitter}.\n\t *\n\t * @param {String} domEvtName The name of the native DOM event.\n\t * @param {String} domSelector The selector in the DOM to filter delegated events.\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t * @returns {Function} A function to sever the listener binding.\n\t */\n\tactivateDomEventListener( domEvtName, domSelector, data ) {\n\t\tconst callback = ( evt, domEvt ) => {\n\t\t\tif ( !domSelector || domEvt.target.matches( domSelector ) ) {\n\t\t\t\tif ( typeof this.eventNameOrFunction == 'function' ) {\n\t\t\t\t\tthis.eventNameOrFunction( domEvt );\n\t\t\t\t} else {\n\t\t\t\t\tthis.observable.fire( this.eventNameOrFunction, domEvt );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tthis.emitter.listenTo( data.node, domEvtName, callback );\n\n\t\t// Allows revert of the listener.\n\t\treturn () => {\n\t\t\tthis.emitter.stopListening( data.node, domEvtName, callback );\n\t\t};\n\t}\n}\n\n/**\n * Describes a binding to {@link module:utils/observablemixin~ObservableMixin} created by the {@link module:ui/template~BindChain#if}\n * method.\n *\n * @protected\n */\nexport class TemplateIfBinding extends TemplateBinding {\n\t/**\n\t * @inheritDoc\n\t */\n\tgetValue( node ) {\n\t\tconst value = super.getValue( node );\n\n\t\treturn isFalsy( value ) ? false : ( this.valueIfTrue || true );\n\t}\n\n\t/**\n\t * The value of the DOM attribute or text to be set if the {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable} is `true`.\n\t *\n\t * @member {String} [module:ui/template~TemplateIfBinding#valueIfTrue]\n\t */\n}\n\n// Checks whether given {@link module:ui/template~TemplateValueSchema} contains a\n// {@link module:ui/template~TemplateBinding}.\n//\n// @param {module:ui/template~TemplateValueSchema} schema\n// @returns {Boolean}\nfunction hasTemplateBinding( schema ) {\n\tif ( !schema ) {\n\t\treturn false;\n\t}\n\n\t// Normalize attributes with additional data like namespace:\n\t//\n\t//\t\tclass: {\n\t//\t\t\tns: 'abc',\n\t//\t\t\tvalue: [ ... ]\n\t//\t\t}\n\t//\n\tif ( schema.value ) {\n\t\tschema = schema.value;\n\t}\n\n\tif ( Array.isArray( schema ) ) {\n\t\treturn schema.some( hasTemplateBinding );\n\t} else if ( schema instanceof TemplateBinding ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// Assembles the value using {@link module:ui/template~TemplateValueSchema} and stores it in a form of\n// an Array. Each entry of the Array corresponds to one of {@link module:ui/template~TemplateValueSchema}\n// items.\n//\n// @param {module:ui/template~TemplateValueSchema} schema\n// @param {Node} node DOM Node updated when {@link module:utils/observablemixin~ObservableMixin} changes.\n// @returns {Array}\nfunction getValueSchemaValue( schema, node ) {\n\treturn schema.map( schemaItem => {\n\t\t// Process {@link module:ui/template~TemplateBinding} bindings.\n\t\tif ( schemaItem instanceof TemplateBinding ) {\n\t\t\treturn schemaItem.getValue( node );\n\t\t}\n\n\t\t// All static values like strings, numbers, and \"falsy\" values (false, null, undefined, '', etc.) just pass.\n\t\treturn schemaItem;\n\t} );\n}\n\n// A function executed each time the bound Observable attribute changes, which updates the DOM with a value\n// constructed from {@link module:ui/template~TemplateValueSchema}.\n//\n// @param {module:ui/template~TemplateValueSchema} schema\n// @param {Function} updater A function which updates the DOM (like attribute or text).\n// @param {Node} node DOM Node updated when {@link module:utils/observablemixin~ObservableMixin} changes.\nfunction syncValueSchemaValue( schema, updater, { node } ) {\n\tlet value = getValueSchemaValue( schema, node );\n\n\t// Check if schema is a single Template.bind.if, like:\n\t//\n\t//\t\tclass: Template.bind.if( 'foo' )\n\t//\n\tif ( schema.length == 1 && schema[ 0 ] instanceof TemplateIfBinding ) {\n\t\tvalue = value[ 0 ];\n\t} else {\n\t\tvalue = value.reduce( arrayValueReducer, '' );\n\t}\n\n\tif ( isFalsy( value ) ) {\n\t\tupdater.remove();\n\t} else {\n\t\tupdater.set( value );\n\t}\n}\n\n// Returns an object consisting of `set` and `remove` functions, which\n// can be used in the context of DOM Node to set or reset `textContent`.\n// @see module:ui/view~View#_bindToObservable\n//\n// @param {Node} node DOM Node to be modified.\n// @returns {Object}\nfunction getTextUpdater( node ) {\n\treturn {\n\t\tset( value ) {\n\t\t\tnode.textContent = value;\n\t\t},\n\n\t\tremove() {\n\t\t\tnode.textContent = '';\n\t\t}\n\t};\n}\n\n// Returns an object consisting of `set` and `remove` functions, which\n// can be used in the context of DOM Node to set or reset an attribute.\n// @see module:ui/view~View#_bindToObservable\n//\n// @param {Node} node DOM Node to be modified.\n// @param {String} attrName Name of the attribute to be modified.\n// @param {String} [ns=null] Namespace to use.\n// @returns {Object}\nfunction getAttributeUpdater( el, attrName, ns ) {\n\treturn {\n\t\tset( value ) {\n\t\t\tel.setAttributeNS( ns, attrName, value );\n\t\t},\n\n\t\tremove() {\n\t\t\tel.removeAttributeNS( ns, attrName );\n\t\t}\n\t};\n}\n\n// Returns an object consisting of `set` and `remove` functions, which\n// can be used in the context of CSSStyleDeclaration to set or remove a style.\n// @see module:ui/view~View#_bindToObservable\n//\n// @param {Node} node DOM Node to be modified.\n// @param {String} styleName Name of the style to be modified.\n// @returns {Object}\nfunction getStyleUpdater( el, styleName ) {\n\treturn {\n\t\tset( value ) {\n\t\t\tel.style[ styleName ] = value;\n\t\t},\n\n\t\tremove() {\n\t\t\tel.style[ styleName ] = null;\n\t\t}\n\t};\n}\n\n// Clones definition of the template.\n//\n// @param {module:ui/template~TemplateDefinition} def\n// @returns {module:ui/template~TemplateDefinition}\nfunction clone( def ) {\n\tconst clone = cloneDeepWith( def, value => {\n\t\t// Don't clone the `Template.bind`* bindings because of the references to Observable\n\t\t// and DomEmitterMixin instances inside, which would also be traversed and cloned by greedy\n\t\t// cloneDeepWith algorithm. There's no point in cloning Observable/DomEmitterMixins\n\t\t// along with the definition.\n\t\t//\n\t\t// Don't clone Template instances if provided as a child. They're simply #render()ed\n\t\t// and nothing should interfere.\n\t\t//\n\t\t// Also don't clone View instances if provided as a child of the Template. The template\n\t\t// instance will be extracted from the View during the normalization and there's no need\n\t\t// to clone it.\n\t\tif ( value && ( value instanceof TemplateBinding || isTemplate( value ) || isView( value ) || isViewCollection( value ) ) ) {\n\t\t\treturn value;\n\t\t}\n\t} );\n\n\treturn clone;\n}\n\n// Normalizes given {@link module:ui/template~TemplateDefinition}.\n//\n// See:\n// * {@link normalizeAttributes}\n// * {@link normalizeListeners}\n// * {@link normalizePlainTextDefinition}\n// * {@link normalizeTextDefinition}\n//\n// @param {module:ui/template~TemplateDefinition} def\n// @returns {module:ui/template~TemplateDefinition} Normalized definition.\nfunction normalize( def ) {\n\tif ( typeof def == 'string' ) {\n\t\tdef = normalizePlainTextDefinition( def );\n\t} else if ( def.text ) {\n\t\tnormalizeTextDefinition( def );\n\t}\n\n\tif ( def.on ) {\n\t\tdef.eventListeners = normalizeListeners( def.on );\n\n\t\t// Template mixes EmitterMixin, so delete #on to avoid collision.\n\t\tdelete def.on;\n\t}\n\n\tif ( !def.text ) {\n\t\tif ( def.attributes ) {\n\t\t\tnormalizeAttributes( def.attributes );\n\t\t}\n\n\t\tconst children = [];\n\n\t\tif ( def.children ) {\n\t\t\tif ( isViewCollection( def.children ) ) {\n\t\t\t\tchildren.push( def.children );\n\t\t\t} else {\n\t\t\t\tfor ( const child of def.children ) {\n\t\t\t\t\tif ( isTemplate( child ) || isView( child ) || isNode( child ) ) {\n\t\t\t\t\t\tchildren.push( child );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tchildren.push( new Template( child ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tdef.children = children;\n\t}\n\n\treturn def;\n}\n\n// Normalizes \"attributes\" section of {@link module:ui/template~TemplateDefinition}.\n//\n//\t\tattributes: {\n//\t\t\ta: 'bar',\n//\t\t\tb: {@link module:ui/template~TemplateBinding},\n//\t\t\tc: {\n//\t\t\t\tvalue: 'bar'\n//\t\t\t}\n//\t\t}\n//\n// becomes\n//\n//\t\tattributes: {\n//\t\t\ta: [ 'bar' ],\n//\t\t\tb: [ {@link module:ui/template~TemplateBinding} ],\n//\t\t\tc: {\n//\t\t\t\tvalue: [ 'bar' ]\n//\t\t\t}\n//\t\t}\n//\n// @param {Object} attributes\nfunction normalizeAttributes( attributes ) {\n\tfor ( const a in attributes ) {\n\t\tif ( attributes[ a ].value ) {\n\t\t\tattributes[ a ].value = [].concat( attributes[ a ].value );\n\t\t}\n\n\t\tarrayify( attributes, a );\n\t}\n}\n\n// Normalizes \"on\" section of {@link module:ui/template~TemplateDefinition}.\n//\n//\t\ton: {\n//\t\t\ta: 'bar',\n//\t\t\tb: {@link module:ui/template~TemplateBinding},\n//\t\t\tc: [ {@link module:ui/template~TemplateBinding}, () => { ... } ]\n//\t\t}\n//\n// becomes\n//\n//\t\ton: {\n//\t\t\ta: [ 'bar' ],\n//\t\t\tb: [ {@link module:ui/template~TemplateBinding} ],\n//\t\t\tc: [ {@link module:ui/template~TemplateBinding}, () => { ... } ]\n//\t\t}\n//\n// @param {Object} listeners\n// @returns {Object} Object containing normalized listeners.\nfunction normalizeListeners( listeners ) {\n\tfor ( const l in listeners ) {\n\t\tarrayify( listeners, l );\n\t}\n\n\treturn listeners;\n}\n\n// Normalizes \"string\" {@link module:ui/template~TemplateDefinition}.\n//\n//\t\t\"foo\"\n//\n// becomes\n//\n//\t\t{ text: [ 'foo' ] },\n//\n// @param {String} def\n// @returns {module:ui/template~TemplateDefinition} Normalized template definition.\nfunction normalizePlainTextDefinition( def ) {\n\treturn {\n\t\ttext: [ def ]\n\t};\n}\n\n// Normalizes text {@link module:ui/template~TemplateDefinition}.\n//\n//\t\tchildren: [\n//\t\t\t{ text: 'def' },\n//\t\t\t{ text: {@link module:ui/template~TemplateBinding} }\n//\t\t]\n//\n// becomes\n//\n//\t\tchildren: [\n//\t\t\t{ text: [ 'def' ] },\n//\t\t\t{ text: [ {@link module:ui/template~TemplateBinding} ] }\n//\t\t]\n//\n// @param {module:ui/template~TemplateDefinition} def\nfunction normalizeTextDefinition( def ) {\n\tif ( !Array.isArray( def.text ) ) {\n\t\tdef.text = [ def.text ];\n\t}\n}\n\n// Wraps an entry in Object in an Array, if not already one.\n//\n//\t\t{\n//\t\t\tx: 'y',\n//\t\t\ta: [ 'b' ]\n//\t\t}\n//\n// becomes\n//\n//\t\t{\n//\t\t\tx: [ 'y' ],\n//\t\t\ta: [ 'b' ]\n//\t\t}\n//\n// @param {Object} obj\n// @param {String} key\nfunction arrayify( obj, key ) {\n\tif ( !Array.isArray( obj[ key ] ) ) {\n\t\tobj[ key ] = [ obj[ key ] ];\n\t}\n}\n\n// A helper which concatenates the value avoiding unwanted\n// leading white spaces.\n//\n// @param {String} prev\n// @param {String} cur\n// @returns {String}\nfunction arrayValueReducer( prev, cur ) {\n\tif ( isFalsy( cur ) ) {\n\t\treturn prev;\n\t} else if ( isFalsy( prev ) ) {\n\t\treturn cur;\n\t} else {\n\t\treturn `${ prev } ${ cur }`;\n\t}\n}\n\n// Extends one object defined in the following format:\n//\n//\t\t{\n//\t\t\tkey1: [Array1],\n//\t\t\tkey2: [Array2],\n//\t\t\t...\n//\t\t\tkeyN: [ArrayN]\n//\t\t}\n//\n// with another object of the same data format.\n//\n// @param {Object} obj Base object.\n// @param {Object} ext Object extending base.\n// @returns {String}\nfunction extendObjectValueArray( obj, ext ) {\n\tfor ( const a in ext ) {\n\t\tif ( obj[ a ] ) {\n\t\t\tobj[ a ].push( ...ext[ a ] );\n\t\t} else {\n\t\t\tobj[ a ] = ext[ a ];\n\t\t}\n\t}\n}\n\n// A helper for {@link module:ui/template~Template#extend}. Recursively extends {@link module:ui/template~Template} instance\n// with content from {@link module:ui/template~TemplateDefinition}. See {@link module:ui/template~Template#extend} to learn more.\n//\n// @param {module:ui/template~Template} def A template instance to be extended.\n// @param {module:ui/template~TemplateDefinition} def A definition which is to extend the template instance.\n// @param {Object} Error context.\nfunction extendTemplate( template, def ) {\n\tif ( def.attributes ) {\n\t\tif ( !template.attributes ) {\n\t\t\ttemplate.attributes = {};\n\t\t}\n\n\t\textendObjectValueArray( template.attributes, def.attributes );\n\t}\n\n\tif ( def.eventListeners ) {\n\t\tif ( !template.eventListeners ) {\n\t\t\ttemplate.eventListeners = {};\n\t\t}\n\n\t\textendObjectValueArray( template.eventListeners, def.eventListeners );\n\t}\n\n\tif ( def.text ) {\n\t\ttemplate.text.push( ...def.text );\n\t}\n\n\tif ( def.children && def.children.length ) {\n\t\tif ( template.children.length != def.children.length ) {\n\t\t\t/**\n\t\t\t * The number of children in extended definition does not match.\n\t\t\t *\n\t\t\t * @error ui-template-extend-children-mismatch\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-template-extend-children-mismatch: The number of children in extended definition does not match.',\n\t\t\t\ttemplate\n\t\t\t);\n\t\t}\n\n\t\tlet childIndex = 0;\n\n\t\tfor ( const childDef of def.children ) {\n\t\t\textendTemplate( template.children[ childIndex++ ], childDef );\n\t\t}\n\t}\n}\n\n// Checks if value is \"falsy\".\n// Note: 0 (Number) is not \"falsy\" in this context.\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isFalsy( value ) {\n\treturn !value && value !== 0;\n}\n\n// Checks if the item is an instance of {@link module:ui/view~View}\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isView( item ) {\n\treturn item instanceof View;\n}\n\n// Checks if the item is an instance of {@link module:ui/template~Template}\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isTemplate( item ) {\n\treturn item instanceof Template;\n}\n\n// Checks if the item is an instance of {@link module:ui/viewcollection~ViewCollection}\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isViewCollection( item ) {\n\treturn item instanceof ViewCollection;\n}\n\n// Creates an empty skeleton for {@link module:ui/template~Template#revert}\n// data.\n//\n// @private\nfunction getEmptyRevertData() {\n\treturn {\n\t\tchildren: [],\n\t\tbindings: [],\n\t\tattributes: {}\n\t};\n}\n\n// Checks whether an attribute should be extended when\n// {@link module:ui/template~Template#apply} is called.\n//\n// @private\n// @param {String} attrName Attribute name to check.\nfunction shouldExtend( attrName ) {\n\treturn attrName == 'class' || attrName == 'style';\n}\n\n/**\n * A definition of the {@link module:ui/template~Template}. It describes what kind of\n * node a template will render (HTML element or text), attributes of an element, DOM event\n * listeners and children.\n *\n * Also see:\n * * {@link module:ui/template~TemplateValueSchema} to learn about HTML element attributes,\n * * {@link module:ui/template~TemplateListenerSchema} to learn about DOM event listeners.\n *\n * A sample definition on an HTML element can look like this:\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tchildren: [\n *\t\t\t\t{\n *\t\t\t\t\ttag: 'span',\n *\t\t\t\t\tattributes: { ... },\n *\t\t\t\t\tchildren: [ ... ],\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\ttext: 'static–text'\n *\t\t\t\t},\n *\t\t\t\t'also-static–text',\n *\t\t\t],\n *\t\t\tattributes: {\n *\t\t\t\tclass: {@link module:ui/template~TemplateValueSchema},\n *\t\t\t\tid: {@link module:ui/template~TemplateValueSchema},\n *\t\t\t\tstyle: {@link module:ui/template~TemplateValueSchema}\n *\n *\t\t\t\t// ...\n *\t\t\t},\n *\t\t\ton: {\n *\t\t\t\t'click': {@link module:ui/template~TemplateListenerSchema}\n *\n *\t\t\t\t// Document.querySelector format is also accepted.\n *\t\t\t\t'keyup@a.some-class': {@link module:ui/template~TemplateListenerSchema}\n *\n *\t\t\t\t// ...\n *\t\t\t}\n *\t\t} );\n *\n * A {@link module:ui/view~View}, another {@link module:ui/template~Template} or a native DOM node\n * can also become a child of a template. When a view is passed, its {@link module:ui/view~View#element} is used:\n *\n *\t\tconst view = new SomeView();\n *\t\tconst childTemplate = new Template( { ... } );\n *\t\tconst childNode = document.createElement( 'b' );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\n *\t\t\tchildren: [\n *\t\t\t\t// view#element will be added as a child of this <p>.\n *\t\t\t\tview,\n *\n * \t\t\t\t// The output of childTemplate.render() will be added here.\n *\t\t\t\tchildTemplate,\n *\n *\t\t\t\t// Native DOM nodes are included directly in the rendered output.\n *\t\t\t\tchildNode\n *\t\t\t]\n *\t\t} );\n *\n * An entire {@link module:ui/viewcollection~ViewCollection} can be used as a child in the definition:\n *\n *\t\tconst collection = new ViewCollection();\n *\t\tcollection.add( someView );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\n *\t\t\tchildren: collection\n *\t\t} );\n *\n * @typedef module:ui/template~TemplateDefinition\n * @type Object\n *\n * @property {String} tag See the template {@link module:ui/template~Template#tag} property.\n *\n * @property {Array.<module:ui/template~TemplateDefinition>} [children]\n * See the template {@link module:ui/template~Template#children} property.\n *\n * @property {Object.<String, module:ui/template~TemplateValueSchema>} [attributes]\n * See the template {@link module:ui/template~Template#attributes} property.\n *\n * @property {String|module:ui/template~TemplateValueSchema|Array.<String|module:ui/template~TemplateValueSchema>} [text]\n * See the template {@link module:ui/template~Template#text} property.\n *\n * @property {Object.<String, module:ui/template~TemplateListenerSchema>} [on]\n * See the template {@link module:ui/template~Template#eventListeners} property.\n */\n\n/**\n * Describes a value of an HTML element attribute or `textContent`. It allows combining multiple\n * data sources like static values and {@link module:utils/observablemixin~Observable} attributes.\n *\n * Also see:\n * * {@link module:ui/template~TemplateDefinition} to learn where to use it,\n * * {@link module:ui/template~Template.bind} to learn how to configure\n * {@link module:utils/observablemixin~Observable} attribute bindings,\n * * {@link module:ui/template~Template#render} to learn how to render a template,\n * * {@link module:ui/template~BindChain#to `to()`} and {@link module:ui/template~BindChain#if `if()`}\n * methods to learn more about bindings.\n *\n * Attribute values can be described in many different ways:\n *\n *\t\t// Bind helper will create bindings to attributes of the observable.\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tattributes: {\n *\t\t\t\t// A plain string schema.\n *\t\t\t\t'class': 'static-text',\n *\n *\t\t\t\t// An object schema, binds to the \"foo\" attribute of the\n *\t\t\t\t// observable and follows its value.\n *\t\t\t\t'class': bind.to( 'foo' ),\n *\n *\t\t\t\t// An array schema, combines the above.\n *\t\t\t\t'class': [\n *\t\t\t\t\t'static-text',\n *\t\t\t\t\tbind.to( 'bar', () => { ... } ),\n *\n * \t\t\t\t\t// Bindings can also be conditional.\n *\t\t\t\t\tbind.if( 'baz', 'class-when-baz-is-true' )\n *\t\t\t\t],\n *\n *\t\t\t\t// An array schema, with a custom namespace, e.g. useful for creating SVGs.\n *\t\t\t\t'class': {\n *\t\t\t\t\tns: 'http://ns.url',\n *\t\t\t\t\tvalue: [\n *\t\t\t\t\t\tbind.if( 'baz', 'value-when-true' ),\n *\t\t\t\t\t\t'static-text'\n *\t\t\t\t\t]\n *\t\t\t\t},\n *\n *\t\t\t\t// An object schema, specific for styles.\n *\t\t\t\tstyle: {\n *\t\t\t\t\tcolor: 'red',\n *\t\t\t\t\tbackgroundColor: bind.to( 'qux', () => { ... } )\n *\t\t\t\t}\n *\t\t\t}\n *\t\t} );\n *\n * Text nodes can also have complex values:\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\t// Will render a \"foo\" text node.\n *\t\tnew Template( {\n *\t\t\ttext: 'foo'\n *\t\t} );\n *\n *\t\t// Will render a \"static text: {observable.foo}\" text node.\n *\t\t// The text of the node will be updated as the \"foo\" attribute changes.\n *\t\tnew Template( {\n *\t\t\ttext: [\n *\t\t\t\t'static text: ',\n *\t\t\t\tbind.to( 'foo', () => { ... } )\n *\t\t\t]\n *\t\t} );\n *\n * @typedef module:ui/template~TemplateValueSchema\n * @type {Object|String|Array}\n */\n\n/**\n * Describes an event listener attached to an HTML element. Such listener can propagate DOM events\n * through an {@link module:utils/observablemixin~Observable} instance, execute custom callbacks\n * or both, if necessary.\n *\n * Also see:\n * * {@link module:ui/template~TemplateDefinition} to learn more about template definitions,\n * * {@link module:ui/template~BindChain#to `to()`} method to learn more about bindings.\n *\n * Check out different ways of attaching event listeners below:\n *\n *\t\t// Bind helper will propagate events through the observable.\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\ton: {\n *\t\t\t\t// An object schema. The observable will fire the \"clicked\" event upon DOM \"click\".\n *\t\t\t\tclick: bind.to( 'clicked' )\n *\n *\t\t\t\t// An object schema. It will work for \"click\" event on \"a.foo\" children only.\n *\t\t\t\t'click@a.foo': bind.to( 'clicked' )\n *\n *\t\t\t\t// An array schema, makes the observable propagate multiple events.\n *\t\t\t\tclick: [\n *\t\t\t\t\tbind.to( 'clicked' ),\n *\t\t\t\t\tbind.to( 'executed' )\n *\t\t\t\t],\n *\n *\t\t\t\t// An array schema with a custom callback.\n *\t\t\t\t'click@a.foo': {\n *\t\t\t\t\tbind.to( 'clicked' ),\n *\t\t\t\t\tbind.to( evt => {\n *\t\t\t\t\t\tconsole.log( `${ evt.target } has been clicked!` );\n *\t\t\t\t\t} }\n *\t\t\t\t}\n *\t\t\t}\n *\t\t} );\n *\n * @typedef module:ui/template~TemplateListenerSchema\n * @type {Object|String|Array}\n */\n\n/**\n * The return value of {@link ~Template.bind `Template.bind()`}. It provides `to()` and `if()`\n * methods to create the {@link module:utils/observablemixin~Observable observable} attribute and event bindings.\n *\n * @interface module:ui/template~BindChain\n */\n\n/**\n * Binds an {@link module:utils/observablemixin~Observable observable} to either:\n *\n * * an HTML element attribute or a text node `textContent`, so it remains in sync with the observable\n * attribute as it changes,\n * * or an HTML element DOM event, so the DOM events are propagated through an observable.\n *\n * Some common use cases of `to()` bindings are presented below:\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tattributes: {\n *\t\t\t\t// class=\"...\" attribute gets bound to `observable#a`\n *\t\t\t\tclass: bind.to( 'a' )\n *\t\t\t},\n *\t\t\tchildren: [\n *\t\t\t\t// <p>...</p> gets bound to observable#b; always `toUpperCase()`.\n *\t\t\t\t{\n *\t\t\t\t\ttext: bind.to( 'b', ( value, node ) => value.toUpperCase() )\n *\t\t\t\t}\n *\t\t\t],\n *\t\t\ton: {\n *\t\t\t\tclick: [\n *\t\t\t\t\t// An observable will fire \"clicked\" upon \"click\" in the DOM.\n *\t\t\t\t\tbind.to( 'clicked' ),\n *\n *\t\t\t\t\t// A custom callback will be executed upon \"click\" in the DOM.\n *\t\t\t\t\tbind.to( () => {\n *\t\t\t\t\t\t...\n *\t\t\t\t\t} )\n *\t\t\t\t]\n *\t\t\t}\n *\t\t} ).render();\n *\n * Learn more about using `to()` in the {@link module:ui/template~TemplateValueSchema} and\n * {@link module:ui/template~TemplateListenerSchema}.\n *\n * @method #to\n * @param {String|Function} eventNameOrFunctionOrAttribute An attribute name of\n * {@link module:utils/observablemixin~Observable} or a DOM event name or an event callback.\n * @param {Function} [callback] Allows for processing of the value. Accepts `Node` and `value` as arguments.\n * @returns {module:ui/template~TemplateBinding}\n */\n\n/**\n * Binds an {@link module:utils/observablemixin~Observable observable} to an HTML element attribute or a text\n * node `textContent` so it remains in sync with the observable attribute as it changes.\n *\n * Unlike {@link module:ui/template~BindChain#to}, it controls the presence of the attribute or `textContent`\n * depending on the \"falseness\" of an {@link module:utils/observablemixin~Observable} attribute.\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'input',\n *\t\t\tattributes: {\n *\t\t\t\t// <input checked> when `observable#a` is not undefined/null/false/''\n *\t\t\t\t// <input> when `observable#a` is undefined/null/false\n *\t\t\t\tchecked: bind.if( 'a' )\n *\t\t\t},\n *\t\t\tchildren: [\n *\t\t\t\t{\n *\t\t\t\t\t// <input>\"b-is-not-set\"</input> when `observable#b` is undefined/null/false/''\n *\t\t\t\t\t// <input></input> when `observable#b` is not \"falsy\"\n *\t\t\t\t\ttext: bind.if( 'b', 'b-is-not-set', ( value, node ) => !value )\n *\t\t\t\t}\n *\t\t\t]\n *\t\t} ).render();\n *\n * Learn more about using `if()` in the {@link module:ui/template~TemplateValueSchema}.\n *\n * @method #if\n * @param {String} attribute An attribute name of {@link module:utils/observablemixin~Observable} used in the binding.\n * @param {String} [valueIfTrue] Value set when the {@link module:utils/observablemixin~Observable} attribute is not\n * undefined/null/false/'' (empty string).\n * @param {Function} [callback] Allows for processing of the value. Accepts `Node` and `value` as arguments.\n * @returns {module:ui/template~TemplateBinding}\n */\n\n/**\n * The {@link module:ui/template~Template#_renderNode} configuration.\n *\n * @private\n * @interface module:ui/template~RenderData\n */\n\n/**\n * Tells {@link module:ui/template~Template#_renderNode} to render\n * children into `DocumentFragment` first and then append the fragment\n * to the parent element. It is a speed optimization.\n *\n * @member {Boolean} #intoFragment\n */\n\n/**\n * A node which is being rendered.\n *\n * @member {HTMLElement|Text} #node\n */\n\n/**\n * Indicates whether the {@module:ui/template~RenderNodeOptions#node} has\n * been provided by {@module:ui/template~Template#apply}.\n *\n * @member {Boolean} #isApplying\n */\n\n/**\n * An object storing the data that helps {@module:ui/template~Template#revert}\n * bringing back an element to its initial state, i.e. before\n * {@module:ui/template~Template#apply} was called.\n *\n * @member {Object} #revertData\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/view\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport ViewCollection from './viewcollection';\nimport Template from './template';\nimport DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\nimport '../theme/globals/globals.css';\n\n/**\n * The basic view class, which represents an HTML element created out of a\n * {@link module:ui/view~View#template}. Views are building blocks of the user interface and handle\n * interaction\n *\n * Views {@link module:ui/view~View#registerChild aggregate} children in\n * {@link module:ui/view~View#createCollection collections} and manage the life cycle of DOM\n * listeners e.g. by handling rendering and destruction.\n *\n * See the {@link module:ui/template~TemplateDefinition} syntax to learn more about shaping view\n * elements, attributes and listeners.\n *\n *\t\tclass SampleView extends View {\n *\t\t\tconstructor( locale ) {\n *\t\t\t\tsuper( locale );\n *\n *\t\t\t\tconst bind = this.bindTemplate;\n *\n *\t\t\t\t// Views define their interface (state) using observable attributes.\n *\t\t\t\tthis.set( 'elementClass', 'bar' );\n *\n *\t\t\t\tthis.setTemplate( {\n *\t\t\t\t\ttag: 'p',\n *\n *\t\t\t\t\t// The element of the view can be defined with its children.\n *\t\t\t\t\tchildren: [\n *\t\t\t\t\t\t'Hello',\n *\t\t\t\t\t\t{\n *\t\t\t\t\t\t\ttag: 'b',\n *\t\t\t\t\t\t\tchildren: [ 'world!' ]\n *\t\t\t\t\t\t}\n *\t\t\t\t\t],\n *\t\t\t\t\tattributes: {\n *\t\t\t\t\t\tclass: [\n *\t\t\t\t\t\t\t'foo',\n *\n *\t\t\t\t\t\t\t// Observable attributes control the state of the view in DOM.\n *\t\t\t\t\t\t\tbind.to( 'elementClass' )\n *\t\t\t\t\t\t]\n *\t\t\t\t\t},\n *\t\t\t\t\ton: {\n *\t\t\t\t\t\t// Views listen to DOM events and propagate them.\n *\t\t\t\t\t\tclick: bind.to( 'clicked' )\n *\t\t\t\t\t}\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n *\n *\t\tconst view = new SampleView( locale );\n *\n *\t\tview.render();\n *\n *\t\t// Append <p class=\"foo bar\">Hello<b>world</b></p> to the <body>\n *\t\tdocument.body.appendChild( view.element );\n *\n *\t\t// Change the class attribute to <p class=\"foo baz\">Hello<b>world</b></p>\n *\t\tview.elementClass = 'baz';\n *\n *\t\t// Respond to the \"click\" event in DOM by executing a custom action.\n *\t\tview.on( 'clicked', () => {\n *\t\t\tconsole.log( 'The view has been clicked!' );\n *\t\t} );\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class View {\n\t/**\n\t * Creates an instance of the {@link module:ui/view~View} class.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t */\n\tconstructor( locale ) {\n\t\t/**\n\t\t * An HTML element of the view. `null` until {@link #render rendered}\n\t\t * from the {@link #template}.\n\t\t *\n\t\t *\t\tclass SampleView extends View {\n\t\t *\t\t\tconstructor() {\n\t\t *\t\t\t\tsuper();\n\t\t *\n\t\t *\t\t\t\t// A template instance the #element will be created from.\n\t\t *\t\t\t\tthis.setTemplate( {\n\t\t *\t\t\t\t\ttag: 'p'\n\t\t *\n\t\t *\t\t\t\t\t// ...\n\t\t *\t\t\t\t} );\n\t\t *\t\t\t}\n\t\t *\t\t}\n\t\t *\n\t\t *\t\tconst view = new SampleView();\n\t\t *\n\t\t *\t\t// Renders the #template.\n\t\t *\t\tview.render();\n\t\t *\n\t\t *\t\t// Append the HTML element of the view to <body>.\n\t\t *\t\tdocument.body.appendChild( view.element );\n\t\t *\n\t\t * **Note**: The element of the view can also be assigned directly:\n\t\t *\n\t\t *\t\tview.element = document.querySelector( '#my-container' );\n\t\t *\n\t\t * @member {HTMLElement}\n\t\t */\n\t\tthis.element = null;\n\n\t\t/**\n\t\t * Set `true` when the view has already been {@link module:ui/view~View#render rendered}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isRendered\n\t\t */\n\t\tthis.isRendered = false;\n\n\t\t/**\n\t\t * A set of tools to localize the user interface.\n\t\t *\n\t\t * Also see {@link module:core/editor/editor~Editor#locale}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = locale;\n\n\t\t/**\n\t\t * Shorthand for {@link module:utils/locale~Locale#t}.\n\t\t *\n\t\t * Note: If {@link #locale} instance hasn't been passed to the view this method may not\n\t\t * be available.\n\t\t *\n\t\t * @see module:utils/locale~Locale#t\n\t\t * @method\n\t\t */\n\t\tthis.t = locale && locale.t;\n\n\t\t/**\n\t\t * Collections registered with {@link #createCollection}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Set.<module:ui/viewcollection~ViewCollection>}\n\t\t */\n\t\tthis._viewCollections = new Collection();\n\n\t\t/**\n\t\t * A collection of view instances, which have been added directly\n\t\t * into the {@link module:ui/template~Template#children}.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._unboundChildren = this.createCollection();\n\n\t\t// Pass parent locale to its children.\n\t\tthis._viewCollections.on( 'add', ( evt, collection ) => {\n\t\t\tcollection.locale = locale;\n\t\t} );\n\n\t\t/**\n\t\t * Template of this view. It provides the {@link #element} representing\n\t\t * the view in DOM, which is {@link #render rendered}.\n\t\t *\n\t\t * @member {module:ui/template~Template} #template\n\t\t */\n\n\t\t/**\n\t\t * Cached {@link module:ui/template~BindChain bind chain} object created by the\n\t\t * {@link #template}. See {@link #bindTemplate}.\n\t\t *\n\t\t * @private\n\t\t * @member {Object} #_bindTemplate\n\t\t */\n\n\t\tthis.decorate( 'render' );\n\t}\n\n\t/**\n\t * Shorthand for {@link module:ui/template~Template.bind}, a binding\n\t * {@link module:ui/template~BindChain interface} pre–configured for the view instance.\n\t *\n\t * It provides {@link module:ui/template~BindChain#to `to()`} and\n\t * {@link module:ui/template~BindChain#if `if()`} methods that initialize bindings with\n\t * observable attributes and attach DOM listeners.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tconst bind = this.bindTemplate;\n\t *\n\t *\t\t\t\t// These {@link module:utils/observablemixin~Observable observable} attributes will control\n\t *\t\t\t\t// the state of the view in DOM.\n\t *\t\t\t\tthis.set( {\n\t *\t\t\t\t\telementClass: 'foo',\n\t *\t\t\t\t \tisEnabled: true\n\t *\t\t\t\t } );\n\t *\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\ttag: 'p',\n\t *\n\t *\t\t\t\t\tattributes: {\n\t *\t\t\t\t\t\t// The class HTML attribute will follow elementClass\n\t *\t\t\t\t\t\t// and isEnabled view attributes.\n\t *\t\t\t\t\t\tclass: [\n\t *\t\t\t\t\t\t\tbind.to( 'elementClass' )\n\t *\t\t\t\t\t\t\tbind.if( 'isEnabled', 'present-when-enabled' )\n\t *\t\t\t\t\t\t]\n\t *\t\t\t\t\t},\n\t *\n\t *\t\t\t\t\ton: {\n\t *\t\t\t\t\t\t// The view will fire the \"clicked\" event upon clicking <p> in DOM.\n\t *\t\t\t\t\t\tclick: bind.to( 'clicked' )\n\t *\t\t\t\t\t}\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * @method #bindTemplate\n\t */\n\tget bindTemplate() {\n\t\tif ( this._bindTemplate ) {\n\t\t\treturn this._bindTemplate;\n\t\t}\n\n\t\treturn ( this._bindTemplate = Template.bind( this, this ) );\n\t}\n\n\t/**\n\t * Creates a new collection of views, which can be used as\n\t * {@link module:ui/template~Template#children} of this view.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tthis.items = this.createCollection();\n \t *\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\ttag: 'p',\n\t *\n\t *\t\t\t\t\t// `items` collection will render here.\n\t *\t\t\t\t\tchildren: this.items\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst view = new SampleView( locale );\n\t *\t\tconst child = new ChildView( locale );\n\t *\n\t *\t\tview.render();\n\t *\n\t *\t\t// It will append <p></p> to the <body>.\n\t *\t\tdocument.body.appendChild( view.element );\n\t *\n\t *\t\t// From now on the child is nested under its parent, which is also reflected in DOM.\n\t *\t\t// <p><child#element></p>\n\t *\t\tview.items.add( child );\n\t *\n\t * @returns {module:ui/viewcollection~ViewCollection} A new collection of view instances.\n\t */\n\tcreateCollection() {\n\t\tconst collection = new ViewCollection();\n\n\t\tthis._viewCollections.add( collection );\n\n\t\treturn collection;\n\t}\n\n\t/**\n\t * Registers a new child view under the view instance. Once registered, a child\n\t * view is managed by its parent, including {@link #render rendering}\n\t * and {@link #destroy destruction}.\n\t *\n\t * To revert this, use {@link #deregisterChild}.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tthis.childA = new SomeChildView( locale );\n\t *\t\t\t\tthis.childB = new SomeChildView( locale );\n\t *\n\t *\t\t\t\tthis.setTemplate( { tag: 'p' } );\n\t *\n\t *\t\t\t\t// Register the children.\n\t *\t\t\t\tthis.registerChild( [ this.childA, this.childB ] );\n\t *\t\t\t}\n\t *\n\t *\t\t\trender() {\n\t *\t\t\t\tsuper.render();\n\t *\n\t *\t\t\t\tthis.element.appendChild( this.childA.element );\n\t *\t\t\t\tthis.element.appendChild( this.childB.element );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst view = new SampleView( locale );\n\t *\n\t *\t\tview.render();\n\t *\n\t *\t\t// Will append <p><childA#element><b></b><childB#element></p>.\n\t *\t\tdocument.body.appendChild( view.element );\n\t *\n\t * **Note**: There's no need to add child views if they're already referenced in the\n\t * {@link #template}:\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tthis.childA = new SomeChildView( locale );\n\t *\t\t\t\tthis.childB = new SomeChildView( locale );\n\t *\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\ttag: 'p',\n\t *\n \t *\t\t\t\t\t// These children will be added automatically. There's no\n \t *\t\t\t\t\t// need to call {@link #registerChild} for any of them.\n\t *\t\t\t\t\tchildren: [ this.childA, this.childB ]\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\n\t *\t\t\t// ...\n\t *\t\t}\n\t *\n\t * @param {module:ui/view~View|Iterable.<module:ui/view~View>} children Children views to be registered.\n\t */\n\tregisterChild( children ) {\n\t\tif ( !isIterable( children ) ) {\n\t\t\tchildren = [ children ];\n\t\t}\n\n\t\tfor ( const child of children ) {\n\t\t\tthis._unboundChildren.add( child );\n\t\t}\n\t}\n\n\t/**\n\t * The opposite of {@link #registerChild}. Removes a child view from this view instance.\n\t * Once removed, the child is no longer managed by its parent, e.g. it can safely\n\t * become a child of another parent view.\n\t *\n\t * @see #registerChild\n\t * @param {module:ui/view~View|Iterable.<module:ui/view~View>} children Child views to be removed.\n\t */\n\tderegisterChild( children ) {\n\t\tif ( !isIterable( children ) ) {\n\t\t\tchildren = [ children ];\n\t\t}\n\n\t\tfor ( const child of children ) {\n\t\t\tthis._unboundChildren.remove( child );\n\t\t}\n\t}\n\n\t/**\n\t * Sets the {@link #template} of the view with with given definition.\n\t *\n\t * A shorthand for:\n\t *\n\t *\t\tview.setTemplate( definition );\n\t *\n\t * @param {module:ui/template~TemplateDefinition} definition Definition of view's template.\n\t */\n\tsetTemplate( definition ) {\n\t\tthis.template = new Template( definition );\n\t}\n\n\t/**\n\t * {@link module:ui/template~Template.extend Extends} the {@link #template} of the view with\n\t * with given definition.\n\t *\n\t * A shorthand for:\n\t *\n\t *\t\tTemplate.extend( view.template, definition );\n\t *\n\t * **Note**: Is requires the {@link #template} to be already set. See {@link #setTemplate}.\n\t *\n\t * @param {module:ui/template~TemplateDefinition} definition Definition which\n\t * extends the {@link #template}.\n\t */\n\textendTemplate( definition ) {\n\t\tTemplate.extend( this.template, definition );\n\t}\n\n\t/**\n\t * Recursively renders the view.\n\t *\n\t * Once the view is rendered:\n\t * * the {@link #element} becomes an HTML element out of {@link #template},\n\t * * the {@link #isRendered} flag is set `true`.\n\t *\n\t * **Note**: The children of the view:\n\t * * defined directly in the {@link #template}\n\t * * residing in collections created by the {@link #createCollection} method,\n\t * * and added by {@link #registerChild}\n\t * are also rendered in the process.\n\t *\n\t * In general, `render()` method is the right place to keep the code which refers to the\n\t * {@link #element} and should be executed at the very beginning of the view's life cycle.\n\t *\n\t * It is possible to {@link module:ui/template~Template.extend} the {@link #template} before\n\t * the view is rendered. To allow an early customization of the view (e.g. by its parent),\n\t * such references should be done in `render()`.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor() {\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\t// ...\n\t *\t\t\t\t} );\n\t *\t\t\t},\n\t *\n\t *\t\t\trender() {\n\t *\t\t\t\t// View#element becomes available.\n\t *\t\t\t\tsuper.render();\n\t *\n\t *\t\t\t\t// The \"scroll\" listener depends on #element.\n\t *\t\t\t\tthis.listenTo( window, 'scroll', () => {\n\t *\t\t\t\t\t// A reference to #element would render the #template and make it non-extendable.\n\t *\t\t\t\t\tif ( window.scrollY > 0 ) {\n\t *\t\t\t\t\t\tthis.element.scrollLeft = 100;\n\t *\t\t\t\t\t} else {\n\t *\t\t\t\t\t\tthis.element.scrollLeft = 0;\n\t *\t\t\t\t\t}\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst view = new SampleView();\n\t *\n\t *\t\t// Let's customize the view before it gets rendered.\n\t *\t\tview.extendTemplate( {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: [\n\t *\t\t\t\t\t'additional-class'\n\t *\t\t\t\t]\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Late rendering allows customization of the view.\n\t *\t\tview.render();\n\t */\n\trender() {\n\t\tif ( this.isRendered ) {\n\t\t\t/**\n\t\t\t * This View has already been rendered.\n\t\t\t *\n\t\t\t * @error ui-view-render-rendered\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-view-render-already-rendered: This View has already been rendered.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\t// Render #element of the view.\n\t\tif ( this.template ) {\n\t\t\tthis.element = this.template.render();\n\n\t\t\t// Auto–register view children from #template.\n\t\t\tthis.registerChild( this.template.getViews() );\n\t\t}\n\n\t\tthis.isRendered = true;\n\t}\n\n\t/**\n\t * Recursively destroys the view instance and child views added by {@link #registerChild} and\n\t * residing in collections created by the {@link #createCollection}.\n\t *\n\t * Destruction disables all event listeners:\n\t * * created on the view, e.g. `view.on( 'event', () => {} )`,\n\t * * defined in the {@link #template} for DOM events.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\n\t\tthis._viewCollections.map( c => c.destroy() );\n\n\t\t// Template isn't obligatory for views.\n\t\tif ( this.template && this.template._revertData ) {\n\t\t\tthis.template.revert( this.element );\n\t\t}\n\t}\n\n\t/**\n\t * Event fired by the {@link #render} method. Actual rendering is executed as a listener to\n\t * this event with the default priority.\n\t *\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * @event render\n\t */\n}\n\nmix( View, DomEmitterMixin );\nmix( View, ObservableMixin );\n","import baseGetTag from './_baseGetTag.js';\nimport isArray from './isArray.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar stringTag = '[object String]';\n\n/**\n * Checks if `value` is classified as a `String` primitive or object.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a string, else `false`.\n * @example\n *\n * _.isString('abc');\n * // => true\n *\n * _.isString(1);\n * // => false\n */\nfunction isString(value) {\n return typeof value == 'string' ||\n (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);\n}\n\nexport default isString;\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/editorui/bodycollection\n */\n\n/* globals document */\n\nimport Template from '../template';\nimport ViewCollection from '../viewcollection';\n\nimport createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';\n\n/**\n * This is a special {@link module:ui/viewcollection~ViewCollection} dedicated to elements that are detached\n * from the DOM structure of the editor, like panels, icons, etc.\n *\n * The body collection is available in the {@link module:ui/editorui/editoruiview~EditorUIView#body `editor.ui.view.body`} property.\n * Any plugin can add a {@link module:ui/view~View view} to this collection.\n * These views will render in a container placed directly in the `<body>` element.\n * The editor will detach and destroy this collection when the editor will be {@link module:core/editor/editor~Editor#destroy destroyed}.\n *\n * If you need to control the life cycle of the body collection on your own, you can create your own instance of this class.\n *\n * A body collection will render itself automatically in the DOM body element as soon as you call {@link ~BodyCollection#attachToDom}.\n * If you create multiple body collections, this class will create a special wrapper element in the DOM to limit the number of\n * elements created directly in the body and remove it when the last body collection will be\n * {@link ~BodyCollection#detachFromDom detached}.\n *\n * @extends module:ui/viewcollection~ViewCollection\n */\nexport default class BodyCollection extends ViewCollection {\n\t/**\n\t * Attaches the body collection to the DOM body element. You need to execute this method to render the content of\n\t * the body collection.\n\t */\n\tattachToDom() {\n\t\t/**\n\t\t * The element holding elements of the body region.\n\t\t *\n\t\t * @protected\n\t\t * @member {HTMLElement} #_bodyCollectionContainer\n\t\t */\n\t\tthis._bodyCollectionContainer = new Template( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-reset_all',\n\t\t\t\t\t'ck-body',\n\t\t\t\t\t'ck-rounded-corners'\n\t\t\t\t],\n\t\t\t\tdir: this.locale.uiLanguageDirection,\n\t\t\t},\n\t\t\tchildren: this\n\t\t} ).render();\n\n\t\tlet wrapper = document.querySelector( '.ck-body-wrapper' );\n\n\t\tif ( !wrapper ) {\n\t\t\twrapper = createElement( document, 'div', { class: 'ck-body-wrapper' } );\n\t\t\tdocument.body.appendChild( wrapper );\n\t\t}\n\n\t\twrapper.appendChild( this._bodyCollectionContainer );\n\t}\n\n\t/**\n\t * Detaches the collection from the DOM structure. Use this method when you do not need to use the body collection\n\t * anymore to clean-up the DOM structure.\n\t */\n\tdetachFromDom() {\n\t\tsuper.destroy();\n\n\t\tif ( this._bodyCollectionContainer ) {\n\t\t\tthis._bodyCollectionContainer.remove();\n\t\t}\n\n\t\tconst wrapper = document.querySelector( '.ck-body-wrapper' );\n\n\t\tif ( wrapper && wrapper.childElementCount == 0 ) {\n\t\t\twrapper.remove();\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/createelement\n */\n\nimport isIterable from '../isiterable';\nimport { isString } from 'lodash-es';\n\n/**\n * Creates element with attributes and children.\n *\n *\t\tcreateElement( document, 'p' ); // <p>\n *\t\tcreateElement( document, 'p', { class: 'foo' } ); // <p class=\"foo\">\n *\t\tcreateElement( document, 'p', null, 'foo' ); // <p>foo</p>\n *\t\tcreateElement( document, 'p', null, [ 'foo', createElement( document, 'img' ) ] ); // <p>foo<img></p>\n *\n * @param {Document} doc Document used to create element.\n * @param {String} name Name of the element.\n * @param {Object} [attributes] Object keys will become attributes keys and object values will became attributes values.\n * @param {Node|String|Array.<Node|String>} [children] Child or array of children. Strings will be automatically turned\n * into Text nodes.\n * @returns {Element} Created element.\n */\nexport default function createElement( doc, name, attributes = {}, children = [] ) {\n\tconst namespace = attributes && attributes.xmlns;\n\tconst element = namespace ? doc.createElementNS( namespace, name ) : doc.createElement( name );\n\n\tfor ( const key in attributes ) {\n\t\telement.setAttribute( key, attributes[ key ] );\n\t}\n\n\tif ( isString( children ) || !isIterable( children ) ) {\n\t\tchildren = [ children ];\n\t}\n\n\tfor ( let child of children ) {\n\t\tif ( isString( child ) ) {\n\t\t\tchild = doc.createTextNode( child );\n\t\t}\n\n\t\telement.appendChild( child );\n\t}\n\n\treturn element;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/editorui/editoruiview\n */\n\nimport View from '../view';\nimport BodyCollection from './bodycollection';\n\nimport '../../theme/components/editorui/editorui.css';\n\n/**\n * The editor UI view class. Base class for the editor main views.\n *\n * @extends module:ui/view~View\n */\nexport default class EditorUIView extends View {\n\t/**\n\t * Creates an instance of the editor UI view class.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The locale instance.\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Collection of the child views, detached from the DOM\n\t\t * structure of the editor, like panels, icons etc.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection} #body\n\t\t */\n\t\tthis.body = new BodyCollection( locale );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.body.attachToDom();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis.body.detachFromDom();\n\n\t\treturn super.destroy();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/label/labelview\n */\n\nimport View from '../view';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\n\nimport '../../theme/components/label/label.css';\n\n/**\n * The label view class.\n *\n * @extends module:ui/view~View\n */\nexport default class LabelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The text of the label.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #text\n\t\t */\n\t\tthis.set( 'text' );\n\n\t\t/**\n\t\t * The `for` attribute of the label (i.e. to pair with an `<input>` element).\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #for\n\t\t */\n\t\tthis.set( 'for' );\n\n\t\t/**\n\t\t * An unique id of the label. It can be used by other UI components to reference\n\t\t * the label, for instance, using the `aria-describedby` DOM attribute.\n\t\t *\n\t\t * @member {String} #id\n\t\t */\n\t\tthis.id = `ck-editor__label_${ uid() }`;\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'label',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-label'\n\t\t\t\t],\n\t\t\t\tid: this.id,\n\t\t\t\tfor: bind.to( 'for' )\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: bind.to( 'text' )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module ui/editorui/boxed/boxededitoruiview\n */\nimport EditorUIView from '../../editorui/editoruiview';\nimport LabelView from '../../label/labelview';\n/**\n * The boxed editor UI view class. This class represents an editor interface\n * consisting of a toolbar and an editable area, enclosed within a box.\n *\n * @extends module:ui/editorui/editoruiview~EditorUIView\n */\nexport default class BoxedEditorUIView extends EditorUIView {\n /**\n\t * Creates an instance of the boxed editor UI view class.\n\t *\n\t * @param {module:utils/locale~Locale} locale The locale instance..\n\t */\n constructor(locale) {\n super(locale);\n /**\n\t\t * Collection of the child views located in the top (`.ck-editor__top`)\n\t\t * area of the UI.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this.top = this.createCollection();\n /**\n\t\t * Collection of the child views located in the main (`.ck-editor__main`)\n\t\t * area of the UI.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this.main = this.createCollection();\n /**\n\t\t * Voice label of the UI.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @member {module:ui/view~View} #_voiceLabelView\n\t\t */\n this._voiceLabelView = this._createVoiceLabel();\n this.setTemplate({\n tag: 'div',\n attributes: {\n class: [\n 'ck',\n 'ck-reset',\n 'ck-editor',\n 'ck-rounded-corners'\n ],\n role: 'application',\n dir: locale.uiLanguageDirection,\n lang: locale.uiLanguage,\n 'aria-labelledby': this._voiceLabelView.id\n },\n children: [\n this._voiceLabelView,\n {\n tag: 'div',\n attributes: {\n class: [\n 'ck',\n 'ck-editor__top',\n 'ck-reset_all'\n ],\n role: 'presentation'\n },\n children: this.top\n },\n {\n tag: 'div',\n attributes: {\n class: [\n 'ck',\n 'ck-editor__main'\n ],\n role: 'presentation'\n },\n children: this.main\n }\n ]\n });\n }\n /**\n\t * Creates a voice label view instance.\n\t *\n\t * @private\n\t * @returns {module:ui/label/labelview~LabelView}\n\t */\n _createVoiceLabel() {\n const t = this.t;\n const voiceLabel = new LabelView();\n voiceLabel.text = t('bn');\n voiceLabel.extendTemplate({ attributes: { class: 'ck-voice-label' } });\n return voiceLabel;\n }\n}","/**\n * @license Copyright (c) 2003-2020, 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 ui/editableui/editableuiview\n */\n\nimport View from '../view';\n\n/**\n * The editable UI view class.\n *\n * @extends module:ui/view~View\n */\nexport default class EditableUIView extends View {\n\t/**\n\t * Creates an instance of EditableUIView class.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The locale instance.\n\t * @param {module:engine/view/view~View} editingView The editing view instance the editable is related to.\n\t * @param {HTMLElement} [editableElement] The editable element. If not specified, this view\n\t * should create it. Otherwise, the existing element should be used.\n\t */\n\tconstructor( locale, editingView, editableElement ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-content',\n\t\t\t\t\t'ck-editor__editable',\n\t\t\t\t\t'ck-rounded-corners'\n\t\t\t\t],\n\t\t\t\tlang: locale.contentLanguage,\n\t\t\t\tdir: locale.contentLanguageDirection\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * The name of the editable UI view.\n\t\t *\n\t\t * @member {String} #name\n\t\t */\n\t\tthis.name = null;\n\n\t\t/**\n\t\t * Controls whether the editable is focused, i.e. the user is typing in it.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * The element which is the main editable element (usually the one with `contentEditable=\"true\"`).\n\t\t *\n\t\t * @private\n\t\t * @member {HTMLElement} #_editableElement\n\t\t */\n\t\tthis._editableElement = editableElement;\n\n\t\t/**\n\t\t * Whether an external {@link #_editableElement} was passed into the constructor, which also means\n\t\t * the view will not render its {@link #template}.\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean} #_hasExternalElement\n\t\t */\n\t\tthis._hasExternalElement = !!this._editableElement;\n\n\t\t/**\n\t\t * The editing view instance the editable is related to. Editable uses the editing\n\t\t * view to dynamically modify its certain DOM attributes after {@link #render rendering}.\n\t\t *\n\t\t * **Note**: The DOM attributes are performed by the editing view and not UI\n\t\t * {@link module:ui/view~View#bindTemplate template bindings} because once rendered,\n\t\t * the editable DOM element must remain under the full control of the engine to work properly.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:engine/view/view~View} #isFocused\n\t\t */\n\t\tthis._editingView = editingView;\n\t}\n\n\t/**\n\t * Renders the view by either applying the {@link #template} to the existing\n\t * {@link #_editableElement} or assigning {@link #element} as {@link #_editableElement}.\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tif ( this._hasExternalElement ) {\n\t\t\tthis.template.apply( this.element = this._editableElement );\n\t\t} else {\n\t\t\tthis._editableElement = this.element;\n\t\t}\n\n\t\tthis.on( 'change:isFocused', () => this._updateIsFocusedClasses() );\n\t\tthis._updateIsFocusedClasses();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tif ( this._hasExternalElement ) {\n\t\t\tthis.template.revert( this._editableElement );\n\t\t}\n\n\t\tsuper.destroy();\n\t}\n\n\t/**\n\t * Updates the `ck-focused` and `ck-blurred` CSS classes on the {@link #element} according to\n\t * the {@link #isFocused} property value using the {@link #_editingView editing view} API.\n\t *\n\t * @private\n\t */\n\t_updateIsFocusedClasses() {\n\t\tconst editingView = this._editingView;\n\n\t\tif ( editingView.isRenderingInProgress ) {\n\t\t\tupdateAfterRender( this );\n\t\t} else {\n\t\t\tupdate( this );\n\t\t}\n\n\t\tfunction update( view ) {\n\t\t\teditingView.change( writer => {\n\t\t\t\tconst viewRoot = editingView.document.getRoot( view.name );\n\n\t\t\t\twriter.addClass( view.isFocused ? 'ck-focused' : 'ck-blurred', viewRoot );\n\t\t\t\twriter.removeClass( view.isFocused ? 'ck-blurred' : 'ck-focused', viewRoot );\n\t\t\t} );\n\t\t}\n\n\t\t// In a case of a multi-root editor, a callback will be attached more than once (one callback for each root).\n\t\t// While executing one callback the `isRenderingInProgress` observable is changing what causes executing another\n\t\t// callback and render is called inside the already pending render.\n\t\t// We need to be sure that callback is executed only when the value has changed from `true` to `false`.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/1676.\n\t\tfunction updateAfterRender( view ) {\n\t\t\teditingView.once( 'change:isRenderingInProgress', ( evt, name, value ) => {\n\t\t\t\tif ( !value ) {\n\t\t\t\t\tupdate( view );\n\t\t\t\t} else {\n\t\t\t\t\tupdateAfterRender( view );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module ui/editableui/inline/inlineeditableuiview\n */\nimport EditableUIView from '../../editableui/editableuiview';\n/**\n * The inline editable UI class implementing an inline {@link module:ui/editableui/editableuiview~EditableUIView}.\n *\n * @extends module:ui/editableui/editableuiview~EditableUIView\n */\nexport default class InlineEditableUIView extends EditableUIView {\n /**\n\t * Creates an instance of the InlineEditableUIView class.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The locale instance.\n\t * @param {module:engine/view/view~View} editingView The editing view instance the editable is related to.\n\t * @param {HTMLElement} [editableElement] The editable element. If not specified, the\n\t * {@link module:ui/editableui/editableuiview~EditableUIView}\n\t * will create it. Otherwise, the existing element will be used.\n\t */\n constructor(locale, editingView, editableElement) {\n super(locale, editingView, editableElement);\n this.extendTemplate({\n attributes: {\n role: 'textbox',\n class: 'ck-editor__editable_inline'\n }\n });\n }\n /**\n\t * @inheritDoc\n\t */\n render() {\n super.render();\n const editingView = this._editingView;\n const t = this.t;\n editingView.change(writer => {\n const viewRoot = editingView.document.getRoot(this.name);\n writer.setAttribute('aria-label', t('bo', [this.name]), viewRoot);\n });\n }\n}","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/tounit\n */\n\n/**\n * Returns a helper function, which adds a desired trailing\n * `unit` to the passed value.\n *\n * @param {String} unit An unit like \"px\" or \"em\".\n * @returns {module:utils/dom/tounit~helper}\n */\nexport default function toUnit( unit ) {\n\t/**\n\t * A function, which adds a pre–defined trailing `unit`\n\t * to the passed `value`.\n\t *\n\t * @function helper\n \t * @param {*} value A value to be given the unit.\n \t * @returns {String} A value with the trailing unit.\n\t */\n\treturn value => value + unit;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/panel/sticky/stickypanelview\n */\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport View from '../../view';\nimport Template from '../../template';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\n\nimport '../../../theme/components/panel/stickypanel.css';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * The sticky panel view class.\n */\nexport default class StickyPanelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Controls whether the sticky panel should be active.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isActive\n\t\t */\n\t\tthis.set( 'isActive', false );\n\n\t\t/**\n\t\t * Controls whether the sticky panel is in the \"sticky\" state.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isSticky\n\t\t */\n\t\tthis.set( 'isSticky', false );\n\n\t\t/**\n\t\t * The limiter element for the sticky panel instance. Its bounding rect limits\n\t\t * the \"stickyness\" of the panel, i.e. when the panel reaches the bottom\n\t\t * edge of the limiter, it becomes sticky to that edge and does not float\n\t\t * off the limiter. It is mandatory for the panel to work properly and once\n\t\t * set, it cannot be changed.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {HTMLElement} #limiterElement\n\t\t */\n\t\tthis.set( 'limiterElement', null );\n\n\t\t/**\n\t\t * The offset from the bottom edge of {@link #limiterElement}\n\t\t * which stops the panel from stickying any further to prevent limiter's content\n\t\t * from being completely covered.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @default 50\n\t\t * @member {Number} #limiterBottomOffset\n\t\t */\n\t\tthis.set( 'limiterBottomOffset', 50 );\n\n\t\t/**\n\t\t * The offset from the top edge of the web browser's viewport which makes the\n\t\t * panel become sticky. The default value is `0`, which means the panel becomes\n\t\t * sticky when it's upper edge touches the top of the page viewport.\n\t\t *\n\t\t * This attribute is useful when the web page has UI elements positioned to the top\n\t\t * either using `position: fixed` or `position: sticky`, which would cover the\n\t\t * sticky panel or vice–versa (depending on the `z-index` hierarchy).\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @default 0\n\t\t * @member {Number} #viewportTopOffset\n\t\t */\n\t\tthis.set( 'viewportTopOffset', 0 );\n\n\t\t/**\n\t\t * Controls the `margin-left` CSS style of the panel.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {String} #_marginLeft\n\t\t */\n\t\tthis.set( '_marginLeft', null );\n\n\t\t/**\n\t\t * Set `true` if the sticky panel reached the bottom edge of the\n\t\t * {@link #limiterElement}.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #_isStickyToTheLimiter\n\t\t */\n\t\tthis.set( '_isStickyToTheLimiter', false );\n\n\t\t/**\n\t\t * Set `true` if the sticky panel uses the {@link #viewportTopOffset},\n\t\t * i.e. not {@link #_isStickyToTheLimiter} and the {@link #viewportTopOffset}\n\t\t * is not `0`.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #_hasViewportTopOffset\n\t\t */\n\t\tthis.set( '_hasViewportTopOffset', false );\n\n\t\t/**\n\t\t * Collection of the child views which creates balloon panel contents.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.content = this.createCollection();\n\n\t\t/**\n\t\t * The DOM bounding client rect of the {@link module:ui/view~View#element} of the panel.\n\t\t *\n\t\t * @protected\n\t\t * @member {Object} #_panelRect\n\t\t */\n\n\t\t/**\n\t\t * The DOM bounding client rect of the {@link #limiterElement}\n\t\t * of the panel.\n\t\t *\n\t\t * @protected\n\t\t * @member {Object} #_limiterRect\n\t\t */\n\n\t\t/**\n\t\t * A dummy element which visually fills the space as long as the\n\t\t * actual panel is sticky. It prevents flickering of the UI.\n\t\t *\n\t\t * @protected\n\t\t * @property {HTMLElement}\n\t\t */\n\t\tthis._contentPanelPlaceholder = new Template( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-sticky-panel__placeholder'\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\tdisplay: bind.to( 'isSticky', isSticky => isSticky ? 'block' : 'none' ),\n\t\t\t\t\theight: bind.to( 'isSticky', isSticky => {\n\t\t\t\t\t\treturn isSticky ? toPx( this._panelRect.height ) : null;\n\t\t\t\t\t} )\n\t\t\t\t}\n\t\t\t}\n\t\t} ).render();\n\n\t\t/**\n\t\t * The panel which accepts children into {@link #content} collection.\n\t\t * Also an element which is positioned when {@link #isSticky}.\n\t\t *\n\t\t * @protected\n\t\t * @property {HTMLElement}\n\t\t */\n\t\tthis._contentPanel = new Template( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-sticky-panel__content',\n\t\t\t\t\t// Toggle class of the panel when \"sticky\" state changes in the view.\n\t\t\t\t\tbind.if( 'isSticky', 'ck-sticky-panel__content_sticky' ),\n\t\t\t\t\tbind.if( '_isStickyToTheLimiter', 'ck-sticky-panel__content_sticky_bottom-limit' ),\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\twidth: bind.to( 'isSticky', isSticky => {\n\t\t\t\t\t\treturn isSticky ? toPx( this._contentPanelPlaceholder.getBoundingClientRect().width ) : null;\n\t\t\t\t\t} ),\n\n\t\t\t\t\ttop: bind.to( '_hasViewportTopOffset', _hasViewportTopOffset => {\n\t\t\t\t\t\treturn _hasViewportTopOffset ? toPx( this.viewportTopOffset ) : null;\n\t\t\t\t\t} ),\n\n\t\t\t\t\tbottom: bind.to( '_isStickyToTheLimiter', _isStickyToTheLimiter => {\n\t\t\t\t\t\treturn _isStickyToTheLimiter ? toPx( this.limiterBottomOffset ) : null;\n\t\t\t\t\t} ),\n\n\t\t\t\t\tmarginLeft: bind.to( '_marginLeft' )\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tchildren: this.content\n\t\t} ).render();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-sticky-panel'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\tthis._contentPanelPlaceholder,\n\t\t\t\tthis._contentPanel\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Check if the panel should go into the sticky state immediately.\n\t\tthis._checkIfShouldBeSticky();\n\n\t\t// Update sticky state of the panel as the window is being scrolled.\n\t\tthis.listenTo( global.window, 'scroll', () => {\n\t\t\tthis._checkIfShouldBeSticky();\n\t\t} );\n\n\t\t// Synchronize with `model.isActive` because sticking an inactive panel is pointless.\n\t\tthis.listenTo( this, 'change:isActive', () => {\n\t\t\tthis._checkIfShouldBeSticky();\n\t\t} );\n\t}\n\n\t/**\n\t * Analyzes the environment to decide whether the panel should\n\t * be sticky or not.\n\t *\n\t * @protected\n\t */\n\t_checkIfShouldBeSticky() {\n\t\tconst panelRect = this._panelRect = this._contentPanel.getBoundingClientRect();\n\t\tlet limiterRect;\n\n\t\tif ( !this.limiterElement ) {\n\t\t\tthis.isSticky = false;\n\t\t} else {\n\t\t\tlimiterRect = this._limiterRect = this.limiterElement.getBoundingClientRect();\n\n\t\t\t// The panel must be active to become sticky.\n\t\t\tthis.isSticky = this.isActive &&\n\t\t\t\t// The limiter's top edge must be beyond the upper edge of the visible viewport (+the viewportTopOffset).\n\t\t\t\tlimiterRect.top < this.viewportTopOffset &&\n\t\t\t\t// The model#limiterElement's height mustn't be smaller than the panel's height and model#limiterBottomOffset.\n\t\t\t\t// There's no point in entering the sticky mode if the model#limiterElement is very, very small, because\n\t\t\t\t// it would immediately set model#_isStickyToTheLimiter true and, given model#limiterBottomOffset, the panel\n\t\t\t\t// would be positioned before the model#limiterElement.\n\t\t\t\tthis._panelRect.height + this.limiterBottomOffset < limiterRect.height;\n\t\t}\n\n\t\t// Stick the panel to the top edge of the viewport simulating CSS position:sticky.\n\t\t// TODO: Possibly replaced by CSS in the future http://caniuse.com/#feat=css-sticky\n\t\tif ( this.isSticky ) {\n\t\t\tthis._isStickyToTheLimiter =\n\t\t\t\tlimiterRect.bottom < panelRect.height + this.limiterBottomOffset + this.viewportTopOffset;\n\t\t\tthis._hasViewportTopOffset = !this._isStickyToTheLimiter && !!this.viewportTopOffset;\n\t\t\tthis._marginLeft = this._isStickyToTheLimiter ? null : toPx( -global.window.scrollX );\n\t\t}\n\t\t// Detach the panel from the top edge of the viewport.\n\t\telse {\n\t\t\tthis._isStickyToTheLimiter = false;\n\t\t\tthis._hasViewportTopOffset = false;\n\t\t\tthis._marginLeft = null;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/focuscycler\n */\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\n\n/**\n * A utility class that helps cycling over focusable {@link module:ui/view~View views} in a\n * {@link module:ui/viewcollection~ViewCollection} when the focus is tracked by the\n * {@link module:utils/focustracker~FocusTracker} instance. It helps implementing keyboard\n * navigation in HTML forms, toolbars, lists and the like.\n *\n * To work properly it requires:\n * * a collection of focusable (HTML `tabindex` attribute) views that implement the `focus()` method,\n * * an associated focus tracker to determine which view is focused.\n *\n * A simple cycler setup can look like this:\n *\n *\t\tconst focusables = new ViewCollection();\n *\t\tconst focusTracker = new FocusTracker();\n *\n *\t\t// Add focusable views to the focus tracker.\n *\t\tfocusTracker.add( ... );\n *\n * Then, the cycler can be used manually:\n *\n *\t\tconst cycler = new FocusCycler( { focusables, focusTracker } );\n *\n *\t\t// Will focus the first focusable view in #focusables.\n *\t\tcycler.focusFirst();\n *\n *\t\t// Will log the next focusable item in #focusables.\n *\t\tconsole.log( cycler.next );\n *\n * Alternatively, it can work side by side with the {@link module:utils/keystrokehandler~KeystrokeHandler}:\n *\n *\t\tconst keystrokeHandler = new KeystrokeHandler();\n *\n *\t\t// Activate the keystroke handler.\n *\t\tkeystrokeHandler.listenTo( sourceOfEvents );\n *\n *\t\tconst cycler = new FocusCycler( {\n *\t\t\tfocusables, focusTracker, keystrokeHandler,\n *\t\t\tactions: {\n *\t\t\t\t// When arrowup of arrowleft is detected by the #keystrokeHandler,\n *\t\t\t\t// focusPrevious() will be called on the cycler.\n *\t\t\t\tfocusPrevious: [ 'arrowup', 'arrowleft' ],\n *\t\t\t}\n *\t\t} );\n */\nexport default class FocusCycler {\n\t/**\n\t * Creates an instance of the focus cycler utility.\n\t *\n\t * @param {Object} options Configuration options.\n\t * @param {module:utils/collection~Collection|Object} options.focusables\n\t * @param {module:utils/focustracker~FocusTracker} options.focusTracker\n\t * @param {module:utils/keystrokehandler~KeystrokeHandler} [options.keystrokeHandler]\n\t * @param {Object} [options.actions]\n\t */\n\tconstructor( options ) {\n\t\tObject.assign( this, options );\n\n\t\t/**\n\t\t * A {@link module:ui/view~View view} collection that the cycler operates on.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/collection~Collection} #focusables\n\t\t */\n\n\t\t/**\n\t\t * A focus tracker instance that the cycler uses to determine the current focus\n\t\t * state in {@link #focusables}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker} #focusTracker\n\t\t */\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}\n\t\t * which can respond to certain keystrokes and cycle the focus.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler} #keystrokeHandler\n\t\t */\n\n\t\t/**\n\t\t * Actions that the cycler can take when a keystroke is pressed. Requires\n\t\t * `options.keystrokeHandler` to be passed and working. When an action is\n\t\t * performed, `preventDefault` and `stopPropagation` will be called on the event\n\t\t * the keystroke fired in the DOM.\n\t\t *\n\t\t *\t\tactions: {\n\t\t *\t\t\t// Will call #focusPrevious() when arrowleft or arrowup is pressed.\n\t\t *\t\t\tfocusPrevious: [ 'arrowleft', 'arrowup' ],\n\t\t *\n\t\t *\t\t\t// Will call #focusNext() when arrowdown is pressed.\n\t\t *\t\t\tfocusNext: 'arrowdown'\n\t\t *\t\t}\n\t\t *\n\t\t * @readonly\n\t\t * @member {Object} #actions\n\t\t */\n\n\t\tif ( options.actions && options.keystrokeHandler ) {\n\t\t\tfor ( const methodName in options.actions ) {\n\t\t\t\tlet actions = options.actions[ methodName ];\n\n\t\t\t\tif ( typeof actions == 'string' ) {\n\t\t\t\t\tactions = [ actions ];\n\t\t\t\t}\n\n\t\t\t\tfor ( const keystroke of actions ) {\n\t\t\t\t\toptions.keystrokeHandler.set( keystroke, ( data, cancel ) => {\n\t\t\t\t\t\tthis[ methodName ]();\n\t\t\t\t\t\tcancel();\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns the first focusable view in {@link #focusables}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #first\n\t */\n\tget first() {\n\t\treturn this.focusables.find( isFocusable ) || null;\n\t}\n\n\t/**\n\t * Returns the last focusable view in {@link #focusables}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #last\n\t */\n\tget last() {\n\t\treturn this.focusables.filter( isFocusable ).slice( -1 )[ 0 ] || null;\n\t}\n\n\t/**\n\t * Returns the next focusable view in {@link #focusables} based on {@link #current}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #next\n\t */\n\tget next() {\n\t\treturn this._getFocusableItem( 1 );\n\t}\n\n\t/**\n\t * Returns the previous focusable view in {@link #focusables} based on {@link #current}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #previous\n\t */\n\tget previous() {\n\t\treturn this._getFocusableItem( -1 );\n\t}\n\n\t/**\n\t * An index of the view in the {@link #focusables} which is focused according\n\t * to {@link #focusTracker}. Returns `null` when there is no such view.\n\t *\n\t * @readonly\n\t * @member {Number|null} #current\n\t */\n\tget current() {\n\t\tlet index = null;\n\n\t\t// There's no focused view in the focusables.\n\t\tif ( this.focusTracker.focusedElement === null ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tthis.focusables.find( ( view, viewIndex ) => {\n\t\t\tconst focused = view.element === this.focusTracker.focusedElement;\n\n\t\t\tif ( focused ) {\n\t\t\t\tindex = viewIndex;\n\t\t\t}\n\n\t\t\treturn focused;\n\t\t} );\n\n\t\treturn index;\n\t}\n\n\t/**\n\t * Focuses the {@link #first} item in {@link #focusables}.\n\t */\n\tfocusFirst() {\n\t\tthis._focus( this.first );\n\t}\n\n\t/**\n\t * Focuses the {@link #last} item in {@link #focusables}.\n\t */\n\tfocusLast() {\n\t\tthis._focus( this.last );\n\t}\n\n\t/**\n\t * Focuses the {@link #next} item in {@link #focusables}.\n\t */\n\tfocusNext() {\n\t\tthis._focus( this.next );\n\t}\n\n\t/**\n\t * Focuses the {@link #previous} item in {@link #focusables}.\n\t */\n\tfocusPrevious() {\n\t\tthis._focus( this.previous );\n\t}\n\n\t/**\n\t * Focuses the given view if it exists.\n\t *\n\t * @protected\n\t * @param {module:ui/view~View} view\n\t */\n\t_focus( view ) {\n\t\tif ( view ) {\n\t\t\tview.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Returns the next or previous focusable view in {@link #focusables} with respect\n\t * to {@link #current}.\n\t *\n\t * @protected\n\t * @param {Number} step Either `1` for checking forward from {@link #current} or\n\t * `-1` for checking backwards.\n\t * @returns {module:ui/view~View|null}\n\t */\n\t_getFocusableItem( step ) {\n\t\t// Cache for speed.\n\t\tconst current = this.current;\n\t\tconst collectionLength = this.focusables.length;\n\n\t\tif ( !collectionLength ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Start from the beginning if no view is focused.\n\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/206\n\t\tif ( current === null ) {\n\t\t\treturn this[ step === 1 ? 'first' : 'last' ];\n\t\t}\n\n\t\t// Cycle in both directions.\n\t\tlet index = ( current + collectionLength + step ) % collectionLength;\n\n\t\tdo {\n\t\t\tconst view = this.focusables.get( index );\n\n\t\t\t// TODO: Check if view is visible.\n\t\t\tif ( isFocusable( view ) ) {\n\t\t\t\treturn view;\n\t\t\t}\n\n\t\t\t// Cycle in both directions.\n\t\t\tindex = ( index + collectionLength + step ) % collectionLength;\n\t\t} while ( index !== current );\n\n\t\treturn null;\n\t}\n}\n\n// Checks whether a view is focusable.\n//\n// @private\n// @param {module:ui/view~View} view A view to be checked.\n// @returns {Boolean}\nfunction isFocusable( view ) {\n\treturn !!( view.focus && global.window.getComputedStyle( view.element ).display != 'none' );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/toolbar/toolbarseparatorview\n */\n\nimport View from '../view';\n\n/**\n * The toolbar separator view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ToolbarSeparatorView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-toolbar__separator'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/resizeobserver\n */\n\n/* globals setTimeout, clearTimeout */\n\nimport mix from '../mix';\nimport global from './global';\nimport Rect from './rect';\nimport DomEmitterMixin from './emittermixin';\n\nconst RESIZE_CHECK_INTERVAL = 100;\n\n/**\n * A helper class which instances allow performing custom actions when native DOM elements are resized.\n *\n *\t\tconst editableElement = editor.editing.view.getDomRoot();\n *\n *\t\tconst observer = new ResizeObserver( editableElement, entry => {\n *\t\t\tconsole.log( 'The editable element has been resized in DOM.' );\n *\t\t\tconsole.log( entry.target ); // -> editableElement\n *\t\t\tconsole.log( entry.contentRect.width ); // -> e.g. '423px'\n *\t\t} );\n *\n * By default, it uses the [native DOM resize observer](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)\n * under the hood and in browsers that do not support the native API yet, a polyfilled observer is\n * used instead.\n */\nexport default class ResizeObserver {\n\t/**\n\t * Creates an instance of the `ResizeObserver` class.\n\t *\n\t * @param {HTMLElement} element A DOM element that is to be observed for resizing. Note that\n\t * the element must be visible (i.e. not detached from DOM) for the observer to work.\n\t * @param {Function} callback A function called when the observed element was resized. It passes\n\t * the [`ResizeObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry)\n\t * object with information about the resize event.\n\t */\n\tconstructor( element, callback ) {\n\t\t// **Note**: For the maximum performance, this class ensures only a single instance of the native\n\t\t// (or polyfilled) observer is used no matter how many instances of this class were created.\n\t\tif ( !ResizeObserver._observerInstance ) {\n\t\t\tResizeObserver._createObserver();\n\t\t}\n\n\t\t/**\n\t\t * The element observer by this observer.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {HTMLElement}\n\t\t */\n\t\tthis._element = element;\n\n\t\t/**\n\t\t * The callback executed each time {@link #_element} is resized.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {Function}\n\t\t */\n\t\tthis._callback = callback;\n\n\t\tResizeObserver._addElementCallback( element, callback );\n\t\tResizeObserver._observerInstance.observe( element );\n\t}\n\n\t/**\n\t * Destroys the observer which disables the `callback` passed to the {@link #constructor}.\n\t */\n\tdestroy() {\n\t\tResizeObserver._deleteElementCallback( this._element, this._callback );\n\t}\n\n\t/**\n\t * Registers a new resize callback for the DOM element.\n\t *\n\t * @private\n\t * @static\n\t * @param {HTMLElement} element\n\t * @param {Function} callback\n\t */\n\tstatic _addElementCallback( element, callback ) {\n\t\tif ( !ResizeObserver._elementCallbacks ) {\n\t\t\tResizeObserver._elementCallbacks = new Map();\n\t\t}\n\n\t\tlet callbacks = ResizeObserver._elementCallbacks.get( element );\n\n\t\tif ( !callbacks ) {\n\t\t\tcallbacks = new Set();\n\t\t\tResizeObserver._elementCallbacks.set( element, callbacks );\n\t\t}\n\n\t\tcallbacks.add( callback );\n\t}\n\n\t/**\n\t * Removes a resize callback from the DOM element. If no callbacks are left\n\t * for the element, it removes the element from the native observer.\n\t *\n\t * @private\n\t * @static\n\t * @param {HTMLElement} element\n\t * @param {Function} callback\n\t */\n\tstatic _deleteElementCallback( element, callback ) {\n\t\tconst callbacks = ResizeObserver._getElementCallbacks( element );\n\n\t\t// Remove the element callback. Check if exist first in case someone\n\t\t// called destroy() twice.\n\t\tif ( callbacks ) {\n\t\t\tcallbacks.delete( callback );\n\n\t\t\t// If no callbacks left for the element, also remove the element.\n\t\t\tif ( !callbacks.size ) {\n\t\t\t\tResizeObserver._elementCallbacks.delete( element );\n\t\t\t\tResizeObserver._observerInstance.unobserve( element );\n\t\t\t}\n\t\t}\n\n\t\tif ( ResizeObserver._elementCallbacks && !ResizeObserver._elementCallbacks.size ) {\n\t\t\tResizeObserver._observerInstance = null;\n\t\t\tResizeObserver._elementCallbacks = null;\n\t\t}\n\t}\n\n\t/**\n\t * Returns are registered resize callbacks for the DOM element.\n\t *\n\t * @private\n\t * @static\n\t * @param {HTMLElement} element\n\t * @returns {Set.<HTMLElement>|null}\n\t */\n\tstatic _getElementCallbacks( element ) {\n\t\tif ( !ResizeObserver._elementCallbacks ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn ResizeObserver._elementCallbacks.get( element );\n\t}\n\n\t/**\n\t * Creates the single native observer shared across all `ResizeObserver` instances.\n\t * If the browser does not support the native API, it creates a polyfill.\n\t *\n\t * @private\n\t * @static\n\t */\n\tstatic _createObserver() {\n\t\tlet ObserverConstructor;\n\n\t\t// TODO: One day, the `ResizeObserver` API will be supported in all modern web browsers.\n\t\t// When it happens, this module will no longer make sense and should be removed and\n\t\t// the native implementation should be used across the project to save bytes.\n\t\t// Check out https://caniuse.com/#feat=resizeobserver.\n\t\tif ( typeof global.window.ResizeObserver === 'function' ) {\n\t\t\tObserverConstructor = global.window.ResizeObserver;\n\t\t} else {\n\t\t\tObserverConstructor = ResizeObserverPolyfill;\n\t\t}\n\n\t\tResizeObserver._observerInstance = new ObserverConstructor( entries => {\n\t\t\tfor ( const entry of entries ) {\n\t\t\t\tconst callbacks = ResizeObserver._getElementCallbacks( entry.target );\n\n\t\t\t\tif ( callbacks ) {\n\t\t\t\t\tfor ( const callback of callbacks ) {\n\t\t\t\t\t\tcallback( entry );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n\n/**\n * The single native observer instance (or polyfill in browsers that do not support the API)\n * shared across all {@link module:utils/dom/resizeobserver~ResizeObserver} instances.\n *\n * @static\n * @protected\n * @readonly\n * @property {Object|null} module:utils/dom/resizeobserver~ResizeObserver#_observerInstance\n */\nResizeObserver._observerInstance = null;\n\n/**\n * A mapping of native DOM elements and their callbacks shared across all\n * {@link module:utils/dom/resizeobserver~ResizeObserver} instances.\n *\n * @static\n * @private\n * @readonly\n * @property {Map.<HTMLElement,Set>|null} module:utils/dom/resizeobserver~ResizeObserver#_elementCallbacks\n */\nResizeObserver._elementCallbacks = null;\n\n/**\n * A polyfill class for the native [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).\n *\n * @private\n * @mixes module:utils/domemittermixin~DomEmitterMixin\n */\nclass ResizeObserverPolyfill {\n\t/**\n\t * Creates an instance of the {@link module:utils/dom/resizeobserver~ResizeObserverPolyfill} class.\n\t *\n\t * It synchronously reacts to resize of the window to check if observed elements' geometry changed.\n\t *\n\t * Additionally, the polyfilled observer uses a timeout to check if observed elements' geometry has changed\n\t * in some other way (dynamic layouts, scrollbars showing up, etc.), so its response can also be asynchronous.\n\t *\n\t * @param {Function} callback A function called when any observed element was resized. Refer to the\n\t * native [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) API to\n\t * learn more.\n\t */\n\tconstructor( callback ) {\n\t\t/**\n\t\t * A function called when any observed {@link #_elements element} was resized.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Function}\n\t\t */\n\t\tthis._callback = callback;\n\n\t\t/**\n\t\t * DOM elements currently observed by the observer instance.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Set}\n\t\t */\n\t\tthis._elements = new Set();\n\n\t\t/**\n\t\t * Cached DOM {@link #_elements elements} bounding rects to compare to upon the next check.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Map.<HTMLElement,module:utils/dom/rect~Rect>}\n\t\t */\n\t\tthis._previousRects = new Map();\n\n\t\t/**\n\t\t * An UID of the current timeout upon which the observed elements rects\n\t\t * will be compared to the {@link #_previousRects previous rects} from the past.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Map.<HTMLElement,module:utils/dom/rect~Rect>}\n\t\t */\n\t\tthis._periodicCheckTimeout = null;\n\t}\n\n\t/**\n\t * Starts observing a DOM element.\n\t *\n\t * Learn more in the\n\t * [native method documentation](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/observe).\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tobserve( element ) {\n\t\tthis._elements.add( element );\n\n\t\tthis._checkElementRectsAndExecuteCallback();\n\n\t\tif ( this._elements.size === 1 ) {\n\t\t\tthis._startPeriodicCheck();\n\t\t}\n\t}\n\n\t/**\n\t * Stops observing a DOM element.\n\t *\n\t * Learn more in the\n\t * [native method documentation](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/unobserve).\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tunobserve( element ) {\n\t\tthis._elements.delete( element );\n\t\tthis._previousRects.delete( element );\n\n\t\tif ( !this._elements.size ) {\n\t\t\tthis._stopPeriodicCheck();\n\t\t}\n\t}\n\n\t/**\n\t * When called, the observer calls the {@link #_callback resize callback} for all observed\n\t * {@link #_elements elements} but also starts checking periodically for changes in the elements' geometry.\n\t * If some are detected, {@link #_callback resize callback} is called for relevant elements that were resized.\n\t *\n\t * @protected\n\t */\n\t_startPeriodicCheck() {\n\t\tconst periodicCheck = () => {\n\t\t\tthis._checkElementRectsAndExecuteCallback();\n\t\t\tthis._periodicCheckTimeout = setTimeout( periodicCheck, RESIZE_CHECK_INTERVAL );\n\t\t};\n\n\t\tthis.listenTo( global.window, 'resize', () => {\n\t\t\tthis._checkElementRectsAndExecuteCallback();\n\t\t} );\n\n\t\tthis._periodicCheckTimeout = setTimeout( periodicCheck, RESIZE_CHECK_INTERVAL );\n\t}\n\n\t/**\n\t * Stops checking for changes in all observed {@link #_elements elements} geometry.\n\t *\n\t * @protected\n\t */\n\t_stopPeriodicCheck() {\n\t\tclearTimeout( this._periodicCheckTimeout );\n\t\tthis.stopListening();\n\t\tthis._previousRects.clear();\n\t}\n\n\t/**\n\t * Checks if the geometry of any of the {@link #_elements element} has changed. If so, executes\n\t * the {@link #_callback resize callback} with element geometry data.\n\t *\n\t * @protected\n\t */\n\t_checkElementRectsAndExecuteCallback() {\n\t\tconst entries = [];\n\n\t\tfor ( const element of this._elements ) {\n\t\t\tif ( this._hasRectChanged( element ) ) {\n\t\t\t\tentries.push( {\n\t\t\t\t\ttarget: element,\n\t\t\t\t\tcontentRect: this._previousRects.get( element )\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\tif ( entries.length ) {\n\t\t\tthis._callback( entries );\n\t\t}\n\t}\n\n\t/**\n\t * Compares the DOM element geometry to the {@link #_previousRects cached geometry} from the past.\n\t * Returns `true` if geometry has changed or the element is checked for the first time.\n\t *\n\t * @protected\n\t * @param {HTMLElement} element\n\t * @returns {Boolean}\n\t */\n\t_hasRectChanged( element ) {\n\t\tif ( !element.ownerDocument.body.contains( element ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst currentRect = new Rect( element );\n\t\tconst previousRect = this._previousRects.get( element );\n\n\t\t// The first check should always yield true despite no Previous rect to compare to.\n\t\t// The native ResizeObserver does that and... that makes sense. Sort of.\n\t\tconst hasChanged = !previousRect || !previousRect.isEqual( currentRect );\n\n\t\tthis._previousRects.set( element, currentRect );\n\n\t\treturn hasChanged;\n\t}\n}\n\nmix( ResizeObserverPolyfill, DomEmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/dropdown/dropdownpanelview\n */\n\nimport View from '../view';\n\n/**\n * The dropdown panel view class.\n *\n * See {@link module:ui/dropdown/dropdownview~DropdownView} to learn about the common usage.\n *\n * @extends module:ui/view~View\n */\nexport default class DropdownPanelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Controls whether the panel is visible.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isVisible\n\t\t */\n\t\tthis.set( 'isVisible', false );\n\n\t\t/**\n\t\t * The position of the panel, relative to the parent.\n\t\t *\n\t\t * This property is reflected in the CSS class set to {@link #element} that controls\n\t\t * the position of the panel.\n\t\t *\n\t\t * @observable\n\t\t * @default 'se'\n\t\t * @member {'se'|'sw'|'ne'|'nw'} #position\n\t\t */\n\t\tthis.set( 'position', 'se' );\n\n\t\t/**\n\t\t * Collection of the child views in this panel.\n\t\t *\n\t\t * A common child type is the {@link module:ui/list/listview~ListView} and {@link module:ui/toolbar/toolbarview~ToolbarView}.\n\t\t * See {@link module:ui/dropdown/utils~addListToDropdown} and\n\t\t * {@link module:ui/dropdown/utils~addToolbarToDropdown} to learn more about child views of dropdowns.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-reset',\n\t\t\t\t\t'ck-dropdown__panel',\n\t\t\t\t\tbind.to( 'position', value => `ck-dropdown__panel_${ value }` ),\n\t\t\t\t\tbind.if( 'isVisible', 'ck-dropdown__panel-visible' )\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: this.children,\n\n\t\t\ton: {\n\t\t\t\t// Drag and drop in the panel should not break the selection in the editor.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/228\n\t\t\t\tselectstart: bind.to( evt => evt.preventDefault() )\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the view element or first item in view collection on opening dropdown's panel.\n\t *\n\t * See also {@link module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable}.\n\t */\n\tfocus() {\n\t\tif ( this.children.length ) {\n\t\t\tthis.children.first.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Focuses the view element or last item in view collection on opening dropdown's panel.\n\t *\n\t * See also {@link module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable}.\n\t */\n\tfocusLast() {\n\t\tif ( this.children.length ) {\n\t\t\tconst lastChild = this.children.last;\n\n\t\t\tif ( typeof lastChild.focusLast === 'function' ) {\n\t\t\t\tlastChild.focusLast();\n\t\t\t} else {\n\t\t\t\tlastChild.focus();\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/position\n */\n\nimport global from './global';\nimport Rect from './rect';\nimport getPositionedAncestor from './getpositionedancestor';\nimport getBorderWidths from './getborderwidths';\nimport { isFunction } from 'lodash-es';\n\n/**\n * Calculates the `position: absolute` coordinates of a given element so it can be positioned with respect to the\n * target in the visually most efficient way, taking various restrictions like viewport or limiter geometry\n * into consideration.\n *\n *\t\t// The element which is to be positioned.\n *\t\tconst element = document.body.querySelector( '#toolbar' );\n *\n *\t\t// A target to which the element is positioned relatively.\n *\t\tconst target = document.body.querySelector( '#container' );\n *\n *\t\t// Finding the optimal coordinates for the positioning.\n *\t\tconst { left, top, name } = getOptimalPosition( {\n *\t\t\telement: element,\n *\t\t\ttarget: target,\n *\n * \t\t\t// The algorithm will chose among these positions to meet the requirements such\n * \t\t\t// as \"limiter\" element or \"fitInViewport\", set below. The positions are considered\n * \t\t\t// in the order of the array.\n *\t\t\tpositions: [\n *\t\t\t\t//\n *\t\t\t \t//\t[ Target ]\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\t| Element |\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\n *\t\t\t\ttargetRect => ( {\n *\t\t\t\t\ttop: targetRect.bottom,\n *\t\t\t\t\tleft: targetRect.left,\n *\t\t\t\t\tname: 'mySouthEastPosition'\n *\t\t\t\t} ),\n *\n *\t\t\t\t//\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\t| Element |\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\t[ Target ]\n *\t\t\t\t//\n *\t\t\t\t( targetRect, elementRect ) => ( {\n *\t\t\t\t\ttop: targetRect.top - elementRect.height,\n *\t\t\t\t\tleft: targetRect.left,\n *\t\t\t\t\tname: 'myNorthEastPosition'\n *\t\t\t\t} )\n *\t\t\t],\n *\n *\t\t\t// Find a position such guarantees the element remains within visible boundaries of <body>.\n *\t\t\tlimiter: document.body,\n *\n *\t\t\t// Find a position such guarantees the element remains within visible boundaries of the browser viewport.\n *\t\t\tfitInViewport: true\n *\t\t} );\n *\n *\t\t// The best position which fits into document.body and the viewport. May be useful\n *\t\t// to set proper class on the `element`.\n *\t\tconsole.log( name ); // -> \"myNorthEastPosition\"\n *\n *\t\t// Using the absolute coordinates which has been found to position the element\n *\t\t// as in the diagram depicting the \"myNorthEastPosition\" position.\n *\t\telement.style.top = top;\n *\t\telement.style.left = left;\n *\n * @param {module:utils/dom/position~Options} options Positioning options object.\n * @returns {module:utils/dom/position~Position}\n */\nexport function getOptimalPosition( { element, target, positions, limiter, fitInViewport } ) {\n\t// If the {@link module:utils/dom/position~Options#target} is a function, use what it returns.\n\t// https://github.com/ckeditor/ckeditor5-utils/issues/157\n\tif ( isFunction( target ) ) {\n\t\ttarget = target();\n\t}\n\n\t// If the {@link module:utils/dom/position~Options#limiter} is a function, use what it returns.\n\t// https://github.com/ckeditor/ckeditor5-ui/issues/260\n\tif ( isFunction( limiter ) ) {\n\t\tlimiter = limiter();\n\t}\n\n\tconst positionedElementAncestor = getPositionedAncestor( element.parentElement );\n\tconst elementRect = new Rect( element );\n\tconst targetRect = new Rect( target );\n\n\tlet bestPosition;\n\tlet name;\n\n\t// If there are no limits, just grab the very first position and be done with that drama.\n\tif ( !limiter && !fitInViewport ) {\n\t\t[ name, bestPosition ] = getPosition( positions[ 0 ], targetRect, elementRect );\n\t} else {\n\t\tconst limiterRect = limiter && new Rect( limiter ).getVisible();\n\t\tconst viewportRect = fitInViewport && new Rect( global.window );\n\n\t\t[ name, bestPosition ] =\n\t\t\tgetBestPosition( positions, targetRect, elementRect, limiterRect, viewportRect ) ||\n\t\t\t// If there's no best position found, i.e. when all intersections have no area because\n\t\t\t// rects have no width or height, then just use the first available position.\n\t\t\tgetPosition( positions[ 0 ], targetRect, elementRect );\n\t}\n\n\tlet { left, top } = getAbsoluteRectCoordinates( bestPosition );\n\n\tif ( positionedElementAncestor ) {\n\t\tconst ancestorPosition = getAbsoluteRectCoordinates( new Rect( positionedElementAncestor ) );\n\t\tconst ancestorBorderWidths = getBorderWidths( positionedElementAncestor );\n\n\t\t// (https://github.com/ckeditor/ckeditor5-ui-default/issues/126)\n\t\t// If there's some positioned ancestor of the panel, then its `Rect` must be taken into\n\t\t// consideration. `Rect` is always relative to the viewport while `position: absolute` works\n\t\t// with respect to that positioned ancestor.\n\t\tleft -= ancestorPosition.left;\n\t\ttop -= ancestorPosition.top;\n\n\t\t// (https://github.com/ckeditor/ckeditor5-utils/issues/139)\n\t\t// If there's some positioned ancestor of the panel, not only its position must be taken into\n\t\t// consideration (see above) but also its internal scrolls. Scroll have an impact here because `Rect`\n\t\t// is relative to the viewport (it doesn't care about scrolling), while `position: absolute`\n\t\t// must compensate that scrolling.\n\t\tleft += positionedElementAncestor.scrollLeft;\n\t\ttop += positionedElementAncestor.scrollTop;\n\n\t\t// (https://github.com/ckeditor/ckeditor5-utils/issues/139)\n\t\t// If there's some positioned ancestor of the panel, then its `Rect` includes its CSS `borderWidth`\n\t\t// while `position: absolute` positioning does not consider it.\n\t\t// E.g. `{ position: absolute, top: 0, left: 0 }` means upper left corner of the element,\n\t\t// not upper-left corner of its border.\n\t\tleft -= ancestorBorderWidths.left;\n\t\ttop -= ancestorBorderWidths.top;\n\t}\n\n\treturn { left, top, name };\n}\n\n// For given position function, returns a corresponding `Rect` instance.\n//\n// @private\n// @param {Function} position A function returning {@link module:utils/dom/position~Position}.\n// @param {utils/dom/rect~Rect} targetRect A rect of the target.\n// @param {utils/dom/rect~Rect} elementRect A rect of positioned element.\n// @returns {Array} An array containing position name and its Rect.\nfunction getPosition( position, targetRect, elementRect ) {\n\tconst { left, top, name } = position( targetRect, elementRect );\n\n\treturn [ name, elementRect.clone().moveTo( left, top ) ];\n}\n\n// For a given array of positioning functions, returns such that provides the best\n// fit of the `elementRect` into the `limiterRect` and `viewportRect`.\n//\n// @private\n// @param {module:utils/dom/position~Options#positions} positions Functions returning\n// {@link module:utils/dom/position~Position} to be checked, in the order of preference.\n// @param {utils/dom/rect~Rect} targetRect A rect of the {@link module:utils/dom/position~Options#target}.\n// @param {utils/dom/rect~Rect} elementRect A rect of positioned {@link module:utils/dom/position~Options#element}.\n// @param {utils/dom/rect~Rect} limiterRect A rect of the {@link module:utils/dom/position~Options#limiter}.\n// @param {utils/dom/rect~Rect} viewportRect A rect of the viewport.\n// @returns {Array} An array containing the name of the position and it's rect.\nfunction getBestPosition( positions, targetRect, elementRect, limiterRect, viewportRect ) {\n\tlet maxLimiterIntersectArea = 0;\n\tlet maxViewportIntersectArea = 0;\n\tlet bestPositionRect;\n\tlet bestPositionName;\n\n\t// This is when element is fully visible.\n\tconst elementRectArea = elementRect.getArea();\n\n\tpositions.some( position => {\n\t\tconst [ positionName, positionRect ] = getPosition( position, targetRect, elementRect );\n\t\tlet limiterIntersectArea;\n\t\tlet viewportIntersectArea;\n\n\t\tif ( limiterRect ) {\n\t\t\tif ( viewportRect ) {\n\t\t\t\t// Consider only the part of the limiter which is visible in the viewport. So the limiter is getting limited.\n\t\t\t\tconst limiterViewportIntersectRect = limiterRect.getIntersection( viewportRect );\n\n\t\t\t\tif ( limiterViewportIntersectRect ) {\n\t\t\t\t\t// If the limiter is within the viewport, then check the intersection between that part of the\n\t\t\t\t\t// limiter and actual position.\n\t\t\t\t\tlimiterIntersectArea = limiterViewportIntersectRect.getIntersectionArea( positionRect );\n\t\t\t\t} else {\n\t\t\t\t\tlimiterIntersectArea = 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlimiterIntersectArea = limiterRect.getIntersectionArea( positionRect );\n\t\t\t}\n\t\t}\n\n\t\tif ( viewportRect ) {\n\t\t\tviewportIntersectArea = viewportRect.getIntersectionArea( positionRect );\n\t\t}\n\n\t\t// The only criterion: intersection with the viewport.\n\t\tif ( viewportRect && !limiterRect ) {\n\t\t\tif ( viewportIntersectArea > maxViewportIntersectArea ) {\n\t\t\t\tsetBestPosition();\n\t\t\t}\n\t\t}\n\t\t// The only criterion: intersection with the limiter.\n\t\telse if ( !viewportRect && limiterRect ) {\n\t\t\tif ( limiterIntersectArea > maxLimiterIntersectArea ) {\n\t\t\t\tsetBestPosition();\n\t\t\t}\n\t\t}\n\t\t// Two criteria: intersection with the viewport and the limiter visible in the viewport.\n\t\telse {\n\t\t\tif ( viewportIntersectArea > maxViewportIntersectArea && limiterIntersectArea >= maxLimiterIntersectArea ) {\n\t\t\t\tsetBestPosition();\n\t\t\t} else if ( viewportIntersectArea >= maxViewportIntersectArea && limiterIntersectArea > maxLimiterIntersectArea ) {\n\t\t\t\tsetBestPosition();\n\t\t\t}\n\t\t}\n\n\t\tfunction setBestPosition() {\n\t\t\tmaxViewportIntersectArea = viewportIntersectArea;\n\t\t\tmaxLimiterIntersectArea = limiterIntersectArea;\n\t\t\tbestPositionRect = positionRect;\n\t\t\tbestPositionName = positionName;\n\t\t}\n\n\t\t// If a such position is found that element is fully container by the limiter then, obviously,\n\t\t// there will be no better one, so finishing.\n\t\treturn limiterIntersectArea === elementRectArea;\n\t} );\n\n\treturn bestPositionRect ? [ bestPositionName, bestPositionRect ] : null;\n}\n\n// DOMRect (also Rect) works in a scroll–independent geometry but `position: absolute` doesn't.\n// This function converts Rect to `position: absolute` coordinates.\n//\n// @private\n// @param {utils/dom/rect~Rect} rect A rect to be converted.\n// @returns {Object} Object containing `left` and `top` properties, in absolute coordinates.\nfunction getAbsoluteRectCoordinates( { left, top } ) {\n\tconst { scrollX, scrollY } = global.window;\n\n\treturn {\n\t\tleft: left + scrollX,\n\t\ttop: top + scrollY,\n\t};\n}\n\n/**\n * The `getOptimalPosition` helper options.\n *\n * @interface module:utils/dom/position~Options\n */\n\n/**\n * Element that is to be positioned.\n *\n * @member {HTMLElement} #element\n */\n\n/**\n * Target with respect to which the `element` is to be positioned.\n *\n * @member {HTMLElement|Range|ClientRect|Rect|Function} #target\n */\n\n/**\n * An array of functions which return {@link module:utils/dom/position~Position} relative\n * to the `target`, in the order of preference.\n *\n * @member {Array.<Function>} #positions\n */\n\n/**\n * When set, the algorithm will chose position which fits the most in the\n * limiter's bounding rect.\n *\n * @member {HTMLElement|Range|ClientRect|Rect|Function} #limiter\n */\n\n/**\n * When set, the algorithm will chose such a position which fits `element`\n * the most inside visible viewport.\n *\n * @member {Boolean} #fitInViewport\n */\n\n/**\n * An object describing a position in `position: absolute` coordinate\n * system, along with position name.\n *\n * @typedef {Object} module:utils/dom/position~Position\n *\n * @property {Number} top Top position offset.\n * @property {Number} left Left position offset.\n * @property {String} name Name of the position.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 utils/dom/getpositionedancestor\n */\n\nimport global from './global';\n\n/**\n * For a given element, returns the nearest ancestor element which CSS position is not \"static\".\n *\n * @param {HTMLElement} element The native DOM element to be checked.\n * @returns {HTMLElement|null}\n */\nexport default function getPositionedAncestor( element ) {\n\twhile ( element && element.tagName.toLowerCase() != 'html' ) {\n\t\tif ( global.window.getComputedStyle( element ).position != 'static' ) {\n\t\t\treturn element;\n\t\t}\n\n\t\telement = element.parentElement;\n\t}\n\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/dropdown/dropdownview\n */\n\nimport View from '../view';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\n\nimport '../../theme/components/dropdown/dropdown.css';\n\nimport { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';\n\n/**\n * The dropdown view class. It manages the dropdown button and dropdown panel.\n *\n * In most cases, the easiest way to create a dropdown is by using the {@link module:ui/dropdown/utils~createDropdown}\n * util:\n *\n *\t\tconst dropdown = createDropdown( locale );\n *\n *\t\t// Configure dropdown's button properties:\n *\t\tdropdown.buttonView.set( {\n *\t\t\tlabel: 'A dropdown',\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tdropdown.render();\n *\n *\t\tdropdown.panelView.element.textContent = 'Content of the panel';\n *\n *\t\t// Will render a dropdown with a panel containing a \"Content of the panel\" text.\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * If you want to add a richer content to the dropdown panel, you can use the {@link module:ui/dropdown/utils~addListToDropdown}\n * and {@link module:ui/dropdown/utils~addToolbarToDropdown} helpers. See more examples in\n * {@link module:ui/dropdown/utils~createDropdown} documentation.\n *\n * If you want to create a completely custom dropdown, then you can compose it manually:\n *\n *\t\tconst button = new DropdownButtonView( locale );\n *\t\tconst panel = new DropdownPanelView( locale );\n *\t\tconst dropdown = new DropdownView( locale, button, panel );\n *\n *\t\tbutton.set( {\n *\t\t\tlabel: 'A dropdown',\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tdropdown.render();\n *\n *\t\tpanel.element.textContent = 'Content of the panel';\n *\n *\t\t// Will render a dropdown with a panel containing a \"Content of the panel\" text.\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * However, dropdown created this way will contain little behavior. You will need to implement handlers for actions\n * such as {@link module:ui/bindings/clickoutsidehandler~clickOutsideHandler clicking outside an open dropdown}\n * (which should close it) and support for arrow keys inside the panel. Therefore, unless you really know what\n * you do and you really need to do it, it is recommended to use the {@link module:ui/dropdown/utils~createDropdown} helper.\n *\n * @extends module:ui/view~View\n */\nexport default class DropdownView extends View {\n\t/**\n\t * Creates an instance of the dropdown.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t * @param {module:ui/dropdown/button/dropdownbutton~DropdownButton} buttonView\n\t * @param {module:ui/dropdown/dropdownpanelview~DropdownPanelView} panelView\n\t */\n\tconstructor( locale, buttonView, panelView ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Button of the dropdown view. Clicking the button opens the {@link #panelView}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/button/buttonview~ButtonView} #buttonView\n\t\t */\n\t\tthis.buttonView = buttonView;\n\n\t\t/**\n\t\t * Panel of the dropdown. It opens when the {@link #buttonView} is\n\t\t * {@link module:ui/button/buttonview~ButtonView#event:execute executed} (i.e. clicked).\n\t\t *\n\t\t * Child views can be added to the panel's `children` collection:\n\t\t *\n\t\t *\t\tdropdown.panelView.children.add( childView );\n\t\t *\n\t\t * See {@link module:ui/dropdown/dropdownpanelview~DropdownPanelView#children} and\n\t\t * {@link module:ui/viewcollection~ViewCollection#add}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/dropdown/dropdownpanelview~DropdownPanelView} #panelView\n\t\t */\n\t\tthis.panelView = panelView;\n\n\t\t/**\n\t\t * Controls whether the dropdown view is open, i.e. shows or hides the {@link #panelView panel}.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isOpen\n\t\t */\n\t\tthis.set( 'isOpen', false );\n\n\t\t/**\n\t\t * Controls whether the dropdown is enabled, i.e. it can be clicked and execute an action.\n\t\t *\n\t\t * See {@link module:ui/button/buttonview~ButtonView#isEnabled}.\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/**\n\t\t * (Optional) The additional CSS class set on the dropdown {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class' );\n\n\t\t/**\n\t\t * (Optional) The `id` attribute of the dropdown (i.e. to pair with a `<label>` element).\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #id\n\t\t */\n\t\tthis.set( 'id' );\n\n\t\t/**\n\t\t * The position of the panel, relative to the dropdown.\n\t\t *\n\t\t * **Note**: When `'auto'`, the panel will use one of the remaining positions to stay\n\t\t * in the viewport, visible to the user. The positions correspond directly to\n\t\t * {@link module:ui/dropdown/dropdownview~DropdownView.defaultPanelPositions default panel positions}.\n\t\t *\n\t\t * **Note**: This value has an impact on the\n\t\t * {@link module:ui/dropdown/dropdownpanelview~DropdownPanelView#position} property\n\t\t * each time the panel becomes {@link #isOpen open}.\n\t\t *\n\t\t * @observable\n\t\t * @default 'auto'\n\t\t * @member {'auto'|'se'|'sw'|'ne'|'nw'} #panelPosition\n\t\t */\n\t\tthis.set( 'panelPosition', 'auto' );\n\n\t\t/**\n\t\t * Tracks information about DOM focus in the dropdown.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}. It manages\n\t\t * keystrokes of the dropdown:\n\t\t *\n\t\t * * <kbd>▼</kbd> opens the dropdown,\n\t\t * * <kbd>◀</kbd> and <kbd>Esc</kbd> closes the dropdown.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-dropdown',\n\t\t\t\t\tbind.to( 'class' ),\n\t\t\t\t\tbind.if( 'isEnabled', 'ck-disabled', value => !value )\n\t\t\t\t],\n\t\t\t\tid: bind.to( 'id' ),\n\t\t\t\t'aria-describedby': bind.to( 'ariaDescribedById' )\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\tbuttonView,\n\t\t\t\tpanelView\n\t\t\t]\n\t\t} );\n\n\t\tbuttonView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-dropdown__button',\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * A child {@link module:ui/list/listview~ListView list view} of the dropdown located\n\t\t * in its {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel}.\n\t\t *\n\t\t * **Note**: Only supported when dropdown has list view added using {@link module:ui/dropdown/utils~addListToDropdown}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/list/listview~ListView} #listView\n\t\t */\n\n\t\t/**\n\t\t * A child toolbar of the dropdown located in the\n\t\t * {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel}.\n\t\t *\n\t\t * **Note**: Only supported when dropdown has list view added using {@link module:ui/dropdown/utils~addToolbarToDropdown}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarView} #toolbarView\n\t\t */\n\n\t\t/**\n\t\t * Fired when the toolbar button or list item is executed.\n\t\t *\n\t\t * For {@link #listView} It fires when a child of some {@link module:ui/list/listitemview~ListItemView}\n\t\t * fired `execute`.\n\t\t *\n\t\t * For {@link #toolbarView} It fires when one of the buttons has been\n\t\t * {@link module:ui/button/buttonview~ButtonView#event:execute executed}.\n\t\t *\n\t\t * **Note**: Only supported when dropdown has list view added using {@link module:ui/dropdown/utils~addListToDropdown}\n\t\t * or {@link module:ui/dropdown/utils~addToolbarToDropdown}.\n\t\t *\n\t\t * @event execute\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Toggle the dropdown when its button has been clicked.\n\t\tthis.listenTo( this.buttonView, 'open', () => {\n\t\t\tthis.isOpen = !this.isOpen;\n\t\t} );\n\n\t\t// Toggle the visibility of the panel when the dropdown becomes open.\n\t\tthis.panelView.bind( 'isVisible' ).to( this, 'isOpen' );\n\n\t\t// Let the dropdown control the position of the panel. The position must\n\t\t// be updated every time the dropdown is open.\n\t\tthis.on( 'change:isOpen', () => {\n\t\t\tif ( !this.isOpen ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If \"auto\", find the best position of the panel to fit into the viewport.\n\t\t\t// Otherwise, simply assign the static position.\n\t\t\tif ( this.panelPosition === 'auto' ) {\n\t\t\t\tthis.panelView.position = DropdownView._getOptimalPosition( {\n\t\t\t\t\telement: this.panelView.element,\n\t\t\t\t\ttarget: this.buttonView.element,\n\t\t\t\t\tfitInViewport: true,\n\t\t\t\t\tpositions: this._panelPositions\n\t\t\t\t} ).name;\n\t\t\t} else {\n\t\t\t\tthis.panelView.position = this.panelPosition;\n\t\t\t}\n\t\t} );\n\n\t\t// Listen for keystrokes coming from within #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\n\t\t// Register #element in the focus tracker.\n\t\tthis.focusTracker.add( this.element );\n\n\t\tconst closeDropdown = ( data, cancel ) => {\n\t\t\tif ( this.isOpen ) {\n\t\t\t\tthis.buttonView.focus();\n\t\t\t\tthis.isOpen = false;\n\t\t\t\tcancel();\n\t\t\t}\n\t\t};\n\n\t\t// Open the dropdown panel using the arrow down key, just like with return or space.\n\t\tthis.keystrokes.set( 'arrowdown', ( data, cancel ) => {\n\t\t\t// Don't open if the dropdown is disabled or already open.\n\t\t\tif ( this.buttonView.isEnabled && !this.isOpen ) {\n\t\t\t\tthis.isOpen = true;\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\n\t\t// Block the right arrow key (until nested dropdowns are implemented).\n\t\tthis.keystrokes.set( 'arrowright', ( data, cancel ) => {\n\t\t\tif ( this.isOpen ) {\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\n\t\t// Close the dropdown using the arrow left/escape key.\n\t\tthis.keystrokes.set( 'arrowleft', closeDropdown );\n\t\tthis.keystrokes.set( 'esc', closeDropdown );\n\t}\n\n\t/**\n\t * Focuses the {@link #buttonView}.\n\t */\n\tfocus() {\n\t\tthis.buttonView.focus();\n\t}\n\n\t/**\n\t * Returns {@link #panelView panel} positions to be used by the\n\t * {@link module:utils/dom/position~getOptimalPosition `getOptimalPosition()`}\n\t * utility considering the direction of the language the UI of the editor is displayed in.\n\t *\n\t * @type {module:utils/dom/position~Options#positions}\n\t * @private\n\t */\n\tget _panelPositions() {\n\t\tconst { southEast, southWest, northEast, northWest } = DropdownView.defaultPanelPositions;\n\n\t\tif ( this.locale.uiLanguageDirection === 'ltr' ) {\n\t\t\treturn [ southEast, southWest, northEast, northWest ];\n\t\t} else {\n\t\t\treturn [ southWest, southEast, northWest, northEast ];\n\t\t}\n\t}\n}\n\n/**\n * A set of positioning functions used by the dropdown view to determine\n * the optimal position (i.e. fitting into the browser viewport) of its\n * {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel} when\n * {@link module:ui/dropdown/dropdownview~DropdownView#panelPosition} is set to 'auto'`.\n *\n * The available positioning functions are as follow:\n *\n * **South**\n *\n * * `southEast`\n *\n *\t\t[ Button ]\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\n * * `southWest`\n *\n *\t\t [ Button ]\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\n * **North**\n *\n * * `northEast`\n *\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\t\t[ Button ]\n *\n * * `northWest`\n *\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\t\t [ Button ]\n *\n * Positioning functions are compatible with {@link module:utils/dom/position~Position}.\n *\n * The name that position function returns will be reflected in dropdown panel's class that\n * controls its placement. See {@link module:ui/dropdown/dropdownview~DropdownView#panelPosition}\n * to learn more.\n *\n * @member {Object} module:ui/dropdown/dropdownview~DropdownView.defaultPanelPositions\n */\nDropdownView.defaultPanelPositions = {\n\tsouthEast: buttonRect => {\n\t\treturn {\n\t\t\ttop: buttonRect.bottom,\n\t\t\tleft: buttonRect.left,\n\t\t\tname: 'se'\n\t\t};\n\t},\n\tsouthWest: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.bottom,\n\t\t\tleft: buttonRect.left - panelRect.width + buttonRect.width,\n\t\t\tname: 'sw'\n\t\t};\n\t},\n\tnorthEast: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.top - panelRect.height,\n\t\t\tleft: buttonRect.left,\n\t\t\tname: 'ne'\n\t\t};\n\t},\n\tnorthWest: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.bottom - panelRect.height,\n\t\t\tleft: buttonRect.left - panelRect.width + buttonRect.width,\n\t\t\tname: 'nw'\n\t\t};\n\t}\n};\n\n/**\n * A function used to calculate the optimal position for the dropdown panel.\n *\n * @protected\n * @member {Function} module:ui/dropdown/dropdownview~DropdownView._getOptimalPosition\n */\nDropdownView._getOptimalPosition = getOptimalPosition;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* global DOMParser */\n\n/**\n * @module ui/icon/iconview\n */\n\nimport View from '../view';\n\nimport '../../theme/components/icon/icon.css';\n\n/**\n * The icon view class.\n *\n * @extends module:ui/view~View\n */\nexport default class IconView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor() {\n\t\tsuper();\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * The SVG source of the icon.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #content\n\t\t */\n\t\tthis.set( 'content', '' );\n\n\t\t/**\n\t\t * This attribute specifies the boundaries to which the\n\t\t * icon content should stretch.\n\t\t *\n\t\t * @observable\n\t\t * @default '0 0 20 20'\n\t\t * @member {String} #viewBox\n\t\t */\n\t\tthis.set( 'viewBox', '0 0 20 20' );\n\n\t\t/**\n\t\t * The fill color of the child `path.ck-icon__fill`.\n\t\t *\n\t\t * @observable\n\t\t * @default ''\n\t\t * @member {String} #fillColor\n\t\t */\n\t\tthis.set( 'fillColor', '' );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'svg',\n\t\t\tns: 'http://www.w3.org/2000/svg',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-icon'\n\t\t\t\t],\n\t\t\t\tviewBox: bind.to( 'viewBox' )\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis._updateXMLContent();\n\t\tthis._colorFillPaths();\n\n\t\t// This is a hack for lack of innerHTML binding.\n\t\t// See: https://github.com/ckeditor/ckeditor5-ui/issues/99.\n\t\tthis.on( 'change:content', () => {\n\t\t\tthis._updateXMLContent();\n\t\t\tthis._colorFillPaths();\n\t\t} );\n\n\t\tthis.on( 'change:fillColor', () => {\n\t\t\tthis._colorFillPaths();\n\t\t} );\n\t}\n\n\t/**\n\t * Updates the {@link #element} with the value of {@link #content}.\n\t *\n\t * @private\n\t */\n\t_updateXMLContent() {\n\t\tif ( this.content ) {\n\t\t\tconst parsed = new DOMParser().parseFromString( this.content.trim(), 'image/svg+xml' );\n\t\t\tconst svg = parsed.querySelector( 'svg' );\n\t\t\tconst viewBox = svg.getAttribute( 'viewBox' );\n\n\t\t\tif ( viewBox ) {\n\t\t\t\tthis.viewBox = viewBox;\n\t\t\t}\n\n\t\t\tthis.element.innerHTML = '';\n\n\t\t\twhile ( svg.childNodes.length > 0 ) {\n\t\t\t\tthis.element.appendChild( svg.childNodes[ 0 ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Fills all child `path.ck-icon__fill` with the `#fillColor`.\n\t *\n\t * @private\n\t */\n\t_colorFillPaths() {\n\t\tif ( this.fillColor ) {\n\t\t\tthis.element.querySelectorAll( '.ck-icon__fill' ).forEach( path => {\n\t\t\t\tpath.style.fill = this.fillColor;\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/tooltip/tooltipview\n */\n\nimport View from '../view';\n\nimport '../../theme/components/tooltip/tooltip.css';\n\n/**\n * The tooltip view class.\n *\n * @extends module:ui/view~View\n */\nexport default class TooltipView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The text of the tooltip visible to the user.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #text\n\t\t */\n\t\tthis.set( 'text', '' );\n\n\t\t/**\n\t\t * The position of the tooltip (south or north).\n\t\t *\n\t\t *\t\t+-----------+\n\t\t *\t\t| north |\n\t\t *\t\t+-----------+\n\t\t *\t\t V\n\t\t *\t\t [element]\n\t\t *\n\t\t *\t\t [element]\n\t\t *\t\t ^\n\t\t *\t\t+-----------+\n\t\t *\t\t| south |\n\t\t *\t\t+-----------+\n\t\t *\n\t\t * @observable\n\t\t * @default 's'\n\t\t * @member {'s'|'n'} #position\n\t\t */\n\t\tthis.set( 'position', 's' );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-tooltip',\n\t\t\t\t\tbind.to( 'position', position => 'ck-tooltip_' + position ),\n\t\t\t\t\tbind.if( 'text', 'ck-hidden', value => !value.trim() )\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'span',\n\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-tooltip__text'\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttext: bind.to( 'text' ),\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/button/buttonview\n */\n\nimport View from '../view';\nimport IconView from '../icon/iconview';\nimport TooltipView from '../tooltip/tooltipview';\n\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\nimport { getEnvKeystrokeText } from '@ckeditor/ckeditor5-utils/src/keyboard';\n\nimport '../../theme/components/button/button.css';\n\n/**\n * The button view class.\n *\n *\t\tconst view = new ButtonView();\n *\n *\t\tview.set( {\n *\t\t\tlabel: 'A button',\n *\t\t\tkeystroke: 'Ctrl+B',\n *\t\t\ttooltip: true,\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tview.render();\n *\n *\t\tdocument.body.append( view.element );\n *\n * @extends module:ui/view~View\n * @implements module:ui/button/button~Button\n */\nexport default class ButtonView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\t\tconst ariaLabelUid = uid();\n\n\t\t// Implement the Button interface.\n\t\tthis.set( 'class' );\n\t\tthis.set( 'labelStyle' );\n\t\tthis.set( 'icon' );\n\t\tthis.set( 'isEnabled', true );\n\t\tthis.set( 'isOn', false );\n\t\tthis.set( 'isVisible', true );\n\t\tthis.set( 'isToggleable', false );\n\t\tthis.set( 'keystroke' );\n\t\tthis.set( 'label' );\n\t\tthis.set( 'tabindex', -1 );\n\t\tthis.set( 'tooltip' );\n\t\tthis.set( 'tooltipPosition', 's' );\n\t\tthis.set( 'type', 'button' );\n\t\tthis.set( 'withText', false );\n\t\tthis.set( 'withKeystroke', false );\n\n\t\t/**\n\t\t * Collection of the child views inside of the button {@link #element}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\t/**\n\t\t * Tooltip of the button view. It is configurable using the {@link #tooltip tooltip attribute}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/tooltip/tooltipview~TooltipView} #tooltipView\n\t\t */\n\t\tthis.tooltipView = this._createTooltipView();\n\n\t\t/**\n\t\t * Label of the button view. It is configurable using the {@link #label label attribute}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/view~View} #labelView\n\t\t */\n\t\tthis.labelView = this._createLabelView( ariaLabelUid );\n\n\t\t/**\n\t\t * The icon view of the button. Will be added to {@link #children} when the\n\t\t * {@link #icon icon attribute} is defined.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/icon/iconview~IconView} #iconView\n\t\t */\n\t\tthis.iconView = new IconView();\n\n\t\tthis.iconView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-button__icon'\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * A view displaying the keystroke of the button next to the {@link #labelView label}.\n\t\t * Added to {@link #children} when the {@link #withKeystroke `withKeystroke` attribute}\n\t\t * is defined.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/view/view~View} #keystrokeView\n\t\t */\n\t\tthis.keystrokeView = this._createKeystrokeView();\n\n\t\t/**\n\t\t * Tooltip of the button bound to the template.\n\t\t *\n\t\t * @see #tooltip\n\t\t * @see #_getTooltipString\n\t\t * @private\n\t\t * @observable\n\t\t * @member {Boolean} #_tooltipString\n\t\t */\n\t\tthis.bind( '_tooltipString' ).to(\n\t\t\tthis, 'tooltip',\n\t\t\tthis, 'label',\n\t\t\tthis, 'keystroke',\n\t\t\tthis._getTooltipString.bind( this )\n\t\t);\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'button',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-button',\n\t\t\t\t\tbind.to( 'class' ),\n\t\t\t\t\tbind.if( 'isEnabled', 'ck-disabled', value => !value ),\n\t\t\t\t\tbind.if( 'isVisible', 'ck-hidden', value => !value ),\n\t\t\t\t\tbind.to( 'isOn', value => value ? 'ck-on' : 'ck-off' ),\n\t\t\t\t\tbind.if( 'withText', 'ck-button_with-text' ),\n\t\t\t\t\tbind.if( 'withKeystroke', 'ck-button_with-keystroke' ),\n\t\t\t\t],\n\t\t\t\ttype: bind.to( 'type', value => value ? value : 'button' ),\n\t\t\t\ttabindex: bind.to( 'tabindex' ),\n\t\t\t\t'aria-labelledby': `ck-editor__aria-label_${ ariaLabelUid }`,\n\t\t\t\t'aria-disabled': bind.if( 'isEnabled', true, value => !value ),\n\t\t\t\t'aria-pressed': bind.to( 'isOn', value => this.isToggleable ? String( value ) : false )\n\t\t\t},\n\n\t\t\tchildren: this.children,\n\n\t\t\ton: {\n\t\t\t\tmousedown: bind.to( evt => {\n\t\t\t\t\tevt.preventDefault();\n\t\t\t\t} ),\n\n\t\t\t\tclick: bind.to( evt => {\n\t\t\t\t\t// We can't make the button disabled using the disabled attribute, because it won't be focusable.\n\t\t\t\t\t// Though, shouldn't this condition be moved to the button controller?\n\t\t\t\t\tif ( this.isEnabled ) {\n\t\t\t\t\t\tthis.fire( 'execute' );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Prevent the default when button is disabled, to block e.g.\n\t\t\t\t\t\t// automatic form submitting. See ckeditor/ckeditor5-link#74.\n\t\t\t\t\t\tevt.preventDefault();\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tif ( this.icon ) {\n\t\t\tthis.iconView.bind( 'content' ).to( this, 'icon' );\n\t\t\tthis.children.add( this.iconView );\n\t\t}\n\n\t\tthis.children.add( this.tooltipView );\n\t\tthis.children.add( this.labelView );\n\n\t\tif ( this.withKeystroke ) {\n\t\t\tthis.children.add( this.keystrokeView );\n\t\t}\n\t}\n\n\t/**\n\t * Focuses the {@link #element} of the button.\n\t */\n\tfocus() {\n\t\tthis.element.focus();\n\t}\n\n\t/**\n\t * Creates a {@link module:ui/tooltip/tooltipview~TooltipView} instance and binds it with button\n\t * attributes.\n\t *\n\t * @private\n\t * @returns {module:ui/tooltip/tooltipview~TooltipView}\n\t */\n\t_createTooltipView() {\n\t\tconst tooltipView = new TooltipView();\n\n\t\ttooltipView.bind( 'text' ).to( this, '_tooltipString' );\n\t\ttooltipView.bind( 'position' ).to( this, 'tooltipPosition' );\n\n\t\treturn tooltipView;\n\t}\n\n\t/**\n\t * Creates a label view instance and binds it with button attributes.\n\t *\n\t * @private\n\t * @param {String} ariaLabelUid The aria label UID.\n\t * @returns {module:ui/view~View}\n\t */\n\t_createLabelView( ariaLabelUid ) {\n\t\tconst labelView = new View();\n\t\tconst bind = this.bindTemplate;\n\n\t\tlabelView.setTemplate( {\n\t\t\ttag: 'span',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-button__label'\n\t\t\t\t],\n\t\t\t\tstyle: bind.to( 'labelStyle' ),\n\t\t\t\tid: `ck-editor__aria-label_${ ariaLabelUid }`,\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: this.bindTemplate.to( 'label' )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn labelView;\n\t}\n\n\t/**\n\t * Creates a view that displays a keystroke next to a {@link #labelView label }\n\t * and binds it with button attributes.\n\t *\n\t * @private\n\t * @returns {module:ui/view~View}\n\t */\n\t_createKeystrokeView() {\n\t\tconst keystrokeView = new View();\n\n\t\tkeystrokeView.setTemplate( {\n\t\t\ttag: 'span',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-button__keystroke'\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: this.bindTemplate.to( 'keystroke', text => getEnvKeystrokeText( text ) )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn keystrokeView;\n\t}\n\n\t/**\n\t * Gets the text for the {@link #tooltipView} from the combination of\n\t * {@link #tooltip}, {@link #label} and {@link #keystroke} attributes.\n\t *\n\t * @private\n\t * @see #tooltip\n\t * @see #_tooltipString\n\t * @param {Boolean|String|Function} tooltip Button tooltip.\n\t * @param {String} label Button label.\n\t * @param {String} keystroke Button keystroke.\n\t * @returns {String}\n\t */\n\t_getTooltipString( tooltip, label, keystroke ) {\n\t\tif ( tooltip ) {\n\t\t\tif ( typeof tooltip == 'string' ) {\n\t\t\t\treturn tooltip;\n\t\t\t} else {\n\t\t\t\tif ( keystroke ) {\n\t\t\t\t\tkeystroke = getEnvKeystrokeText( keystroke );\n\t\t\t\t}\n\n\t\t\t\tif ( tooltip instanceof Function ) {\n\t\t\t\t\treturn tooltip( label, keystroke );\n\t\t\t\t} else {\n\t\t\t\t\treturn `${ label }${ keystroke ? ` (${ keystroke })` : '' }`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn '';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/dropdown/button/dropdownbuttonview\n */\n\nimport ButtonView from '../../button/buttonview';\n\nimport dropdownArrowIcon from '../../../theme/assets/icons/dropdown-arrow.svg';\nimport IconView from '../../icon/iconview';\n\n/**\n * The default dropdown button view class.\n *\n *\t\tconst view = new DropdownButtonView();\n *\n *\t\tview.set( {\n *\t\t\tlabel: 'A button',\n *\t\t\tkeystroke: 'Ctrl+B',\n *\t\t\ttooltip: true\n *\t\t} );\n *\n *\t\tview.render();\n *\n *\t\tdocument.body.append( view.element );\n *\n * Also see the {@link module:ui/dropdown/utils~createDropdown `createDropdown()` util}.\n *\n * @implements module:ui/dropdown/button/dropdownbutton~DropdownButton\n * @extends module:ui/button/buttonview~ButtonView\n */\nexport default class DropdownButtonView extends ButtonView {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * An icon that displays arrow to indicate a dropdown button.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/icon/iconview~IconView}\n\t\t */\n\t\tthis.arrowView = this._createArrowView();\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\t'aria-haspopup': true\n\t\t\t}\n\t\t} );\n\n\t\t// The DropdownButton interface expects the open event upon which will open the dropdown.\n\t\tthis.delegate( 'execute' ).to( this, 'open' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.children.add( this.arrowView );\n\t}\n\n\t/**\n\t * Creates a {@link module:ui/icon/iconview~IconView} instance as {@link #arrowView}.\n\t *\n\t * @private\n\t * @returns {module:ui/icon/iconview~IconView}\n\t */\n\t_createArrowView() {\n\t\tconst arrowView = new IconView();\n\n\t\tarrowView.content = dropdownArrowIcon;\n\n\t\tarrowView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-dropdown__arrow'\n\t\t\t}\n\t\t} );\n\n\t\treturn arrowView;\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 10 10\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M.941 4.523a.75.75 0 111.06-1.06l3.006 3.005 3.005-3.005a.75.75 0 111.06 1.06l-3.549 3.55a.75.75 0 01-1.168-.136L.941 4.523z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 ui/list/listview\n */\n\nimport View from '../view';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '../focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\n\nimport '../../theme/components/list/list.css';\n\n/**\n * The list view class.\n *\n * @extends module:ui/view~View\n * @implements module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable\n */\nexport default class ListView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor() {\n\t\tsuper();\n\n\t\t/**\n\t\t * Collection of the child list views.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this.createCollection();\n\n\t\t/**\n\t\t * Tracks information about DOM focus in the list.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * Helps cycling over focusable {@link #items} in the list.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this.items,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate list items backwards using the arrowup key.\n\t\t\t\tfocusPrevious: 'arrowup',\n\n\t\t\t\t// Navigate toolbar items forwards using the arrowdown key.\n\t\t\t\tfocusNext: 'arrowdown',\n\t\t\t}\n\t\t} );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'ul',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-reset',\n\t\t\t\t\t'ck-list'\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: this.items\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Items added before rendering should be known to the #focusTracker.\n\t\tfor ( const item of this.items ) {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t}\n\n\t\tthis.items.on( 'add', ( evt, item ) => {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t} );\n\n\t\tthis.items.on( 'remove', ( evt, item ) => {\n\t\t\tthis.focusTracker.remove( item.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Focuses the first focusable in {@link #items}.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Focuses the last focusable in {@link #items}.\n\t */\n\tfocusLast() {\n\t\tthis._focusCycler.focusLast();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/list/listitemview\n */\n\nimport View from '../view';\n\n/**\n * The list item view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ListItemView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Collection of the child views inside of the list item {@link #element}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'li',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-list__item'\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: this.children\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the list item.\n\t */\n\tfocus() {\n\t\tthis.children.first.focus();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/list/listseparatorview\n */\n\nimport View from '../view';\n\n/**\n * The list separator view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ListSeparatorView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'li',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-list__separator'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/button/switchbuttonview\n */\n\nimport View from '../view';\nimport ButtonView from './buttonview';\n\nimport '../../theme/components/button/switchbutton.css';\n\n/**\n * The switch button view class.\n *\n *\t\tconst view = new SwitchButtonView();\n *\n *\t\tview.set( {\n *\t\t\twithText: true,\n *\t\t\tlabel: 'Switch me!'\n *\t\t} );\n *\n *\t\tview.render();\n *\n *\t\tdocument.body.append( view.element );\n *\n * @extends module:ui/button/buttonview~ButtonView\n */\nexport default class SwitchButtonView extends ButtonView {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.isToggleable = true;\n\n\t\t/**\n\t\t * The toggle switch of the button.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/view~View} #toggleSwitchView\n\t\t */\n\t\tthis.toggleSwitchView = this._createToggleView();\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-switchbutton'\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.children.add( this.toggleSwitchView );\n\t}\n\n\t/**\n\t * Creates a toggle child view.\n\t *\n\t * @private\n\t * @returns {module:ui/view~View}\n\t */\n\t_createToggleView() {\n\t\tconst toggleSwitchView = new View();\n\n\t\ttoggleSwitchView.setTemplate( {\n\t\t\ttag: 'span',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-button__toggle'\n\t\t\t\t],\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'span',\n\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-button__toggle__inner'\n\t\t\t\t\t\t],\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn toggleSwitchView;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/bindings/clickoutsidehandler\n */\n\n/* global document */\n\n/**\n * Handles clicking **outside** of a specified set of elements, then fires an action.\n *\n * **Note**: Actually, the action is executed upon `mousedown`, not `click`. It prevents\n * certain issues when the user keeps holding the mouse button and the UI cannot react\n * properly.\n *\n * @param {Object} options Configuration options.\n * @param {module:utils/dom/emittermixin~Emitter} options.emitter The emitter to which this behavior\n * should be added.\n * @param {Function} options.activator Function returning a `Boolean`, to determine whether the handler is active.\n * @param {Array.<HTMLElement>} options.contextElements HTML elements that determine the scope of the\n * handler. Clicking any of them or their descendants will **not** fire the callback.\n * @param {Function} options.callback An action executed by the handler.\n */\nexport default function clickOutsideHandler( { emitter, activator, callback, contextElements } ) {\n\temitter.listenTo( document, 'mousedown', ( evt, { target } ) => {\n\t\tif ( !activator() ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const contextElement of contextElements ) {\n\t\t\tif ( contextElement.contains( target ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tcallback();\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module ui/dropdown/utils\n */\nimport DropdownPanelView from './dropdownpanelview';\nimport DropdownView from './dropdownview';\nimport DropdownButtonView from './button/dropdownbuttonview';\nimport ToolbarView from '../toolbar/toolbarview';\nimport ListView from '../list/listview';\nimport ListItemView from '../list/listitemview';\nimport ListSeparatorView from '../list/listseparatorview';\nimport ButtonView from '../button/buttonview';\nimport SwitchButtonView from '../button/switchbuttonview';\nimport clickOutsideHandler from '../bindings/clickoutsidehandler';\nimport '../../theme/components/dropdown/toolbardropdown.css';\nimport '../../theme/components/dropdown/listdropdown.css';\n/**\n * A helper for creating dropdowns. It creates an instance of a {@link module:ui/dropdown/dropdownview~DropdownView dropdown},\n * with a {@link module:ui/dropdown/button/dropdownbutton~DropdownButton button},\n * {@link module:ui/dropdown/dropdownpanelview~DropdownPanelView panel} and all standard dropdown's behaviors.\n *\n * # Creating dropdowns\n *\n * By default, the default {@link module:ui/dropdown/button/dropdownbuttonview~DropdownButtonView} class is used as\n * definition of the button:\n *\n *\t\tconst dropdown = createDropdown( model );\n *\n *\t\t// Configure dropdown's button properties:\n *\t\tdropdown.buttonView.set( {\n *\t\t\tlabel: 'A dropdown',\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tdropdown.render();\n *\n *\t\t// Will render a dropdown labeled \"A dropdown\" with an empty panel.\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * You can also provide other button views (they need to implement the\n * {@link module:ui/dropdown/button/dropdownbutton~DropdownButton} interface). For instance, you can use\n * {@link module:ui/dropdown/button/splitbuttonview~SplitButtonView} to create a dropdown with a split button.\n *\n *\t\tconst dropdown = createDropdown( model, SplitButtonView );\n *\n *\t\t// Configure dropdown's button properties:\n *\t\tdropdown.buttonView.set( {\n *\t\t\tlabel: 'A dropdown',\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tdropdown.buttonView.on( 'execute', () => {\n *\t\t\t// Add the behavior of the \"action part\" of the split button.\n *\t\t\t// Split button consists of the \"action part\" and \"arrow part\".\n *\t\t\t// The arrow opens the dropdown while the action part can have some other behavior.\n * \t\t} );\n *\n *\t\tdropdown.render();\n *\n *\t\t// Will render a dropdown labeled \"A dropdown\" with an empty panel.\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * # Adding content to the dropdown's panel\n *\n * The content of the panel can be inserted directly into the `dropdown.panelView.element`:\n *\n *\t\tdropdown.panelView.element.textContent = 'Content of the panel';\n *\n * However, most of the time you will want to add there either a {@link module:ui/list/listview~ListView list of options}\n * or a list of buttons (i.e. a {@link module:ui/toolbar/toolbarview~ToolbarView toolbar}).\n * To simplify the task, you can use, respectively, {@link module:ui/dropdown/utils~addListToDropdown} or\n * {@link module:ui/dropdown/utils~addToolbarToDropdown} utils.\n *\n * @param {module:utils/locale~Locale} locale The locale instance.\n * @param {Function} ButtonClass The dropdown button view class. Needs to implement the\n * {@link module:ui/dropdown/button/dropdownbutton~DropdownButton} interface.\n * @returns {module:ui/dropdown/dropdownview~DropdownView} The dropdown view instance.\n */\nexport function createDropdown(locale, ButtonClass = DropdownButtonView) {\n const buttonView = new ButtonClass(locale);\n const panelView = new DropdownPanelView(locale);\n const dropdownView = new DropdownView(locale, buttonView, panelView);\n buttonView.bind('isEnabled').to(dropdownView);\n if (buttonView instanceof DropdownButtonView) {\n buttonView.bind('isOn').to(dropdownView, 'isOpen');\n } else {\n buttonView.arrowView.bind('isOn').to(dropdownView, 'isOpen');\n }\n addDefaultBehavior(dropdownView);\n return dropdownView;\n}\n/**\n * Adds an instance of {@link module:ui/toolbar/toolbarview~ToolbarView} to a dropdown.\n *\n *\t\tconst buttons = [];\n *\n *\t\t// Either create a new ButtonView instance or create existing.\n *\t\tbuttons.push( new ButtonView() );\n *\t\tbuttons.push( editor.ui.componentFactory.get( 'someButton' ) );\n *\n *\t\tconst dropdown = createDropdown( locale );\n *\n *\t\taddToolbarToDropdown( dropdown, buttons );\n *\n *\t\tdropdown.toolbarView.isVertical = true;\n *\n *\t\t// Will render a vertical button dropdown labeled \"A button dropdown\"\n *\t\t// with a button group in the panel containing two buttons.\n *\t\tdropdown.render()\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * See {@link module:ui/dropdown/utils~createDropdown} and {@link module:ui/toolbar/toolbarview~ToolbarView}.\n *\n * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView A dropdown instance to which `ToolbarView` will be added.\n * @param {Iterable.<module:ui/button/buttonview~ButtonView>} buttons\n */\nexport function addToolbarToDropdown(dropdownView, buttons) {\n const locale = dropdownView.locale;\n const t = locale.t;\n const toolbarView = dropdownView.toolbarView = new ToolbarView(locale);\n toolbarView.set('ariaLabel', t('ca'));\n dropdownView.extendTemplate({ attributes: { class: ['ck-toolbar-dropdown'] } });\n buttons.map(view => toolbarView.items.add(view));\n dropdownView.panelView.children.add(toolbarView);\n toolbarView.items.delegate('execute').to(dropdownView);\n}\n/**\n * Adds an instance of {@link module:ui/list/listview~ListView} to a dropdown.\n *\n *\t\tconst items = new Collection();\n *\n *\t\titems.add( {\n *\t\t\ttype: 'button',\n *\t\t\tmodel: new Model( {\n *\t\t\t\twithText: true,\n *\t\t\t\tlabel: 'First item',\n *\t\t\t\tlabelStyle: 'color: red'\n *\t\t\t} )\n *\t\t} );\n *\n *\t\titems.add( {\n *\t\t\t type: 'button',\n *\t\t\t model: new Model( {\n *\t\t\t\twithText: true,\n *\t\t\t\tlabel: 'Second item',\n *\t\t\t\tlabelStyle: 'color: green',\n *\t\t\t\tclass: 'foo'\n *\t\t\t} )\n *\t\t} );\n *\n *\t\tconst dropdown = createDropdown( locale );\n *\n *\t\taddListToDropdown( dropdown, items );\n *\n *\t\t// Will render a dropdown with a list in the panel containing two items.\n *\t\tdropdown.render()\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * The `items` collection passed to this methods controls the presence and attributes of respective\n * {@link module:ui/list/listitemview~ListItemView list items}.\n *\n *\n * See {@link module:ui/dropdown/utils~createDropdown} and {@link module:list/list~List}.\n *\n * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView A dropdown instance to which `ListVIew` will be added.\n * @param {Iterable.<module:ui/dropdown/utils~ListDropdownItemDefinition>} items\n * A collection of the list item definitions to populate the list.\n */\nexport function addListToDropdown(dropdownView, items) {\n const locale = dropdownView.locale;\n const listView = dropdownView.listView = new ListView(locale);\n listView.items.bindTo(items).using(({type, model}) => {\n if (type === 'separator') {\n return new ListSeparatorView(locale);\n } else if (type === 'button' || type === 'switchbutton') {\n const listItemView = new ListItemView(locale);\n let buttonView;\n if (type === 'button') {\n buttonView = new ButtonView(locale);\n } else {\n buttonView = new SwitchButtonView(locale);\n }\n // Bind all model properties to the button view.\n buttonView.bind(...Object.keys(model)).to(model);\n buttonView.delegate('execute').to(listItemView);\n listItemView.children.add(buttonView);\n return listItemView;\n }\n });\n dropdownView.panelView.children.add(listView);\n listView.items.delegate('execute').to(dropdownView);\n}\n// Add a set of default behaviors to dropdown view.\n//\n// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\nfunction addDefaultBehavior(dropdownView) {\n closeDropdownOnBlur(dropdownView);\n closeDropdownOnExecute(dropdownView);\n focusDropdownContentsOnArrows(dropdownView);\n}\n// Adds a behavior to a dropdownView that closes opened dropdown when user clicks outside the dropdown.\n//\n// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\nfunction closeDropdownOnBlur(dropdownView) {\n dropdownView.on('render', () => {\n clickOutsideHandler({\n emitter: dropdownView,\n activator: () => dropdownView.isOpen,\n callback: () => {\n dropdownView.isOpen = false;\n },\n contextElements: [dropdownView.element]\n });\n });\n}\n// Adds a behavior to a dropdownView that closes the dropdown view on \"execute\" event.\n//\n// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\nfunction closeDropdownOnExecute(dropdownView) {\n // Close the dropdown when one of the list items has been executed.\n dropdownView.on('execute', evt => {\n // Toggling a switch button view should not close the dropdown.\n if (evt.source instanceof SwitchButtonView) {\n return;\n }\n dropdownView.isOpen = false;\n });\n}\n// Adds a behavior to a dropdownView that focuses the dropdown's panel view contents on keystrokes.\n//\n// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\nfunction focusDropdownContentsOnArrows(dropdownView) {\n // If the dropdown panel is already open, the arrow down key should focus the first child of the #panelView.\n dropdownView.keystrokes.set('arrowdown', (data, cancel) => {\n if (dropdownView.isOpen) {\n dropdownView.panelView.focus();\n cancel();\n }\n });\n // If the dropdown panel is already open, the arrow up key should focus the last child of the #panelView.\n dropdownView.keystrokes.set('arrowup', (data, cancel) => {\n if (dropdownView.isOpen) {\n dropdownView.panelView.focusLast();\n cancel();\n }\n });\n} /**\n * A definition of the list item used by the {@link module:ui/dropdown/utils~addListToDropdown}\n * utility.\n *\n * @typedef {Object} module:ui/dropdown/utils~ListDropdownItemDefinition\n *\n * @property {String} type Either `'separator'`, `'button'` or `'switchbutton'`.\n * @property {module:ui/model~Model} [model] Model of the item (when **not** `'separator'`).\n * Its properties fuel the newly created list item (or its children, depending on the `type`).\n */","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module ui/toolbar/toolbarview\n */\n/* globals console */\nimport View from '../view';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '../focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport ToolbarSeparatorView from './toolbarseparatorview';\nimport ResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/resizeobserver';\nimport preventDefault from '../bindings/preventdefault.js';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport {\n createDropdown,\n addToolbarToDropdown\n} from '../dropdown/utils';\nimport { attachLinkToDocumentation } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport verticalDotsIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/three-vertical-dots.svg';\nimport '../../theme/components/toolbar/toolbar.css';\n/**\n * The toolbar view class.\n *\n * @extends module:ui/view~View\n * @implements module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable\n */\nexport default class ToolbarView extends View {\n /**\n\t * Creates an instance of the {@link module:ui/toolbar/toolbarview~ToolbarView} class.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} locale The localization services instance.\n\t * @param {module:ui/toolbar/toolbarview~ToolbarOptions} [options] Configuration options of the toolbar.\n\t */\n constructor(locale, options) {\n super(locale);\n const bind = this.bindTemplate;\n const t = this.t;\n /**\n\t\t * A reference to the options object passed to the constructor.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarOptions}\n\t\t */\n this.options = options || {};\n /**\n\t\t * Label used by assistive technologies to describe this toolbar element.\n\t\t *\n\t\t * @default 'Editor toolbar'\n\t\t * @member {String} #ariaLabel\n\t\t */\n this.set('ariaLabel', t('by'));\n /**\n\t\t * A collection of toolbar items (buttons, dropdowns, etc.).\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this.items = this.createCollection();\n /**\n\t\t * Tracks information about the DOM focus in the toolbar.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n this.focusTracker = new FocusTracker();\n /**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}\n\t\t * to handle keyboard navigation in the toolbar.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n this.keystrokes = new KeystrokeHandler();\n /**\n\t\t * An additional CSS class added to the {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n this.set('class');\n /**\n\t\t * When set true, makes the toolbar look compact with {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @default false\n\t\t * @member {String} #isCompact\n\t\t */\n this.set('isCompact', false);\n /**\n\t\t * A (child) view containing {@link #items toolbar items}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ItemsView}\n\t\t */\n this.itemsView = new ItemsView(locale);\n /**\n\t\t * A top–level collection aggregating building blocks of the toolbar.\n\t\t *\n\t\t *\t┌───────────────── ToolbarView ─────────────────┐\n\t\t *\t| ┌──────────────── #children ────────────────┐ |\n\t\t *\t| | ┌──────────── #itemsView ───────────┐ | |\n\t\t *\t| | | [ item1 ] [ item2 ] ... [ itemN ] | | |\n\t\t *\t| | └──────────────────────────────────-┘ | |\n\t\t *\t| └───────────────────────────────────────────┘ |\n\t\t *\t└───────────────────────────────────────────────┘\n\t\t *\n\t\t * By default, it contains the {@link #itemsView} but it can be extended with additional\n\t\t * UI elements when necessary.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this.children = this.createCollection();\n this.children.add(this.itemsView);\n /**\n\t\t * A collection of {@link #items} that take part in the focus cycling\n\t\t * (i.e. navigation using the keyboard). Usually, it contains a subset of {@link #items} with\n\t\t * some optional UI elements that also belong to the toolbar and should be focusable\n\t\t * by the user.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this.focusables = this.createCollection();\n /**\n\t\t * Controls the orientation of toolbar items. Only available when\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull dynamic items grouping}\n\t\t * is **disabled**.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isVertical\n\t\t */\n /**\n\t\t * Helps cycling over {@link #focusables focusable items} in the toolbar.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n this._focusCycler = new FocusCycler({\n focusables: this.focusables,\n focusTracker: this.focusTracker,\n keystrokeHandler: this.keystrokes,\n actions: {\n // Navigate toolbar items backwards using the arrow[left,up] keys.\n focusPrevious: [\n 'arrowleft',\n 'arrowup'\n ],\n // Navigate toolbar items forwards using the arrow[right,down] keys.\n focusNext: [\n 'arrowright',\n 'arrowdown'\n ]\n }\n });\n this.setTemplate({\n tag: 'div',\n attributes: {\n class: [\n 'ck',\n 'ck-toolbar',\n bind.to('class'),\n bind.if('isCompact', 'ck-toolbar_compact')\n ],\n role: 'toolbar',\n 'aria-label': bind.to('ariaLabel')\n },\n children: this.children,\n on: {\n // https://github.com/ckeditor/ckeditor5-ui/issues/206\n mousedown: preventDefault(this)\n }\n });\n /**\n\t\t * An instance of the active toolbar behavior that shapes its look and functionality.\n\t\t *\n\t\t * See {@link module:ui/toolbar/toolbarview~ToolbarBehavior} to learn more.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarBehavior}\n\t\t */\n this._behavior = this.options.shouldGroupWhenFull ? new DynamicGrouping(this) : new StaticLayout(this);\n }\n /**\n\t * @inheritDoc\n\t */\n render() {\n super.render();\n // Children added before rendering should be known to the #focusTracker.\n for (const item of this.items) {\n this.focusTracker.add(item.element);\n }\n this.items.on('add', (evt, item) => {\n this.focusTracker.add(item.element);\n });\n this.items.on('remove', (evt, item) => {\n this.focusTracker.remove(item.element);\n });\n // Start listening for the keystrokes coming from #element.\n this.keystrokes.listenTo(this.element);\n this._behavior.render(this);\n }\n /**\n\t * @inheritDoc\n\t */\n destroy() {\n this._behavior.destroy();\n return super.destroy();\n }\n /**\n\t * Focuses the first focusable in {@link #focusables}.\n\t */\n focus() {\n this._focusCycler.focusFirst();\n }\n /**\n\t * Focuses the last focusable in {@link #focusables}.\n\t */\n focusLast() {\n this._focusCycler.focusLast();\n }\n /**\n\t * A utility that expands the plain toolbar configuration into\n\t * {@link module:ui/toolbar/toolbarview~ToolbarView#items} using a given component factory.\n\t *\n\t * @param {Array.<String>} config The toolbar items configuration.\n\t * @param {module:ui/componentfactory~ComponentFactory} factory A factory producing toolbar items.\n\t */\n fillFromConfig(config, factory) {\n config.map(name => {\n if (name == '|') {\n this.items.add(new ToolbarSeparatorView());\n } else if (factory.has(name)) {\n this.items.add(factory.create(name));\n } else {\n /**\n\t\t\t\t * There was a problem processing the configuration of the toolbar. The item with the given\n\t\t\t\t * name does not exist so it was omitted when rendering the toolbar.\n\t\t\t\t *\n\t\t\t\t * This warning usually shows up when the {@link module:core/plugin~Plugin} which is supposed\n\t\t\t\t * to provide a toolbar item has not been loaded or there is a typo in the configuration.\n\t\t\t\t *\n\t\t\t\t * Make sure the plugin responsible for this toolbar item is loaded and the toolbar configuration\n\t\t\t\t * is correct, e.g. {@link module:basic-styles/bold~Bold} is loaded for the `'bold'` toolbar item.\n\t\t\t\t *\n\t\t\t\t * You can use the following snippet to retrieve all available toolbar items:\n\t\t\t\t *\n\t\t\t\t *\t\tArray.from( editor.ui.componentFactory.names() );\n\t\t\t\t *\n\t\t\t\t * @error toolbarview-item-unavailable\n\t\t\t\t * @param {String} name The name of the component.\n\t\t\t\t */\n console.warn(attachLinkToDocumentation('toolbarview-item-unavailable: The requested toolbar item is unavailable.'), { name });\n }\n });\n }\n}\n/**\n * An inner block of the {@link module:ui/toolbar/toolbarview~ToolbarView} hosting its\n * {@link module:ui/toolbar/toolbarview~ToolbarView#items}.\n *\n * @private\n * @extends module:ui/view~View\n */\nclass ItemsView extends View {\n /**\n\t * @inheritDoc\n\t */\n constructor(locale) {\n super(locale);\n /**\n\t\t * A collection of items (buttons, dropdowns, etc.).\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this.children = this.createCollection();\n this.setTemplate({\n tag: 'div',\n attributes: {\n class: [\n 'ck',\n 'ck-toolbar__items'\n ]\n },\n children: this.children\n });\n }\n}\n/**\n * A toolbar behavior that makes it static and unresponsive to the changes of the environment.\n * At the same time, it also makes it possible to display a toolbar with a vertical layout\n * using the {@link module:ui/toolbar/toolbarview~ToolbarView#isVertical} property.\n *\n * @private\n * @implements module:ui/toolbar/toolbarview~ToolbarBehavior\n */\nclass StaticLayout {\n /**\n\t * Creates an instance of the {@link module:ui/toolbar/toolbarview~StaticLayout} toolbar\n\t * behavior.\n\t *\n\t * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior\n\t * is added to.\n\t */\n constructor(view) {\n const bind = view.bindTemplate;\n // Static toolbar can be vertical when needed.\n view.set('isVertical', false);\n // 1:1 pass–through binding, all ToolbarView#items are visible.\n view.itemsView.children.bindTo(view.items).using(item => item);\n // 1:1 pass–through binding, all ToolbarView#items are focusable.\n view.focusables.bindTo(view.items).using(item => item);\n view.extendTemplate({\n attributes: {\n class: [// When vertical, the toolbar has an additional CSS class.\n bind.if('isVertical', 'ck-toolbar_vertical')]\n }\n });\n }\n /**\n\t * @inheritDoc\n\t */\n render() {\n }\n /**\n\t * @inheritDoc\n\t */\n destroy() {\n }\n}\n/**\n * A toolbar behavior that makes the items respond to changes in the geometry.\n *\n * In a nutshell, it groups {@link module:ui/toolbar/toolbarview~ToolbarView#items}\n * that do not fit visually into a single row of the toolbar (due to limited space).\n * Items that do not fit are aggregated in a dropdown displayed at the end of the toolbar.\n *\n *\t┌──────────────────────────────────────── ToolbarView ──────────────────────────────────────────┐\n *\t| ┌─────────────────────────────────────── #children ─────────────────────────────────────────┐ |\n *\t| | ┌─────── #itemsView ────────┐ ┌──────────────────────┐ ┌── #groupedItemsDropdown ───┐ | |\n *\t| | | #ungroupedItems | | ToolbarSeparatorView | | #groupedItems | | |\n *\t| | └──────────────────────────-┘ └──────────────────────┘ └────────────────────────────┘ | |\n *\t| | \\---------- only when toolbar items overflow --------/ | |\n *\t| └───────────────────────────────────────────────────────────────────────────────────────────┘ |\n *\t└───────────────────────────────────────────────────────────────────────────────────────────────┘\n *\n * @private\n * @implements module:ui/toolbar/toolbarview~ToolbarBehavior\n */\nclass DynamicGrouping {\n /**\n\t * Creates an instance of the {@link module:ui/toolbar/toolbarview~DynamicGrouping} toolbar\n\t * behavior.\n\t *\n\t * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior\n\t * is added to.\n\t */\n constructor(view) {\n /**\n\t\t * A collection of toolbar children.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this.viewChildren = view.children;\n /**\n\t\t * A collection of focusable toolbar elements.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this.viewFocusables = view.focusables;\n /**\n\t\t * A view containing toolbar items.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ItemsView}\n\t\t */\n this.viewItemsView = view.itemsView;\n /**\n\t\t * Toolbar focus tracker.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n this.viewFocusTracker = view.focusTracker;\n /**\n\t\t * Toolbar locale.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n this.viewLocale = view.locale;\n /**\n\t\t * Toolbar element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {HTMLElement} #viewElement\n\t\t */\n /**\n\t\t * A subset of toolbar {@link module:ui/toolbar/toolbarview~ToolbarView#items}.\n\t\t * Aggregates items that fit into a single row of the toolbar and were not {@link #groupedItems grouped}\n\t\t * into a {@link #groupedItemsDropdown dropdown}. Items of this collection are displayed in the\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarView#itemsView}.\n\t\t *\n\t\t * When none of the {@link module:ui/toolbar/toolbarview~ToolbarView#items} were grouped, it\n\t\t * matches the {@link module:ui/toolbar/toolbarview~ToolbarView#items} collection in size and order.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this.ungroupedItems = view.createCollection();\n /**\n\t\t * A subset of toolbar {@link module:ui/toolbar/toolbarview~ToolbarView#items}.\n\t\t * A collection of the toolbar items that do not fit into a single row of the toolbar.\n\t\t * Grouped items are displayed in a dedicated {@link #groupedItemsDropdown dropdown}.\n\t\t *\n\t\t * When none of the {@link module:ui/toolbar/toolbarview~ToolbarView#items} were grouped,\n\t\t * this collection is empty.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this.groupedItems = view.createCollection();\n /**\n\t\t * The dropdown that aggregates {@link #groupedItems grouped items} that do not fit into a single\n\t\t * row of the toolbar. It is displayed on demand as the last of\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarView#children toolbar children} and offers another\n\t\t * (nested) toolbar which displays items that would normally overflow.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/dropdown/dropdownview~DropdownView}\n\t\t */\n this.groupedItemsDropdown = this._createGroupedItemsDropdown();\n /**\n\t\t * An instance of the resize observer that helps dynamically determine the geometry of the toolbar\n\t\t * and manage items that do not fit into a single row.\n\t\t *\n\t\t * **Note:** Created in {@link #_enableGroupingOnResize}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/dom/resizeobserver~ResizeObserver}\n\t\t */\n this.resizeObserver = null;\n /**\n\t\t * A cached value of the horizontal padding style used by {@link #_updateGrouping}\n\t\t * to manage the {@link module:ui/toolbar/toolbarview~ToolbarView#items} that do not fit into\n\t\t * a single toolbar line. This value can be reused between updates because it is unlikely that\n\t\t * the padding will change and re–using `Window.getComputedStyle()` is expensive.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n this.cachedPadding = null;\n // Only those items that were not grouped are visible to the user.\n view.itemsView.children.bindTo(this.ungroupedItems).using(item => item);\n // Make sure all #items visible in the main space of the toolbar are \"focuscycleable\".\n this.ungroupedItems.on('add', this._updateFocusCycleableItems.bind(this));\n this.ungroupedItems.on('remove', this._updateFocusCycleableItems.bind(this));\n // Make sure the #groupedItemsDropdown is also included in cycling when it appears.\n view.children.on('add', this._updateFocusCycleableItems.bind(this));\n view.children.on('remove', this._updateFocusCycleableItems.bind(this));\n // ToolbarView#items is dynamic. When an item is added, it should be automatically\n // represented in either grouped or ungrouped items at the right index.\n // In other words #items == concat( #ungroupedItems, #groupedItems )\n // (in length and order).\n view.items.on('add', (evt, item, index) => {\n if (index > this.ungroupedItems.length) {\n this.groupedItems.add(item, index - this.ungroupedItems.length);\n } else {\n this.ungroupedItems.add(item, index);\n }\n // When a new ungrouped item joins in and lands in #ungroupedItems, there's a chance it causes\n // the toolbar to overflow.\n this._updateGrouping();\n });\n // When an item is removed from ToolbarView#items, it should be automatically\n // removed from either grouped or ungrouped items.\n view.items.on('remove', (evt, item, index) => {\n if (index > this.ungroupedItems.length) {\n this.groupedItems.remove(item);\n } else {\n this.ungroupedItems.remove(item);\n }\n // Whether removed from grouped or ungrouped items, there is a chance\n // some new space is available and we could do some ungrouping.\n this._updateGrouping();\n });\n view.extendTemplate({\n attributes: {\n class: [// To group items dynamically, the toolbar needs a dedicated CSS class.\n 'ck-toolbar_grouping']\n }\n });\n }\n /**\n\t * Enables dynamic items grouping based on the dimensions of the toolbar.\n\t *\n\t * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior\n\t * is added to.\n\t */\n render(view) {\n this.viewElement = view.element;\n this._enableGroupingOnResize();\n }\n /**\n\t * Cleans up the internals used by this behavior.\n\t */\n destroy() {\n // The dropdown may not be in ToolbarView#children at the moment of toolbar destruction\n // so let's make sure it's actually destroyed along with the toolbar.\n this.groupedItemsDropdown.destroy();\n this.resizeObserver.destroy();\n }\n /**\n\t * When called, it will check if any of the {@link #ungroupedItems} do not fit into a single row of the toolbar,\n\t * and it will move them to the {@link #groupedItems} when it happens.\n\t *\n\t * At the same time, it will also check if there is enough space in the toolbar for the first of the\n\t * {@link #groupedItems} to be returned back to {@link #ungroupedItems} and still fit into a single row\n\t * without the toolbar wrapping.\n\t *\n\t * @protected\n\t */\n _updateGrouping() {\n // Do no grouping–related geometry analysis when the toolbar is detached from visible DOM,\n // for instance before #render(), or after render but without a parent or a parent detached\n // from DOM. DOMRects won't work anyway and there will be tons of warning in the console and\n // nothing else.\n if (!this.viewElement.ownerDocument.body.contains(this.viewElement)) {\n return;\n }\n let wereItemsGrouped;\n // Group #items as long as some wrap to the next row. This will happen, for instance,\n // when the toolbar is getting narrow and there is not enough space to display all items in\n // a single row.\n while (this._areItemsOverflowing) {\n this._groupLastItem();\n wereItemsGrouped = true;\n }\n // If none were grouped now but there were some items already grouped before,\n // then, what the hell, maybe let's see if some of them can be ungrouped. This happens when,\n // for instance, the toolbar is stretching and there's more space in it than before.\n if (!wereItemsGrouped && this.groupedItems.length) {\n // Ungroup items as long as none are overflowing or there are none to ungroup left.\n while (this.groupedItems.length && !this._areItemsOverflowing) {\n this._ungroupFirstItem();\n }\n // If the ungrouping ended up with some item wrapping to the next row,\n // put it back to the group toolbar (\"undo the last ungroup\"). We don't know whether\n // an item will wrap or not until we ungroup it (that's a DOM/CSS thing) so this\n // clean–up is vital for the algorithm.\n if (this._areItemsOverflowing) {\n this._groupLastItem();\n }\n }\n }\n /**\n\t * Returns `true` when {@link module:ui/toolbar/toolbarview~ToolbarView#element} children visually overflow,\n\t * for instance if the toolbar is narrower than its members. Returns `false` otherwise.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n get _areItemsOverflowing() {\n // An empty toolbar cannot overflow.\n if (!this.ungroupedItems.length) {\n return false;\n }\n const element = this.viewElement;\n const uiLanguageDirection = this.viewLocale.uiLanguageDirection;\n const lastChildRect = new Rect(element.lastChild);\n const toolbarRect = new Rect(element);\n if (!this.cachedPadding) {\n const computedStyle = global.window.getComputedStyle(element);\n const paddingProperty = uiLanguageDirection === 'ltr' ? 'paddingRight' : 'paddingLeft';\n // parseInt() is essential because of quirky floating point numbers logic and DOM.\n // If the padding turned out too big because of that, the grouped items dropdown would\n // always look (from the Rect perspective) like it overflows (while it's not).\n this.cachedPadding = Number.parseInt(computedStyle[paddingProperty]);\n }\n if (uiLanguageDirection === 'ltr') {\n return lastChildRect.right > toolbarRect.right - this.cachedPadding;\n } else {\n return lastChildRect.left < toolbarRect.left + this.cachedPadding;\n }\n }\n /**\n\t * Enables the functionality that prevents {@link #ungroupedItems} from overflowing (wrapping to the next row)\n\t * upon resize when there is little space available. Instead, the toolbar items are moved to the\n\t * {@link #groupedItems} collection and displayed in a dropdown at the end of the row (which has its own nested toolbar).\n\t *\n\t * When called, the toolbar will automatically analyze the location of its {@link #ungroupedItems} and \"group\"\n\t * them in the dropdown if necessary. It will also observe the browser window for size changes in\n\t * the future and respond to them by grouping more items or reverting already grouped back, depending\n\t * on the visual space available.\n\t *\n\t * @private\n\t */\n _enableGroupingOnResize() {\n let previousWidth;\n // TODO: Consider debounce.\n this.resizeObserver = new ResizeObserver(this.viewElement, entry => {\n if (!previousWidth || previousWidth !== entry.contentRect.width) {\n this._updateGrouping();\n previousWidth = entry.contentRect.width;\n }\n });\n this._updateGrouping();\n }\n /**\n\t * When called, it will remove the last item from {@link #ungroupedItems} and move it back\n\t * to the {@link #groupedItems} collection.\n\t *\n\t * The opposite of {@link #_ungroupFirstItem}.\n\t *\n\t * @private\n\t */\n _groupLastItem() {\n if (!this.groupedItems.length) {\n this.viewChildren.add(new ToolbarSeparatorView());\n this.viewChildren.add(this.groupedItemsDropdown);\n this.viewFocusTracker.add(this.groupedItemsDropdown.element);\n }\n this.groupedItems.add(this.ungroupedItems.remove(this.ungroupedItems.last), 0);\n }\n /**\n\t * Moves the very first item belonging to {@link #groupedItems} back\n\t * to the {@link #ungroupedItems} collection.\n\t *\n\t * The opposite of {@link #_groupLastItem}.\n\t *\n\t * @private\n\t */\n _ungroupFirstItem() {\n this.ungroupedItems.add(this.groupedItems.remove(this.groupedItems.first));\n if (!this.groupedItems.length) {\n this.viewChildren.remove(this.groupedItemsDropdown);\n this.viewChildren.remove(this.viewChildren.last);\n this.viewFocusTracker.remove(this.groupedItemsDropdown.element);\n }\n }\n /**\n\t * Creates the {@link #groupedItemsDropdown} that hosts the members of the {@link #groupedItems}\n\t * collection when there is not enough space in the toolbar to display all items in a single row.\n\t *\n\t * @private\n\t * @returns {module:ui/dropdown/dropdownview~DropdownView}\n\t */\n _createGroupedItemsDropdown() {\n const locale = this.viewLocale;\n const t = locale.t;\n const dropdown = createDropdown(locale);\n dropdown.class = 'ck-toolbar__grouped-dropdown';\n // Make sure the dropdown never sticks out to the left/right. It should be under the main toolbar.\n // (https://github.com/ckeditor/ckeditor5/issues/5608)\n dropdown.panelPosition = locale.uiLanguageDirection === 'ltr' ? 'sw' : 'se';\n addToolbarToDropdown(dropdown, []);\n dropdown.buttonView.set({\n label: t('bz'),\n tooltip: true,\n icon: verticalDotsIcon\n });\n // 1:1 pass–through binding.\n dropdown.toolbarView.items.bindTo(this.groupedItems).using(item => item);\n return dropdown;\n }\n /**\n\t * Updates the {@link module:ui/toolbar/toolbarview~ToolbarView#focusables focus–cycleable items}\n\t * collection so it represents the up–to–date state of the UI from the perspective of the user.\n\t *\n\t * For instance, the {@link #groupedItemsDropdown} can show up and hide but when it is visible,\n\t * it must be subject to focus cycling in the toolbar.\n\t *\n\t * See the {@link module:ui/toolbar/toolbarview~ToolbarView#focusables collection} documentation\n\t * to learn more about the purpose of this method.\n\t *\n\t * @private\n\t */\n _updateFocusCycleableItems() {\n this.viewFocusables.clear();\n this.ungroupedItems.map(item => {\n this.viewFocusables.add(item);\n });\n if (this.groupedItems.length) {\n this.viewFocusables.add(this.groupedItemsDropdown);\n }\n }\n} /**\n * Options passed to the {@link module:ui/toolbar/toolbarview~ToolbarView#constructor} of the toolbar.\n *\n * @interface module:ui/toolbar/toolbarview~ToolbarOptions\n */\n /**\n * When set to `true`, the toolbar will automatically group {@link module:ui/toolbar/toolbarview~ToolbarView#items} that\n * would normally wrap to the next line when there is not enough space to display them in a single row, for\n * instance, if the parent container of the toolbar is narrow.\n *\n * @member {Boolean} module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull\n */\n /**\n * A class interface defining the behavior of the {@link module:ui/toolbar/toolbarview~ToolbarView}.\n *\n * Toolbar behaviors extend its look and functionality and have an impact on the\n * {@link module:ui/toolbar/toolbarview~ToolbarView#element} template or\n * {@link module:ui/toolbar/toolbarview~ToolbarView#render rendering}. They can be enabled\n * conditionally, e.g. depending on the configuration of the toolbar.\n *\n * @private\n * @interface module:ui/toolbar/toolbarview~ToolbarBehavior\n */\n /**\n * Creates a new toolbar behavior instance.\n *\n * The instance is created in the {@link module:ui/toolbar/toolbarview~ToolbarView#constructor} of the toolbar.\n * This is the right place to extend the {@link module:ui/toolbar/toolbarview~ToolbarView#template} of\n * the toolbar, define extra toolbar properties, etc.\n *\n * @method #constructor\n * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior is added to.\n */\n /**\n * A method called after the toolbar has been {@link module:ui/toolbar/toolbarview~ToolbarView#render rendered}.\n * It can be used to, for example, customize the behavior of the toolbar when its {@link module:ui/toolbar/toolbarview~ToolbarView#element}\n * is available.\n *\n * @readonly\n * @member {Function} #render\n * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar being rendered.\n */\n /**\n * A method called after the toolbar has been {@link module:ui/toolbar/toolbarview~ToolbarView#destroy destroyed}.\n * It allows cleaning up after the toolbar behavior, for instance, this is the right place to detach\n * event listeners, free up references, etc.\n *\n * @readonly\n * @member {Function} #destroy\n */","/**\n * @license Copyright (c) 2003-2020, 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 ui/bindings/preventdefault\n */\n\n/**\n * A helper which executes a native `Event.preventDefault()` if the target of an event equals the\n * {@link module:ui/view~View#element element of the view}. It shortens the definition of a\n * {@link module:ui/view~View#template template}.\n *\n *\t\t// In a class extending View.\n *\t\timport preventDefault from '@ckeditor/ckeditor5-ui/src/bindings/preventdefault';\n *\n *\t\t// ...\n *\n *\t\tthis.setTemplate( {\n *\t\t\ttag: 'div',\n *\n *\t\t\ton: {\n *\t\t\t\t// Prevent the default mousedown action on this view.\n *\t\t\t\tmousedown: preventDefault( this )\n *\t\t\t}\n *\t\t} );\n *\n * @param {module:ui/view~View} view View instance that defines the template.\n * @returns {module:ui/template~TemplateToBinding}\n */\nexport default function preventDefault( view ) {\n\treturn view.bindTemplate.to( evt => {\n\t\tif ( evt.target === view.element ) {\n\t\t\tevt.preventDefault();\n\t\t}\n\t} );\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><circle cx=\\\"9.5\\\" cy=\\\"4.5\\\" r=\\\"1.5\\\"/><circle cx=\\\"9.5\\\" cy=\\\"10.5\\\" r=\\\"1.5\\\"/><circle cx=\\\"9.5\\\" cy=\\\"16.5\\\" r=\\\"1.5\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 editor-classic/classiceditoruiview\n */\n\nimport BoxedEditorUIView from '@ckeditor/ckeditor5-ui/src/editorui/boxed/boxededitoruiview';\nimport InlineEditableUIView from '@ckeditor/ckeditor5-ui/src/editableui/inline/inlineeditableuiview';\nimport StickyPanelView from '@ckeditor/ckeditor5-ui/src/panel/sticky/stickypanelview';\nimport ToolbarView from '@ckeditor/ckeditor5-ui/src/toolbar/toolbarview';\n\nimport '../theme/classiceditor.css';\n\n/**\n * Classic editor UI view. Uses an inline editable and a sticky toolbar, all\n * enclosed in a boxed UI view.\n *\n * @extends module:ui/editorui/boxed/boxededitoruiview~BoxedEditorUIView\n */\nexport default class ClassicEditorUIView extends BoxedEditorUIView {\n\t/**\n\t * Creates an instance of the classic editor UI view.\n\t *\n\t * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.\n\t * @param {module:engine/view/view~View} editingView The editing view instance this view is related to.\n\t * @param {Object} [options={}] Configuration options fo the view instance.\n\t * @param {Boolean} [options.shouldToolbarGroupWhenFull] When set `true` enables automatic items grouping\n\t * in the main {@link module:editor-classic/classiceditoruiview~ClassicEditorUIView#toolbar toolbar}.\n\t * See {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull} to learn more.\n\t */\n\tconstructor( locale, editingView, options = {} ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Sticky panel view instance. This is a parent view of a {@link #toolbar}\n\t\t * that makes toolbar sticky.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/panel/sticky/stickypanelview~StickyPanelView}\n\t\t */\n\t\tthis.stickyPanel = new StickyPanelView( locale );\n\n\t\t/**\n\t\t * Toolbar view instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarView}\n\t\t */\n\t\tthis.toolbar = new ToolbarView( locale, {\n\t\t\tshouldGroupWhenFull: options.shouldToolbarGroupWhenFull\n\t\t} );\n\n\t\t/**\n\t\t * Editable UI view.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/editableui/inline/inlineeditableuiview~InlineEditableUIView}\n\t\t */\n\t\tthis.editable = new InlineEditableUIView( locale, editingView );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Set toolbar as a child of a stickyPanel and makes toolbar sticky.\n\t\tthis.stickyPanel.content.add( this.toolbar );\n\n\t\tthis.top.add( this.stickyPanel );\n\t\tthis.main.add( this.editable );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 editor-classic/classiceditor\n */\n\nimport Editor from '@ckeditor/ckeditor5-core/src/editor/editor';\nimport DataApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/dataapimixin';\nimport ElementApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/elementapimixin';\nimport attachToForm from '@ckeditor/ckeditor5-core/src/editor/utils/attachtoform';\nimport HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';\nimport ClassicEditorUI from './classiceditorui';\nimport ClassicEditorUIView from './classiceditoruiview';\nimport getDataFromElement from '@ckeditor/ckeditor5-utils/src/dom/getdatafromelement';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { isElement } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * The {@glink builds/guides/overview#classic-editor classic editor} implementation.\n * It uses an inline editable and a sticky toolbar, all enclosed in a boxed UI.\n * See the {@glink examples/builds/classic-editor demo}.\n *\n * In order to create a classic editor instance, use the static\n * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`} method.\n *\n * # Classic editor and classic build\n *\n * The classic editor can be used directly from source (if you installed the\n * [`@ckeditor/ckeditor5-editor-classic`](https://www.npmjs.com/package/@ckeditor/ckeditor5-editor-classic) package)\n * but it is also available in the {@glink builds/guides/overview#classic-editor classic build}.\n *\n * {@glink builds/guides/overview Builds} are ready-to-use editors with plugins bundled in. When using the editor from\n * source you need to take care of loading all plugins by yourself\n * (through the {@link module:core/editor/editorconfig~EditorConfig#plugins `config.plugins`} option).\n * Using the editor from source gives much better flexibility and allows easier customization.\n *\n * Read more about initializing the editor from source or as a build in\n * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`}.\n *\n * @mixes module:core/editor/utils/dataapimixin~DataApiMixin\n * @mixes module:core/editor/utils/elementapimixin~ElementApiMixin\n * @implements module:core/editor/editorwithui~EditorWithUI\n * @extends module:core/editor/editor~Editor\n */\nexport default class ClassicEditor extends Editor {\n\t/**\n\t * Creates an instance of the classic editor.\n\t *\n\t * **Note:** do not use the constructor to create editor instances. Use the static\n\t * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`} method instead.\n\t *\n\t * @protected\n\t * @param {HTMLElement|String} sourceElementOrData The DOM element that will be the source for the created editor\n\t * or the editor's initial data. For more information see\n\t * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`}.\n\t * @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.\n\t */\n\tconstructor( sourceElementOrData, config ) {\n\t\tsuper( config );\n\n\t\tif ( isElement( sourceElementOrData ) ) {\n\t\t\tthis.sourceElement = sourceElementOrData;\n\t\t}\n\n\t\tthis.data.processor = new HtmlDataProcessor();\n\n\t\tthis.model.document.createRoot();\n\n\t\tconst shouldToolbarGroupWhenFull = !this.config.get( 'toolbar.shouldNotGroupWhenFull' );\n\t\tconst view = new ClassicEditorUIView( this.locale, this.editing.view, {\n\t\t\tshouldToolbarGroupWhenFull\n\t\t} );\n\n\t\tthis.ui = new ClassicEditorUI( this, view );\n\n\t\tattachToForm( this );\n\t}\n\n\t/**\n\t * Destroys the editor instance, releasing all resources used by it.\n\t *\n\t * Updates the editor's source element with the data.\n\t *\n\t * @returns {Promise}\n\t */\n\tdestroy() {\n\t\tif ( this.sourceElement ) {\n\t\t\tthis.updateSourceElement();\n\t\t}\n\n\t\tthis.ui.destroy();\n\n\t\treturn super.destroy();\n\t}\n\n\t/**\n\t * Creates a new classic editor instance.\n\t *\n\t * There are three ways how the editor can be initialized.\n\t *\n\t * # Replacing a DOM element (and loading data from it)\n\t *\n\t * You can initialize the editor using an existing DOM element:\n\t *\n\t *\t\tClassicEditor\n\t *\t\t\t.create( document.querySelector( '#editor' ) )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\t\t\t} )\n\t *\t\t\t.catch( err => {\n\t *\t\t\t\tconsole.error( err.stack );\n\t *\t\t\t} );\n\t *\n\t * The element's content will be used as the editor data and the element will be replaced by the editor UI.\n\t *\n\t * # Creating a detached editor\n\t *\n\t * Alternatively, you can initialize the editor by passing the initial data directly as a string.\n\t * In this case, the editor will render an element that must be inserted into the DOM:\n\t *\n\t *\t\tClassicEditor\n\t *\t\t\t.create( '<p>Hello world!</p>' )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\n\t *\t\t\t\t// Initial data was provided so the editor UI element needs to be added manually to the DOM.\n\t *\t\t\t\tdocument.body.appendChild( editor.ui.element );\n\t *\t\t\t} )\n\t *\t\t\t.catch( err => {\n\t *\t\t\t\tconsole.error( err.stack );\n\t *\t\t\t} );\n\t *\n\t * This lets you dynamically append the editor to your web page whenever it is convenient for you. You may use this method if your\n\t * web page content is generated on the client side and the DOM structure is not ready at the moment when you initialize the editor.\n\t *\n\t * # Replacing a DOM element (and data provided in `config.initialData`)\n\t *\n\t * You can also mix these two ways by providing a DOM element to be used and passing the initial data through the configuration:\n\t *\n\t *\t\tClassicEditor\n\t *\t\t\t.create( document.querySelector( '#editor' ), {\n\t *\t\t\t\tinitialData: '<h2>Initial data</h2><p>Foo bar.</p>'\n\t *\t\t\t} )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\t\t\t} )\n\t *\t\t\t.catch( err => {\n\t *\t\t\t\tconsole.error( err.stack );\n\t *\t\t\t} );\n\t *\n\t * This method can be used to initialize the editor on an existing element with the specified content in case if your integration\n\t * makes it difficult to set the content of the source element.\n\t *\n\t * Note that an error will be thrown if you pass the initial data both as the first parameter and also in the configuration.\n\t *\n\t * # Configuring the editor\n\t *\n\t * See the {@link module:core/editor/editorconfig~EditorConfig editor configuration documentation} to learn more about\n\t * customizing plugins, toolbar and more.\n\t *\n\t * # Using the editor from source\n\t *\n\t * The code samples listed in the previous sections of this documentation assume that you are using an\n\t * {@glink builds/guides/overview editor build} (for example – `@ckeditor/ckeditor5-build-classic`).\n\t *\n\t * If you want to use the classic editor from source (`@ckeditor/ckeditor5-editor-classic/src/classiceditor`),\n\t * you need to define the list of\n\t * {@link module:core/editor/editorconfig~EditorConfig#plugins plugins to be initialized} and\n\t * {@link module:core/editor/editorconfig~EditorConfig#toolbar toolbar items}. Read more about using the editor from\n\t * source in the {@glink builds/guides/integration/advanced-setup \"Advanced setup\" guide}.\n\t *\n\t * @param {HTMLElement|String} sourceElementOrData The DOM element that will be the source for the created editor\n\t * or the editor's initial data.\n\t *\n\t * If a DOM element is passed, its content will be automatically loaded to the editor upon initialization\n\t * and the {@link module:editor-classic/classiceditorui~ClassicEditorUI#element editor element} will replace the passed element\n\t * in the DOM (the original one will be hidden and the editor will be injected next to it).\n\t *\n\t * Moreover, the editor data will be set back to the original element once the editor is destroyed and when a form, in which\n\t * this element is contained, is submitted (if the original element is a `<textarea>`). This ensures seamless integration with native\n\t * web forms.\n\t *\n\t * If the initial data is passed, a detached editor will be created. In this case you need to insert it into the DOM manually.\n\t * It is available under the {@link module:editor-classic/classiceditorui~ClassicEditorUI#element `editor.ui.element`} property.\n\t *\n\t * @param {module:core/editor/editorconfig~EditorConfig} [config] The editor configuration.\n\t * @returns {Promise} A promise resolved once the editor is ready. The promise resolves with the created editor instance.\n\t */\n\tstatic create( sourceElementOrData, config = {} ) {\n\t\treturn new Promise( resolve => {\n\t\t\tconst editor = new this( sourceElementOrData, config );\n\n\t\t\tresolve(\n\t\t\t\teditor.initPlugins()\n\t\t\t\t\t.then( () => editor.ui.init( isElement( sourceElementOrData ) ? sourceElementOrData : null ) )\n\t\t\t\t\t.then( () => {\n\t\t\t\t\t\tif ( !isElement( sourceElementOrData ) && config.initialData ) {\n\t\t\t\t\t\t\t// Documented in core/editor/editorconfig.jdoc.\n\t\t\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t\t\t'editor-create-initial-data: ' +\n\t\t\t\t\t\t\t\t'The config.initialData option cannot be used together with initial data passed in Editor.create().',\n\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst initialData = config.initialData || getInitialData( sourceElementOrData );\n\n\t\t\t\t\t\treturn editor.data.init( initialData );\n\t\t\t\t\t} )\n\t\t\t\t\t.then( () => editor.fire( 'ready' ) )\n\t\t\t\t\t.then( () => editor )\n\t\t\t);\n\t\t} );\n\t}\n}\n\nmix( ClassicEditor, DataApiMixin );\nmix( ClassicEditor, ElementApiMixin );\n\nfunction getInitialData( sourceElementOrData ) {\n\treturn isElement( sourceElementOrData ) ? getDataFromElement( sourceElementOrData ) : sourceElementOrData;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport { isFunction } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * @module core/editor/utils/attachtoform\n */\n\n/**\n * Checks if the editor is initialized on a `<textarea>` element that belongs to a form. If yes, it updates the editor's element\n * content before submitting the form.\n *\n * This helper requires the {@link module:core/editor/utils/elementapimixin~ElementApi ElementApi interface}.\n *\n * @param {module:core/editor/editor~Editor} editor Editor instance.\n */\nexport default function attachToForm( editor ) {\n\tif ( !isFunction( editor.updateSourceElement ) ) {\n\t\t/**\n\t\t * The editor passed to `attachToForm()` must implement the\n\t\t * {@link module:core/editor/utils/elementapimixin~ElementApi} interface.\n\t\t *\n\t\t * @error attachtoform-missing-elementapi-interface\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'attachtoform-missing-elementapi-interface: Editor passed to attachToForm() must implement ElementApi.',\n\t\t\teditor\n\t\t);\n\t}\n\n\tconst sourceElement = editor.sourceElement;\n\n\t// Only when replacing a textarea which is inside of a form element.\n\tif ( sourceElement && sourceElement.tagName.toLowerCase() === 'textarea' && sourceElement.form ) {\n\t\tlet originalSubmit;\n\t\tconst form = sourceElement.form;\n\t\tconst onSubmit = () => editor.updateSourceElement();\n\n\t\t// Replace the original form#submit() to call a custom submit function first.\n\t\t// Check if #submit is a function because the form might have an input named \"submit\".\n\t\tif ( isFunction( form.submit ) ) {\n\t\t\toriginalSubmit = form.submit;\n\n\t\t\tform.submit = () => {\n\t\t\t\tonSubmit();\n\t\t\t\toriginalSubmit.apply( form );\n\t\t\t};\n\t\t}\n\n\t\t// Update the replaced textarea with data before each form#submit event.\n\t\tform.addEventListener( 'submit', onSubmit );\n\n\t\t// Remove the submit listener and revert the original submit method on\n\t\t// editor#destroy.\n\t\teditor.on( 'destroy', () => {\n\t\t\tform.removeEventListener( 'submit', onSubmit );\n\n\t\t\tif ( originalSubmit ) {\n\t\t\t\tform.submit = originalSubmit;\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals HTMLTextAreaElement */\n\n/**\n * @module utils/dom/getdatafromelement\n */\n\n/**\n * Gets data from a given source element.\n *\n * @param {HTMLElement} el The element from which the data will be retrieved.\n * @returns {String} The data string.\n */\nexport default function getDataFromElement( el ) {\n\tif ( el instanceof HTMLTextAreaElement ) {\n\t\treturn el.value;\n\t}\n\n\treturn el.innerHTML;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 core/plugin\n */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The base class for CKEditor plugin classes.\n *\n * @implements module:core/plugin~PluginInterface\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor instance.\n\t\t *\n\t\t * Note that most editors implement the {@link module:core/editor/editorwithui~EditorWithUI} interface in addition\n\t\t * to the base {@link module:core/editor/editor~Editor} interface. However, editors with an external UI\n\t\t * (i.e. Bootstrap-based) or a headless editor may not implement the {@link module:core/editor/editorwithui~EditorWithUI}\n\t\t * interface.\n\t\t *\n\t\t * Because of above, to make plugins more universal, it is recommended to split features into:\n\t\t * - The \"editing\" part that only uses the {@link module:core/editor/editor~Editor} interface.\n\t\t * - The \"UI\" part that uses both the {@link module:core/editor/editor~Editor} interface and\n\t\t * the {@link module:core/editor/editorwithui~EditorWithUI} interface.\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 * Flag indicating whether a plugin is enabled or disabled.\n\t\t * A disabled plugin will not transform text.\n\t\t *\n\t\t * Plugin can be simply disabled like that:\n\t\t *\n\t\t *\t\t// Disable the plugin so that no toolbars are visible.\n\t\t *\t\teditor.plugins.get( 'TextTransformation' ).isEnabled = false;\n\t\t *\n\t\t * You can also use {@link #forceDisabled} method.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', true );\n\n\t\t/**\n\t\t * Holds identifiers for {@link #forceDisabled} mechanism.\n\t\t *\n\t\t * @type {Set.<String>}\n\t\t * @private\n\t\t */\n\t\tthis._disableStack = new Set();\n\t}\n\n\t/**\n\t * Disables the plugin.\n\t *\n\t * Plugin may be disabled by multiple features or algorithms (at once). When disabling a plugin, unique id should be passed\n\t * (e.g. feature name). The same identifier should be used when {@link #clearForceDisabled enabling back} the plugin.\n\t * The plugin becomes enabled only after all features {@link #clearForceDisabled enabled it back}.\n\t *\n\t * Disabling and enabling a plugin:\n\t *\n\t *\t\tplugin.isEnabled; // -> true\n\t *\t\tplugin.forceDisabled( 'MyFeature' );\n\t *\t\tplugin.isEnabled; // -> false\n\t *\t\tplugin.clearForceDisabled( 'MyFeature' );\n\t *\t\tplugin.isEnabled; // -> true\n\t *\n\t * Plugin disabled by multiple features:\n\t *\n\t *\t\tplugin.forceDisabled( 'MyFeature' );\n\t *\t\tplugin.forceDisabled( 'OtherFeature' );\n\t *\t\tplugin.clearForceDisabled( 'MyFeature' );\n\t *\t\tplugin.isEnabled; // -> false\n\t *\t\tplugin.clearForceDisabled( 'OtherFeature' );\n\t *\t\tplugin.isEnabled; // -> true\n\t *\n\t * Multiple disabling with the same identifier is redundant:\n\t *\n\t *\t\tplugin.forceDisabled( 'MyFeature' );\n\t *\t\tplugin.forceDisabled( 'MyFeature' );\n\t *\t\tplugin.clearForceDisabled( 'MyFeature' );\n\t *\t\tplugin.isEnabled; // -> true\n\t *\n\t * **Note:** some plugins or algorithms may have more complex logic when it comes to enabling or disabling certain plugins,\n\t * so the plugin might be still disabled after {@link #clearForceDisabled} was used.\n\t *\n\t * @param {String} id Unique identifier for disabling. Use the same id when {@link #clearForceDisabled enabling back} the plugin.\n\t */\n\tforceDisabled( id ) {\n\t\tthis._disableStack.add( id );\n\n\t\tif ( this._disableStack.size == 1 ) {\n\t\t\tthis.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );\n\t\t\tthis.isEnabled = false;\n\t\t}\n\t}\n\n\t/**\n\t * Clears forced disable previously set through {@link #forceDisabled}. See {@link #forceDisabled}.\n\t *\n\t * @param {String} id Unique identifier, equal to the one passed in {@link #forceDisabled} call.\n\t */\n\tclearForceDisabled( id ) {\n\t\tthis._disableStack.delete( id );\n\n\t\tif ( this._disableStack.size == 0 ) {\n\t\t\tthis.off( 'set:isEnabled', forceDisable );\n\t\t\tthis.isEnabled = true;\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get isContextPlugin() {\n\t\treturn false;\n\t}\n}\n\nmix( Plugin, ObservableMixin );\n\n/**\n * The base interface for CKEditor plugins.\n *\n * In its minimal form a plugin can be a simple function that accepts {@link module:core/editor/editor~Editor the editor}\n * as a parameter:\n *\n *\t\t// A simple plugin that enables a data processor.\n *\t\tfunction MyPlugin( editor ) {\n *\t\t\teditor.data.processor = new MyDataProcessor();\n *\t\t}\n *\n * In most cases however, you will want to inherit from the {@link module:core/plugin~Plugin} class which implements the\n * {@link module:utils/observablemixin~ObservableMixin} and is, therefore, more convenient:\n *\n *\t\tclass MyPlugin extends Plugin {\n *\t\t\tinit() {\n *\t\t\t\t// `listenTo()` and `editor` are available thanks to `Plugin`.\n *\t\t\t\t// By using `listenTo()` you will ensure that the listener is removed when\n *\t\t\t\t// the plugin is destroyed.\n *\t\t\t\tthis.listenTo( this.editor.data, 'ready', () => {\n *\t\t\t\t\t// Do something when the data is ready.\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n *\n * The plugin can also implement methods (e.g. {@link module:core/plugin~PluginInterface#init `init()`} or\n * {@link module:core/plugin~PluginInterface#destroy `destroy()`}) which, when present, will be used to properly\n * initialize and destroy the plugin.\n *\n * **Note:** When defined as a plain function, the plugin acts as a constructor and will be\n * called in parallel with other plugins' {@link module:core/plugin~PluginInterface#constructor constructors}.\n * This means the code of that plugin will be executed **before** {@link module:core/plugin~PluginInterface#init `init()`} and\n * {@link module:core/plugin~PluginInterface#afterInit `afterInit()`} methods of other plugins and, for instance,\n * you cannot use it to extend other plugins' {@glink framework/guides/architecture/editing-engine#schema schema}\n * rules as they are defined later on during the `init()` stage.\n *\n * @interface PluginInterface\n */\n\n/**\n * Creates a new plugin instance. This is the first step of the plugin initialization.\n * See also {@link #init} and {@link #afterInit}.\n *\n * A plugin is always instantiated after its {@link module:core/plugin~PluginInterface.requires dependencies} and the\n * {@link #init} and {@link #afterInit} methods are called in the same order.\n *\n * Usually, you will want to put your plugin's initialization code in the {@link #init} method.\n * The constructor can be understood as \"before init\" and used in special cases, just like\n * {@link #afterInit} serves the special \"after init\" scenarios (e.g.the code which depends on other\n * plugins, but which does not {@link module:core/plugin~PluginInterface.requires explicitly require} them).\n *\n * @method #constructor\n * @param {module:core/editor/editor~Editor} editor\n */\n\n/**\n * An array of plugins required by this plugin.\n *\n * To keep the plugin class definition tight it is recommended to define this property as a static getter:\n *\n *\t\timport Image from './image.js';\n *\n *\t\texport default class ImageCaption {\n *\t\t\tstatic get requires() {\n *\t\t\t\treturn [ Image ];\n *\t\t\t}\n *\t\t}\n *\n * @static\n * @readonly\n * @member {Array.<Function>|undefined} module:core/plugin~PluginInterface.requires\n */\n\n/**\n * An optional name of the plugin. If set, the plugin will be available in\n * {@link module:core/plugincollection~PluginCollection#get} by its\n * name and its constructor. If not, then only by its constructor.\n *\n * The name should reflect the constructor name.\n *\n * To keep the plugin class definition tight, it is recommended to define this property as a static getter:\n *\n *\t\texport default class ImageCaption {\n *\t\t\tstatic get pluginName() {\n *\t\t\t\treturn 'ImageCaption';\n *\t\t\t}\n *\t\t}\n *\n * Note: The native `Function.name` property could not be used to keep the plugin name because\n * it will be mangled during code minification.\n *\n * Naming a plugin is necessary to enable removing it through the\n * {@link module:core/editor/editorconfig~EditorConfig#removePlugins `config.removePlugins`} option.\n *\n * @static\n * @readonly\n * @member {String|undefined} module:core/plugin~PluginInterface.pluginName\n */\n\n/**\n * The second stage (after plugin {@link #constructor}) of the plugin initialization.\n * Unlike the plugin constructor this method can be asynchronous.\n *\n * A plugin's `init()` method is called after its {@link module:core/plugin~PluginInterface.requires dependencies} are initialized,\n * so in the same order as the constructors of these plugins.\n *\n * **Note:** This method is optional. A plugin instance does not need to have it defined.\n *\n * @method #init\n * @returns {null|Promise}\n */\n\n/**\n * The third (and last) stage of the plugin initialization. See also {@link #constructor} and {@link #init}.\n *\n * **Note:** This method is optional. A plugin instance does not need to have it defined.\n *\n * @method #afterInit\n * @returns {null|Promise}\n */\n\n/**\n * Destroys the plugin.\n *\n * **Note:** This method is optional. A plugin instance does not need to have it defined.\n *\n * @method #destroy\n * @returns {null|Promise}\n */\n\n/**\n * A flag which defines if a plugin is allowed or not allowed to be used directly by a {@link module:core/context~Context}.\n *\n * @static\n * @readonly\n * @member {Boolean} module:core/plugin~PluginInterface.isContextPlugin\n */\n\n/**\n * An array of loaded plugins.\n *\n * @typedef {Array.<module:core/plugin~PluginInterface>} module:core/plugin~LoadedPlugins\n */\n\n// Helper function that forces plugin to be disabled.\nfunction forceDisable( evt ) {\n\tevt.return = false;\n\tevt.stop();\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 clipboard/datatransfer\n */\n\n/**\n * Facade over the native [`DataTransfer`](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer) object.\n */\nexport default class DataTransfer {\n\tconstructor( nativeDataTransfer ) {\n\t\t/**\n\t\t * The array of files created from the native `DataTransfer#files` or `DataTransfer#items`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<File>} #files\n\t\t */\n\t\tthis.files = getFiles( nativeDataTransfer );\n\n\t\t/**\n\t\t * The native DataTransfer object.\n\t\t *\n\t\t * @private\n\t\t * @member {DataTransfer} #_native\n\t\t */\n\t\tthis._native = nativeDataTransfer;\n\t}\n\n\t/**\n\t * Returns an array of available native content types.\n\t *\n\t * @returns {Array.<String>}\n\t */\n\tget types() {\n\t\treturn this._native.types;\n\t}\n\n\t/**\n\t * Gets data from the data transfer by its mime type.\n\t *\n\t *\t\tdataTransfer.getData( 'text/plain' );\n\t *\n\t * @param {String} type The mime type. E.g. `text/html` or `text/plain`.\n\t * @returns {String}\n\t */\n\tgetData( type ) {\n\t\treturn this._native.getData( type );\n\t}\n\n\t/**\n\t * Sets data in the data transfer.\n\t *\n\t * @param {String} type The mime type. E.g. `text/html` or `text/plain`.\n\t * @param {String} data\n\t */\n\tsetData( type, data ) {\n\t\tthis._native.setData( type, data );\n\t}\n}\n\nfunction getFiles( nativeDataTransfer ) {\n\t// DataTransfer.files and items are Array-like and might not have an iterable interface.\n\tconst files = nativeDataTransfer.files ? Array.from( nativeDataTransfer.files ) : [];\n\tconst items = nativeDataTransfer.items ? Array.from( nativeDataTransfer.items ) : [];\n\n\tif ( files.length ) {\n\t\treturn files;\n\t}\n\t// Chrome have empty DataTransfer.files, but let get files through the items interface.\n\treturn items\n\t\t.filter( item => item.kind === 'file' )\n\t\t.map( item => item.getAsFile() );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 clipboard/clipboardobserver\n */\n\nimport DomEventObserver from '@ckeditor/ckeditor5-engine/src/view/observer/domeventobserver';\nimport EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo';\nimport DataTransfer from './datatransfer';\n\n/**\n * Clipboard events observer.\n *\n * Fires the following events:\n *\n * * {@link module:engine/view/document~Document#event:clipboardInput}\n * * {@link module:engine/view/document~Document#event:dragover}\n * * {@link module:engine/view/document~Document#event:drop}\n * * {@link module:engine/view/document~Document#event:paste}\n * * {@link module:engine/view/document~Document#event:copy}\n * * {@link module:engine/view/document~Document#event:cut}\n *\n * Note that this observer is not available by default (it is not added by the engine).\n * To make it available it needs to be added to {@link module:engine/view/document~Document} by\n * the {@link module:engine/view/view~View#addObserver `View#addObserver()`} method. You can also load the\n * {@link module:clipboard/clipboard~Clipboard} plugin which adds this observer automatically (because it uses it).\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class ClipboardObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tconst viewDocument = this.document;\n\n\t\tthis.domEventType = [ 'paste', 'copy', 'cut', 'drop', 'dragover' ];\n\n\t\tthis.listenTo( viewDocument, 'paste', handleInput, { priority: 'low' } );\n\t\tthis.listenTo( viewDocument, 'drop', handleInput, { priority: 'low' } );\n\n\t\tfunction handleInput( evt, data ) {\n\t\t\tdata.preventDefault();\n\n\t\t\tconst targetRanges = data.dropRange ? [ data.dropRange ] : Array.from( viewDocument.selection.getRanges() );\n\n\t\t\tconst eventInfo = new EventInfo( viewDocument, 'clipboardInput' );\n\n\t\t\tviewDocument.fire( eventInfo, {\n\t\t\t\tdataTransfer: data.dataTransfer,\n\t\t\t\ttargetRanges\n\t\t\t} );\n\n\t\t\t// If CKEditor handled the input, do not bubble the original event any further.\n\t\t\t// This helps external integrations recognize that fact and act accordingly.\n\t\t\t// https://github.com/ckeditor/ckeditor5-upload/issues/92\n\t\t\tif ( eventInfo.stop.called ) {\n\t\t\t\tdata.stopPropagation();\n\t\t\t}\n\t\t}\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tconst evtData = {\n\t\t\tdataTransfer: new DataTransfer( domEvent.clipboardData ? domEvent.clipboardData : domEvent.dataTransfer )\n\t\t};\n\n\t\tif ( domEvent.type == 'drop' ) {\n\t\t\tevtData.dropRange = getDropViewRange( this.view, domEvent );\n\t\t}\n\n\t\tthis.fire( domEvent.type, domEvent, evtData );\n\t}\n}\n\nfunction getDropViewRange( view, domEvent ) {\n\tconst domDoc = domEvent.target.ownerDocument;\n\tconst x = domEvent.clientX;\n\tconst y = domEvent.clientY;\n\tlet domRange;\n\n\t// Webkit & Blink.\n\tif ( domDoc.caretRangeFromPoint && domDoc.caretRangeFromPoint( x, y ) ) {\n\t\tdomRange = domDoc.caretRangeFromPoint( x, y );\n\t}\n\t// FF.\n\telse if ( domEvent.rangeParent ) {\n\t\tdomRange = domDoc.createRange();\n\t\tdomRange.setStart( domEvent.rangeParent, domEvent.rangeOffset );\n\t\tdomRange.collapse( true );\n\t}\n\n\tif ( domRange ) {\n\t\treturn view.domConverter.domRangeToView( domRange );\n\t} else {\n\t\treturn view.document.selection.getFirstRange();\n\t}\n}\n\n/**\n * Fired as a continuation of {@link #event:paste} and {@link #event:drop} events.\n *\n * It is a part of the {@glink framework/guides/deep-dive/clipboard#input-pipeline \"clipboard input pipeline\"}.\n *\n * Fired with a `dataTransfer` which comes from the clipboard and which content should be processed\n * and inserted into the editor.\n *\n * Note that this event is not available by default. To make it available {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method.\n * It's done by the {@link module:clipboard/clipboard~Clipboard} feature. If it's not loaded, it must be done manually.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @see module:clipboard/clipboard~Clipboard\n * @event module:engine/view/document~Document#event:clipboardInput\n * @param {Object} data Event data.\n * @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer Data transfer instance.\n * @param {Array.<module:engine/view/range~Range>} data.targetRanges Ranges which are the target of the operation\n * (usually – into which the content should be inserted).\n * If clipboard input was triggered by a paste operation, then these are the selection ranges. If by a drop operation,\n * then it's the drop position (which can be different than the selection at the moment of drop).\n */\n\n/**\n * Fired when user drags content over one of the editables.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * Note that this event is not available by default. To make it available {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method.\n * It's done by the {@link module:clipboard/clipboard~Clipboard} feature. If it's not loaded, it must be done manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:dragover\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data Event data.\n */\n\n/**\n * Fired when user dropped content into one of the editables.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * Note that this event is not available by default. To make it available {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method.\n * It's done by the {@link module:clipboard/clipboard~Clipboard} feature. If it's not loaded, it must be done manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:drop\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data Event data.\n * @param {module:engine/view/range~Range} dropRange The position into which the content is dropped.\n */\n\n/**\n * Fired when user pasted content into one of the editables.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * Note that this event is not available by default. To make it available {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method.\n * It's done by the {@link module:clipboard/clipboard~Clipboard} feature. If it's not loaded, it must be done manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:paste\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data Event data.\n */\n\n/**\n * Fired when user copied content from one of the editables.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * Note that this event is not available by default. To make it available {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method.\n * It's done by the {@link module:clipboard/clipboard~Clipboard} feature. If it's not loaded, it must be done manually.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @event module:engine/view/document~Document#event:copy\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data Event data.\n */\n\n/**\n * Fired when user cut content from one of the editables.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * Note that this event is not available by default. To make it available {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method.\n * It's done by the {@link module:clipboard/clipboard~Clipboard} feature. If it's not loaded, it must be done manually.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @event module:engine/view/document~Document#event:cut\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data Event data.\n */\n\n/**\n * The value of the {@link module:engine/view/document~Document#event:paste},\n * {@link module:engine/view/document~Document#event:copy} and {@link module:engine/view/document~Document#event:cut} events.\n *\n * In order to access clipboard data use `dataTransfer` property.\n *\n * @class module:clipboard/clipboardobserver~ClipboardEventData\n * @extends module:engine/view/observer/domeventdata~DomEventData\n */\n\n/**\n * Data transfer instance.\n *\n * @readonly\n * @member {module:clipboard/datatransfer~DataTransfer} module:clipboard/clipboardobserver~ClipboardEventData#dataTransfer\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 clipboard/utils/viewtoplaintext\n */\n\n// Elements which should not have empty-line padding.\n// Most `view.ContainerElement` want to be separate by new-line, but some are creating one structure\n// together (like `<li>`) so it is better to separate them by only one \"\\n\".\nconst smallPaddingElements = [ 'figcaption', 'li' ];\n\n/**\n * Converts {@link module:engine/view/item~Item view item} and all of its children to plain text.\n *\n * @param {module:engine/view/item~Item} viewItem View item to convert.\n * @returns {String} Plain text representation of `viewItem`.\n */\nexport default function viewToPlainText( viewItem ) {\n\tlet text = '';\n\n\tif ( viewItem.is( 'text' ) || viewItem.is( 'textProxy' ) ) {\n\t\t// If item is `Text` or `TextProxy` simple take its text data.\n\t\ttext = viewItem.data;\n\t} else if ( viewItem.is( 'img' ) && viewItem.hasAttribute( 'alt' ) ) {\n\t\t// Special case for images - use alt attribute if it is provided.\n\t\ttext = viewItem.getAttribute( 'alt' );\n\t} else {\n\t\t// Other elements are document fragments, attribute elements or container elements.\n\t\t// They don't have their own text value, so convert their children.\n\t\tlet prev = null;\n\n\t\tfor ( const child of viewItem.getChildren() ) {\n\t\t\tconst childText = viewToPlainText( child );\n\n\t\t\t// Separate container element children with one or more new-line characters.\n\t\t\tif ( prev && ( prev.is( 'containerElement' ) || child.is( 'containerElement' ) ) ) {\n\t\t\t\tif ( smallPaddingElements.includes( prev.name ) || smallPaddingElements.includes( child.name ) ) {\n\t\t\t\t\ttext += '\\n';\n\t\t\t\t} else {\n\t\t\t\t\ttext += '\\n\\n';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttext += childText;\n\t\t\tprev = child;\n\t\t}\n\t}\n\n\treturn text;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 clipboard/clipboard\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport ClipboardObserver from './clipboardobserver';\n\nimport plainTextToHtml from './utils/plaintexttohtml';\nimport normalizeClipboardHtml from './utils/normalizeclipboarddata';\nimport viewToPlainText from './utils/viewtoplaintext.js';\n\nimport HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';\n\n/**\n * The clipboard feature. It is responsible for intercepting the `paste` and `drop` events and\n * passing the pasted content through the clipboard pipeline in order to insert it into the editor's content.\n * It also handles the `cut` and `copy` events to fill the native clipboard with serialized editor's data.\n *\n * Read more about the clipboard integration in {@glink framework/guides/deep-dive/clipboard \"Clipboard\" deep dive} guide.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Clipboard extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Clipboard';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst modelDocument = editor.model.document;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t/**\n\t\t * Data processor used to convert pasted HTML to a view structure.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/dataprocessor/htmldataprocessor~HtmlDataProcessor} #_htmlDataProcessor\n\t\t */\n\t\tthis._htmlDataProcessor = new HtmlDataProcessor();\n\n\t\tview.addObserver( ClipboardObserver );\n\n\t\t// The clipboard paste pipeline.\n\n\t\t// Pasting and dropping is disabled when editor is read-only.\n\t\t// See: https://github.com/ckeditor/ckeditor5-clipboard/issues/26.\n\t\tthis.listenTo( viewDocument, 'clipboardInput', evt => {\n\t\t\tif ( editor.isReadOnly ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.listenTo( viewDocument, 'clipboardInput', ( evt, data ) => {\n\t\t\tconst dataTransfer = data.dataTransfer;\n\t\t\tlet content = '';\n\n\t\t\tif ( dataTransfer.getData( 'text/html' ) ) {\n\t\t\t\tcontent = normalizeClipboardHtml( dataTransfer.getData( 'text/html' ) );\n\t\t\t} else if ( dataTransfer.getData( 'text/plain' ) ) {\n\t\t\t\tcontent = plainTextToHtml( dataTransfer.getData( 'text/plain' ) );\n\t\t\t}\n\n\t\t\tcontent = this._htmlDataProcessor.toView( content );\n\n\t\t\tthis.fire( 'inputTransformation', { content, dataTransfer } );\n\n\t\t\tview.scrollToTheSelection();\n\t\t}, { priority: 'low' } );\n\n\t\tthis.listenTo( this, 'inputTransformation', ( evt, data ) => {\n\t\t\tif ( !data.content.isEmpty ) {\n\t\t\t\tconst dataController = this.editor.data;\n\t\t\t\tconst model = this.editor.model;\n\n\t\t\t\t// Convert the pasted content to a model document fragment.\n\t\t\t\t// Conversion is contextual, but in this case we need an \"all allowed\" context and for that\n\t\t\t\t// we use the $clipboardHolder item.\n\t\t\t\tconst modelFragment = dataController.toModel( data.content, '$clipboardHolder' );\n\n\t\t\t\tif ( modelFragment.childCount == 0 ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tmodel.insertContent( modelFragment );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\t// The clipboard copy/cut pipeline.\n\n\t\tfunction onCopyCut( evt, data ) {\n\t\t\tconst dataTransfer = data.dataTransfer;\n\n\t\t\tdata.preventDefault();\n\n\t\t\tconst content = editor.data.toView( editor.model.getSelectedContent( modelDocument.selection ) );\n\n\t\t\tviewDocument.fire( 'clipboardOutput', { dataTransfer, content, method: evt.name } );\n\t\t}\n\n\t\tthis.listenTo( viewDocument, 'copy', onCopyCut, { priority: 'low' } );\n\t\tthis.listenTo( viewDocument, 'cut', ( evt, data ) => {\n\t\t\t// Cutting is disabled when editor is read-only.\n\t\t\t// See: https://github.com/ckeditor/ckeditor5-clipboard/issues/26.\n\t\t\tif ( editor.isReadOnly ) {\n\t\t\t\tdata.preventDefault();\n\t\t\t} else {\n\t\t\t\tonCopyCut( evt, data );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\tthis.listenTo( viewDocument, 'clipboardOutput', ( evt, data ) => {\n\t\t\tif ( !data.content.isEmpty ) {\n\t\t\t\tdata.dataTransfer.setData( 'text/html', this._htmlDataProcessor.toData( data.content ) );\n\t\t\t\tdata.dataTransfer.setData( 'text/plain', viewToPlainText( data.content ) );\n\t\t\t}\n\n\t\t\tif ( data.method == 'cut' ) {\n\t\t\t\teditor.model.deleteContent( modelDocument.selection );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\t}\n}\n\n/**\n * Fired with a `content` and `dataTransfer` objects. The `content` which comes from the clipboard (was pasted or dropped)\n * should be processed in order to be inserted into the editor. The `dataTransfer` object is available\n * in case the transformation functions needs access to a raw clipboard data.\n *\n * It is a part of the {@glink framework/guides/deep-dive/clipboard#input-pipeline \"clipboard input pipeline\"}.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @see module:clipboard/clipboard~Clipboard\n * @event module:clipboard/clipboard~Clipboard#event:inputTransformation\n * @param {Object} data Event data.\n * @param {module:engine/view/documentfragment~DocumentFragment} data.content Event data. Content to be inserted into the editor.\n * It can be modified by the event listeners. Read more about the clipboard pipelines in\n * {@glink framework/guides/deep-dive/clipboard \"Clipboard\" deep dive}.\n * @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer Data transfer instance.\n */\n\n/**\n * Fired on {@link module:engine/view/document~Document#event:copy} and {@link module:engine/view/document~Document#event:cut}\n * with a copy of selected content. The content can be processed before it ends up in the clipboard.\n *\n * It is a part of the {@glink framework/guides/deep-dive/clipboard#output-pipeline \"clipboard output pipeline\"}.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @see module:clipboard/clipboard~Clipboard\n * @event module:engine/view/document~Document#event:clipboardOutput\n * @param {module:clipboard/clipboard~ClipboardOutputEventData} data Event data.\n */\n\n/**\n * The value of the {@link module:engine/view/document~Document#event:clipboardOutput} event.\n *\n * @class module:clipboard/clipboard~ClipboardOutputEventData\n */\n\n/**\n * Data transfer instance.\n *\n * @readonly\n * @member {module:clipboard/datatransfer~DataTransfer} module:clipboard/clipboard~ClipboardOutputEventData#dataTransfer\n */\n\n/**\n * Content to be put into the clipboard. It can be modified by the event listeners.\n * Read more about the clipboard pipelines in {@glink framework/guides/deep-dive/clipboard \"Clipboard\" deep dive}.\n *\n * @member {module:engine/view/documentfragment~DocumentFragment} module:clipboard/clipboard~ClipboardOutputEventData#content\n */\n\n/**\n * Whether the event was triggered by copy or cut operation.\n *\n * @member {'copy'|'cut'} module:clipboard/clipboard~ClipboardOutputEventData#method\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 clipboard/utils/plaintexttohtml\n */\n\n/**\n * Converts plain text to its HTML-ized version.\n *\n * @param {String} text The plain text to convert.\n * @returns {String} HTML generated from the plain text.\n */\nexport default function plainTextToHtml( text ) {\n\ttext = text\n\t\t// Encode <>.\n\t\t.replace( /</g, '<' )\n\t\t.replace( />/g, '>' )\n\t\t// Creates paragraphs for every line breaks.\n\t\t.replace( /\\n/g, '</p><p>' )\n\t\t// Preserve trailing spaces (only the first and last one – the rest is handled below).\n\t\t.replace( /^\\s/, ' ' )\n\t\t.replace( /\\s$/, ' ' )\n\t\t// Preserve other subsequent spaces now.\n\t\t.replace( /\\s\\s/g, ' ' );\n\n\tif ( text.indexOf( '</p><p>' ) > -1 ) {\n\t\t// If we created paragraphs above, add the trailing ones.\n\t\ttext = `<p>${ text }</p>`;\n\t}\n\n\t// TODO:\n\t// * What about '\\nfoo' vs ' foo'?\n\n\treturn text;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 clipboard/utils/normalizeclipboarddata\n */\n\n/**\n * Removes some popular browser quirks out of the clipboard data (HTML).\n *\n * @param {String} data The HTML data to normalize.\n * @returns {String} Normalized HTML.\n */\nexport default function normalizeClipboardData( data ) {\n\treturn data\n\t\t.replace( /<span(?: class=\"Apple-converted-space\"|)>(\\s+)<\\/span>/g, ( fullMatch, spaces ) => {\n\t\t\t// Handle the most popular and problematic case when even a single space becomes an nbsp;.\n\t\t\t// Decode those to normal spaces. Read more in https://github.com/ckeditor/ckeditor5-clipboard/issues/2.\n\t\t\tif ( spaces.length == 1 ) {\n\t\t\t\treturn ' ';\n\t\t\t}\n\n\t\t\treturn spaces;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 core/command\n */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The base class for CKEditor commands.\n *\n * Commands are the main way to manipulate editor contents and state. They are mostly used by UI elements (or by other\n * commands) to make changes in the model. Commands are available in every part of code that has access to\n * the {@link module:core/editor/editor~Editor editor} instance.\n *\n * Instances of registered commands can be retrieved from {@link module:core/editor/editor~Editor#commands `editor.commands`}.\n * The easiest way to execute a command is through {@link module:core/editor/editor~Editor#execute `editor.execute()`}.\n *\n * By default commands are disabled when the editor is in {@link module:core/editor/editor~Editor#isReadOnly read-only} mode.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Command {\n\t/**\n\t * Creates a new `Command` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor Editor on which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor on which this command will be used.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * The value of the command. A concrete command class should define what it represents for it.\n\t\t *\n\t\t * For example, the `'bold'` command's value indicates whether the selection starts in a bolded text.\n\t\t * And the value of the `'link'` command may be an object with links details.\n\t\t *\n\t\t * It is possible for a command to have no value (e.g. for stateless actions such as `'imageUpload'`).\n\t\t *\n\t\t * A concrete command class should control this value by overriding the {@link #refresh `refresh()`} method.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member #value\n\t\t */\n\t\tthis.set( 'value', undefined );\n\n\t\t/**\n\t\t * Flag indicating whether a command is enabled or disabled.\n\t\t * A disabled command will do nothing when executed.\n\t\t *\n\t\t * A concrete command class should control this value by overriding the {@link #refresh `refresh()`} method.\n\t\t *\n\t\t * It is possible to disable a command from \"outside\". For instance, in your integration you may want to disable\n\t\t * a certain set of commands for the time being. To do that, you can use the fact that `isEnabled` is observable\n\t\t * and it fires the `set:isEnabled` event every time anyone tries to modify its value:\n\t\t *\n\t\t *\t\tfunction disableCommand( cmd ) {\n\t\t *\t\t\tcmd.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );\n\t\t *\n\t\t *\t\t\tcmd.isEnabled = false;\n\t\t *\n\t\t *\t\t\t// Make it possible to enable the command again.\n\t\t *\t\t\treturn () => {\n\t\t *\t\t\t\tcmd.off( 'set:isEnabled', forceDisable );\n\t\t *\t\t\t\tcmd.refresh();\n\t\t *\t\t\t};\n\t\t *\n\t\t *\t\t\tfunction forceDisable( evt ) {\n\t\t *\t\t\t\tevt.return = false;\n\t\t *\t\t\t\tevt.stop();\n\t\t *\t\t\t}\n\t\t *\t\t}\n\t\t *\n\t\t *\t\t// Usage:\n\t\t *\n\t\t *\t\t// Disabling the command.\n\t\t *\t\tconst enableBold = disableCommand( editor.commands.get( 'bold' ) );\n\t\t *\n\t\t *\t\t// Enabling the command again.\n\t\t *\t\tenableBold();\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', false );\n\n\t\t/**\n\t\t * Holds identifiers for {@link #forceDisabled} mechanism.\n\t\t *\n\t\t * @type {Set.<String>}\n\t\t * @private\n\t\t */\n\t\tthis._disableStack = new Set();\n\n\t\tthis.decorate( 'execute' );\n\n\t\t// By default every command is refreshed when changes are applied to the model.\n\t\tthis.listenTo( this.editor.model.document, 'change', () => {\n\t\t\tthis.refresh();\n\t\t} );\n\n\t\tthis.on( 'execute', evt => {\n\t\t\tif ( !this.isEnabled ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\n\t\t// By default commands are disabled when the editor is in read-only mode.\n\t\tthis.listenTo( editor, 'change:isReadOnly', ( evt, name, value ) => {\n\t\t\tif ( value ) {\n\t\t\t\tthis.forceDisabled( 'readOnlyMode' );\n\t\t\t} else {\n\t\t\t\tthis.clearForceDisabled( 'readOnlyMode' );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Refreshes the command. The command should update its {@link #isEnabled} and {@link #value} properties\n\t * in this method.\n\t *\n\t * This method is automatically called when\n\t * {@link module:engine/model/document~Document#event:change any changes are applied to the document}.\n\t */\n\trefresh() {\n\t\tthis.isEnabled = true;\n\t}\n\n\t/**\n\t * Disables the command.\n\t *\n\t * Command may be disabled by multiple features or algorithms (at once). When disabling a command, unique id should be passed\n\t * (e.g. feature name). The same identifier should be used when {@link #clearForceDisabled enabling back} the command.\n\t * The command becomes enabled only after all features {@link #clearForceDisabled enabled it back}.\n\t *\n\t * Disabling and enabling a command:\n\t *\n\t *\t\tcommand.isEnabled; // -> true\n\t *\t\tcommand.forceDisabled( 'MyFeature' );\n\t *\t\tcommand.isEnabled; // -> false\n\t *\t\tcommand.clearForceDisabled( 'MyFeature' );\n\t *\t\tcommand.isEnabled; // -> true\n\t *\n\t * Command disabled by multiple features:\n\t *\n\t *\t\tcommand.forceDisabled( 'MyFeature' );\n\t *\t\tcommand.forceDisabled( 'OtherFeature' );\n\t *\t\tcommand.clearForceDisabled( 'MyFeature' );\n\t *\t\tcommand.isEnabled; // -> false\n\t *\t\tcommand.clearForceDisabled( 'OtherFeature' );\n\t *\t\tcommand.isEnabled; // -> true\n\t *\n\t * Multiple disabling with the same identifier is redundant:\n\t *\n\t *\t\tcommand.forceDisabled( 'MyFeature' );\n\t *\t\tcommand.forceDisabled( 'MyFeature' );\n\t *\t\tcommand.clearForceDisabled( 'MyFeature' );\n\t *\t\tcommand.isEnabled; // -> true\n\t *\n\t * **Note:** some commands or algorithms may have more complex logic when it comes to enabling or disabling certain commands,\n\t * so the command might be still disabled after {@link #clearForceDisabled} was used.\n\t *\n\t * @param {String} id Unique identifier for disabling. Use the same id when {@link #clearForceDisabled enabling back} the command.\n\t */\n\tforceDisabled( id ) {\n\t\tthis._disableStack.add( id );\n\n\t\tif ( this._disableStack.size == 1 ) {\n\t\t\tthis.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );\n\t\t\tthis.isEnabled = false;\n\t\t}\n\t}\n\n\t/**\n\t * Clears forced disable previously set through {@link #forceDisabled}. See {@link #forceDisabled}.\n\t *\n\t * @param {String} id Unique identifier, equal to the one passed in {@link #forceDisabled} call.\n\t */\n\tclearForceDisabled( id ) {\n\t\tthis._disableStack.delete( id );\n\n\t\tif ( this._disableStack.size == 0 ) {\n\t\t\tthis.off( 'set:isEnabled', forceDisable );\n\t\t\tthis.refresh();\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * A command may accept parameters. They will be passed from {@link module:core/editor/editor~Editor#execute `editor.execute()`}\n\t * to the command.\n\t *\n\t * The `execute()` method will automatically abort when the command is disabled ({@link #isEnabled} is `false`).\n\t * This behavior is implemented by a high priority listener to the {@link #event:execute} event.\n\t *\n\t * In order to see how to disable a command from \"outside\" see the {@link #isEnabled} documentation.\n\t *\n\t * @fires execute\n\t */\n\texecute() {}\n\n\t/**\n\t * Destroys the command.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Event fired by the {@link #execute} method. The command action is a listener to this event so it's\n\t * possible to change/cancel the behavior of the command by listening to this event.\n\t *\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * **Note:** This event is fired even if command is disabled. However, it is automatically blocked\n\t * by a high priority listener in order to prevent command execution.\n\t *\n\t * @event execute\n\t */\n}\n\nmix( Command, ObservableMixin );\n\n// Helper function that forces command to be disabled.\nfunction forceDisable( evt ) {\n\tevt.return = false;\n\tevt.stop();\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 enter/utils\n */\n\n/**\n * Returns attributes that should be preserved on the enter key.\n *\n * Filtering is realized based on `copyOnEnter` attribute property. Read more about attribute properties\n * {@link module:engine/model/schema~Schema#setAttributeProperties here}.\n *\n * @param {module:engine/model/schema~Schema} schema\n * @param {Iterable.<*>} allAttributes attributes to filter.\n * @returns {Iterable.<*>}\n */\nexport function* getCopyOnEnterAttributes( schema, allAttributes ) {\n\tfor ( const attribute of allAttributes ) {\n\t\tif ( attribute && schema.getAttributeProperties( attribute[ 0 ] ).copyOnEnter ) {\n\t\t\tyield attribute;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 enter/entercommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { getCopyOnEnterAttributes } from './utils';\n\n/**\n * Enter command. It is used by the {@link module:enter/enter~Enter Enter feature} to handle the <kbd>Enter</kbd> key.\n *\n * @extends module:core/command~Command\n */\nexport default class EnterCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tmodel.change( writer => {\n\t\t\tenterBlock( this.editor.model, writer, doc.selection, model.schema );\n\t\t\tthis.fire( 'afterExecute', { writer } );\n\t\t} );\n\t}\n}\n\n// Creates a new block in the way that the <kbd>Enter</kbd> key is expected to work.\n//\n// @param {module:engine/model~Model} model\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n// Selection on which the action should be performed.\n// @param {module:engine/model/schema~Schema} schema\nfunction enterBlock( model, writer, selection, schema ) {\n\tconst isSelectionEmpty = selection.isCollapsed;\n\tconst range = selection.getFirstRange();\n\tconst startElement = range.start.parent;\n\tconst endElement = range.end.parent;\n\n\t// Don't touch the roots and other limit elements.\n\tif ( schema.isLimit( startElement ) || schema.isLimit( endElement ) ) {\n\t\t// Delete the selected content but only if inside a single limit element.\n\t\t// Abort, when crossing limit elements boundary (e.g. <limit1>x[x</limit1>donttouchme<limit2>y]y</limit2>).\n\t\t// This is an edge case and it's hard to tell what should actually happen because such a selection\n\t\t// is not entirely valid.\n\t\tif ( !isSelectionEmpty && startElement == endElement ) {\n\t\t\tmodel.deleteContent( selection );\n\t\t}\n\n\t\treturn;\n\t}\n\n\tif ( isSelectionEmpty ) {\n\t\tconst attributesToCopy = getCopyOnEnterAttributes( writer.model.schema, selection.getAttributes() );\n\t\tsplitBlock( writer, range.start );\n\t\twriter.setSelectionAttribute( attributesToCopy );\n\t} else {\n\t\tconst leaveUnmerged = !( range.start.isAtStart && range.end.isAtEnd );\n\t\tconst isContainedWithinOneElement = ( startElement == endElement );\n\n\t\tmodel.deleteContent( selection, { leaveUnmerged } );\n\n\t\tif ( leaveUnmerged ) {\n\t\t\t// Partially selected elements.\n\t\t\t//\n\t\t\t// <h>x[xx]x</h>\t\t-> <h>x^x</h>\t\t\t-> <h>x</h><h>^x</h>\n\t\t\tif ( isContainedWithinOneElement ) {\n\t\t\t\tsplitBlock( writer, selection.focus );\n\t\t\t}\n\t\t\t// Selection over multiple elements.\n\t\t\t//\n\t\t\t// <h>x[x</h><p>y]y<p>\t-> <h>x^</h><p>y</p>\t-> <h>x</h><p>^y</p>\n\t\t\telse {\n\t\t\t\twriter.setSelection( endElement, 0 );\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction splitBlock( writer, splitPos ) {\n\twriter.split( splitPos );\n\twriter.setSelection( splitPos.parent.nextSibling, 0 );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 enter/enterobserver\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';\n\n/**\n * Enter observer introduces the {@link module:engine/view/document~Document#event:enter} event.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class EnterObserver extends Observer {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tconst doc = this.document;\n\n\t\tdoc.on( 'keydown', ( evt, data ) => {\n\t\t\tif ( this.isEnabled && data.keyCode == keyCodes.enter ) {\n\t\t\t\t// Save the event object to check later if it was stopped or not.\n\t\t\t\tlet event;\n\t\t\t\tdoc.once( 'enter', evt => ( event = evt ), { priority: 'highest' } );\n\n\t\t\t\tdoc.fire( 'enter', new DomEventData( doc, data.domEvent, {\n\t\t\t\t\tisSoft: data.shiftKey\n\t\t\t\t} ) );\n\n\t\t\t\t// Stop `keydown` event if `enter` event was stopped.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5/issues/753\n\t\t\t\tif ( event && event.stop.called ) {\n\t\t\t\t\tevt.stop();\n\t\t\t\t}\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 presses the <kbd>Enter</kbd> key.\n *\n * Note: This event is fired by the {@link module:enter/enterobserver~EnterObserver observer}\n * (usually registered by the {@link module:enter/enter~Enter Enter feature} and\n * {@link module:enter/shiftenter~ShiftEnter ShiftEnter feature}).\n *\n * @event module:engine/view/document~Document#event:enter\n * @param {module:engine/view/observer/domeventdata~DomEventData} data\n * @param {Boolean} data.isSoft Whether it's a soft enter (<kbd>Shift</kbd>+<kbd>Enter</kbd>) or hard enter (<kbd>Enter</kbd>).\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 enter/enter\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport EnterCommand from './entercommand';\nimport EnterObserver from './enterobserver';\n\n/**\n * This plugin handles the <kbd>Enter</kbd> key (hard line break) in the editor.\n *\n * See also the {@link module:enter/shiftenter~ShiftEnter} plugin.\n *\n * For more information about this feature see the {@glink api/enter package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Enter extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Enter';\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( EnterObserver );\n\n\t\teditor.commands.add( 'enter', new EnterCommand( editor ) );\n\n\t\tthis.listenTo( viewDocument, 'enter', ( evt, data ) => {\n\t\t\tdata.preventDefault();\n\n\t\t\t// The soft enter key is handled by the ShiftEnter plugin.\n\t\t\tif ( data.isSoft ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\teditor.execute( 'enter' );\n\t\t\tview.scrollToTheSelection();\n\t\t}, { priority: 'low' } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 enter/shiftentercommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { getCopyOnEnterAttributes } from './utils';\n\n/**\n * ShiftEnter command. It is used by the {@link module:enter/shiftenter~ShiftEnter ShiftEnter feature} to handle\n * the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke.\n *\n * @extends module:core/command~Command\n */\nexport default class ShiftEnterCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tmodel.change( writer => {\n\t\t\tsoftBreakAction( model, writer, doc.selection );\n\t\t\tthis.fire( 'afterExecute', { writer } );\n\t\t} );\n\t}\n\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tthis.isEnabled = isEnabled( model.schema, doc.selection );\n\t}\n}\n\n// Checks whether the ShiftEnter command should be enabled in the specified selection.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\nfunction isEnabled( schema, selection ) {\n\t// At this moment it is okay to support single range selections only.\n\t// But in the future we may need to change that.\n\tif ( selection.rangeCount > 1 ) {\n\t\treturn false;\n\t}\n\n\tconst anchorPos = selection.anchor;\n\n\t// Check whether the break element can be inserted in the current selection anchor.\n\tif ( !anchorPos || !schema.checkChild( anchorPos, 'softBreak' ) ) {\n\t\treturn false;\n\t}\n\n\tconst range = selection.getFirstRange();\n\tconst startElement = range.start.parent;\n\tconst endElement = range.end.parent;\n\n\t// Do not modify the content if selection is cross-limit elements.\n\tif ( ( isInsideLimitElement( startElement, schema ) || isInsideLimitElement( endElement, schema ) ) && startElement !== endElement ) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// Creates a break in the way that the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke is expected to work.\n//\n// @param {module:engine/model~Model} model\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n// Selection on which the action should be performed.\nfunction softBreakAction( model, writer, selection ) {\n\tconst isSelectionEmpty = selection.isCollapsed;\n\tconst range = selection.getFirstRange();\n\tconst startElement = range.start.parent;\n\tconst endElement = range.end.parent;\n\tconst isContainedWithinOneElement = ( startElement == endElement );\n\n\tif ( isSelectionEmpty ) {\n\t\tconst attributesToCopy = getCopyOnEnterAttributes( model.schema, selection.getAttributes() );\n\t\tinsertBreak( model, writer, range.end );\n\n\t\twriter.removeSelectionAttribute( selection.getAttributeKeys() );\n\t\twriter.setSelectionAttribute( attributesToCopy );\n\t} else {\n\t\tconst leaveUnmerged = !( range.start.isAtStart && range.end.isAtEnd );\n\t\tmodel.deleteContent( selection, { leaveUnmerged } );\n\n\t\t// Selection within one element:\n\t\t//\n\t\t// <h>x[xx]x</h>\t\t-> <h>x^x</h>\t\t\t-> <h>x<br>^x</h>\n\t\tif ( isContainedWithinOneElement ) {\n\t\t\tinsertBreak( model, writer, selection.focus );\n\t\t}\n\t\t// Selection over multiple elements.\n\t\t//\n\t\t// <h>x[x</h><p>y]y<p>\t-> <h>x^</h><p>y</p>\t-> <h>x</h><p>^y</p>\n\t\t//\n\t\t// We chose not to insert a line break in this case because:\n\t\t//\n\t\t// * it's not a very common scenario,\n\t\t// * it actually surprised me when I saw the \"expected behavior\" in real life.\n\t\t//\n\t\t// It's ok if the user will need to be more specific where they want the <br> to be inserted.\n\t\telse {\n\t\t\t// Move the selection to the 2nd element (last step of the example above).\n\t\t\tif ( leaveUnmerged ) {\n\t\t\t\twriter.setSelection( endElement, 0 );\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction insertBreak( model, writer, position ) {\n\tconst breakLineElement = writer.createElement( 'softBreak' );\n\n\tmodel.insertContent( breakLineElement, position );\n\twriter.setSelection( breakLineElement, 'after' );\n}\n\n// Checks whether the specified `element` is a child of the limit element.\n//\n// Checking whether the `<p>` element is inside a limit element:\n// - <$root><p>Text.</p></$root> => false\n// - <$root><limitElement><p>Text</p></limitElement></$root> => true\n//\n// @param {module:engine/model/element~Element} element\n// @param {module:engine/schema~Schema} schema\n// @returns {Boolean}\nfunction isInsideLimitElement( element, schema ) {\n\t// `$root` is a limit element but in this case is an invalid element.\n\tif ( element.is( 'rootElement' ) ) {\n\t\treturn false;\n\t}\n\n\treturn schema.isLimit( element ) || isInsideLimitElement( element.parent, schema );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 enter/shiftenter\n */\n\nimport ShiftEnterCommand from './shiftentercommand';\nimport EnterObserver from './enterobserver';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * This plugin handles the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke (soft line break) in the editor.\n *\n * See also the {@link module:enter/enter~Enter} plugin.\n *\n * For more information about this feature see the {@glink api/enter package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ShiftEnter extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ShiftEnter';\n\t}\n\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst conversion = editor.conversion;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t// Configure the schema.\n\t\tschema.register( 'softBreak', {\n\t\t\tallowWhere: '$text',\n\t\t\tisInline: true\n\t\t} );\n\n\t\t// Configure converters.\n\t\tconversion.for( 'upcast' )\n\t\t\t.elementToElement( {\n\t\t\t\tmodel: 'softBreak',\n\t\t\t\tview: 'br'\n\t\t\t} );\n\n\t\tconversion.for( 'downcast' )\n\t\t\t.elementToElement( {\n\t\t\t\tmodel: 'softBreak',\n\t\t\t\tview: ( modelElement, viewWriter ) => viewWriter.createEmptyElement( 'br' )\n\t\t\t} );\n\n\t\tview.addObserver( EnterObserver );\n\n\t\teditor.commands.add( 'shiftEnter', new ShiftEnterCommand( editor ) );\n\n\t\tthis.listenTo( viewDocument, 'enter', ( evt, data ) => {\n\t\t\tdata.preventDefault();\n\n\t\t\t// The hard enter key is handled by the Enter plugin.\n\t\t\tif ( !data.isSoft ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\teditor.execute( 'shiftEnter' );\n\t\t\tview.scrollToTheSelection();\n\t\t}, { priority: 'low' } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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-2020, 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<module:engine/model/batch~Batch>}\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 range = options.range || doc.selection.getFirstRange();\n\t\tconst resultRange = options.resultRange;\n\n\t\tmodel.enqueueChange( this._buffer.batch, writer => {\n\t\t\tconst isCollapsedRange = range.isCollapsed;\n\n\t\t\tthis._buffer.lock();\n\n\t\t\tmodel.deleteContent( model.createSelection( range ) );\n\n\t\t\tif ( text ) {\n\t\t\t\tmodel.insertContent( writer.createText( text, doc.selection.getAttributes() ), range.start );\n\t\t\t}\n\n\t\t\tif ( resultRange ) {\n\t\t\t\twriter.setSelection( resultRange );\n\t\t\t} else if ( isCollapsedRange ) {\n\t\t\t\t// If range was collapsed just shift the selection by the number of inserted characters.\n\t\t\t\twriter.setSelection( range.start.getShiftedBy( textInsertions ) );\n\t\t\t}\n\n\t\t\tthis._buffer.unlock();\n\n\t\t\tthis._buffer.input( textInsertions );\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\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ( isSafeKeystroke( 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\tmodel.enqueueChange( buffer.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// Returns `true` if a keystroke should not cause any content change caused by \"typing\".\n//\n// Note: This implementation is very simple and will need to be refined with time.\n//\n// @private\n// @param {engine.view.observer.keyObserver.KeyEventData} keyData\n// @returns {Boolean}\nfunction isSafeKeystroke( keyData ) {\n\t// Keystrokes which contain Ctrl don't represent typing.\n\tif ( keyData.ctrlKey ) {\n\t\treturn true;\n\t}\n\n\treturn safeKeycodes.includes( keyData.keyCode );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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.<module:engine/view/observer/mutationobserver~MutatedText|\n * module:engine/view/observer/mutationobserver~MutatedChildren>} 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-2020, 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 utils/difftochanges\n */\n\n/**\n * Creates a set of changes which need to be applied to the input in order to transform\n * it into the output. This function can be used with strings or arrays.\n *\n *\t\tconst input = Array.from( 'abc' );\n *\t\tconst output = Array.from( 'xaby' );\n *\t\tconst changes = diffToChanges( diff( input, output ), output );\n *\n *\t\tchanges.forEach( change => {\n *\t\t\tif ( change.type == 'insert' ) {\n *\t\t\t\tinput.splice( change.index, 0, ...change.values );\n *\t\t\t} else if ( change.type == 'delete' ) {\n *\t\t\t\tinput.splice( change.index, change.howMany );\n *\t\t\t}\n *\t\t} );\n *\n *\t\tinput.join( '' ) == output.join( '' ); // -> true\n *\n * @param {Array.<'equal'|'insert'|'delete'>} diff Result of {@link module:utils/diff~diff}.\n * @param {String|Array} output The string or array which was passed as diff's output.\n * @returns {Array.<Object>} Set of changes (insert or delete) which need to be applied to the input\n * in order to transform it into the output.\n */\nexport default function diffToChanges( diff, output ) {\n\tconst changes = [];\n\tlet index = 0;\n\tlet lastOperation;\n\n\tdiff.forEach( change => {\n\t\tif ( change == 'equal' ) {\n\t\t\tpushLast();\n\n\t\t\tindex++;\n\t\t} else if ( change == 'insert' ) {\n\t\t\tif ( isContinuationOf( 'insert' ) ) {\n\t\t\t\tlastOperation.values.push( output[ index ] );\n\t\t\t} else {\n\t\t\t\tpushLast();\n\n\t\t\t\tlastOperation = {\n\t\t\t\t\ttype: 'insert',\n\t\t\t\t\tindex,\n\t\t\t\t\tvalues: [ output[ index ] ]\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tindex++;\n\t\t} else /* if ( change == 'delete' ) */ {\n\t\t\tif ( isContinuationOf( 'delete' ) ) {\n\t\t\t\tlastOperation.howMany++;\n\t\t\t} else {\n\t\t\t\tpushLast();\n\n\t\t\t\tlastOperation = {\n\t\t\t\t\ttype: 'delete',\n\t\t\t\t\tindex,\n\t\t\t\t\thowMany: 1\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t} );\n\n\tpushLast();\n\n\treturn changes;\n\n\tfunction pushLast() {\n\t\tif ( lastOperation ) {\n\t\t\tchanges.push( lastOperation );\n\t\t\tlastOperation = null;\n\t\t}\n\t}\n\n\tfunction isContinuationOf( expected ) {\n\t\treturn lastOperation && lastOperation.type == expected;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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.<module:engine/view/observer/mutationobserver~MutatedText|\n\t * module:engine/view/observer/mutationobserver~MutatedChildren>} 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 `<p><a href=\"\"><i>Link{}</i></a></p>`, the browser might change the order of elements\n\t * to `<p><i><a href=\"\">Link</a>x{}</i></p>`. A similar situation happens when the spell checker\n\t * replaces a word wrapped with `<strong>` with a word wrapped with a `<b>` 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.<module:engine/view/observer/mutationobserver~MutatedText|\n\t * module:engine/view/observer/mutationobserver~MutatedChildren>} 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();\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 `<ul>` is a common ancestor, `currentModel` is `undefined`\n\t\t// because `<ul>` is not mapped (`<li>`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 `<softBreak>` from the end of `modelFromDomChildren` if there is no `<softBreak>` in current model.\n\t\t// If the described scenario happened, it means that this is a bogus `<br />` added by a browser.\n\t\tconst lastDomChild = modelFromDomChildren[ modelFromDomChildren.length - 1 ];\n\t\tconst lastCurrentChild = currentModelChildren[ currentModelChildren.length - 1 ];\n\n\t\tif ( lastDomChild && lastDomChild.is( 'softBreak' ) && lastCurrentChild && !lastCurrentChild.is( 'softBreak' ) ) {\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.<module:engine/view/observer/mutationobserver~MutatedText|\n// module:engine/view/observer/mutationobserver~MutatedChildren>} 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.<module:engine/model/node~Node>} 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-2020, 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.isTyping( 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-2020, 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 <kbd>Delete</kbd> and\n * <kbd>Backspace</kbd> 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 * @member {typing.ChangeBuffer} #buffer\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\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// <h1></h1><p>[]</p>\t--> <h1>[</h1><p>]</p> \t\t--> <p></p>\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( options.sequence || 1 ) ) {\n\t\t\t\tthis._replaceEntireContentWithParagraph( writer );\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, { doNotResetEntireContent } );\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 <kbd>Backspace</kbd> or <kbd>Delete</kbd> 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 <kbd>Ctrl</kbd> + <kbd>A</kbd>, <kbd>Backspace</kbd>).\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 (<p><inlineWidget>[]</inlineWidget></p>)\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 */\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","/**\n * @license Copyright (c) 2003-2020, 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 <kbd>Delete</kbd> or <kbd>Backspace</kbd>).\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-2020, 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 <kbd>Delete</kbd> and <kbd>Backspace</kbd> 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\teditor.commands.add( 'forwardDelete', new DeleteCommand( editor, 'forward' ) );\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' ? 'forwardDelete' : '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-2020, 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-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport InsertOperation from './insertoperation';\nimport AttributeOperation from './attributeoperation';\nimport RenameOperation from './renameoperation';\nimport MarkerOperation from './markeroperation';\nimport MoveOperation from './moveoperation';\nimport RootAttributeOperation from './rootattributeoperation';\nimport MergeOperation from './mergeoperation';\nimport SplitOperation from './splitoperation';\nimport NoOperation from './nooperation';\nimport Range from '../range';\nimport Position from '../position';\n\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n\nconst transformations = new Map();\n\n/**\n * @module engine/model/operation/transform\n */\n\n/**\n * Sets a transformation function to be be used to transform instances of class `OperationA` by instances of class `OperationB`.\n *\n * The `transformationFunction` is passed three parameters:\n *\n * * `a` - operation to be transformed, an instance of `OperationA`,\n * * `b` - operation to be transformed by, an instance of `OperationB`,\n * * {@link module:engine/model/operation/transform~TransformationContext `context`} - object with additional information about\n * transformation context.\n *\n * The `transformationFunction` should return transformation result, which is an array with one or multiple\n * {@link module:engine/model/operation/operation~Operation operation} instances.\n *\n * @protected\n * @param {Function} OperationA\n * @param {Function} OperationB\n * @param {Function} transformationFunction Function to use for transforming.\n */\nfunction setTransformation( OperationA, OperationB, transformationFunction ) {\n\tlet aGroup = transformations.get( OperationA );\n\n\tif ( !aGroup ) {\n\t\taGroup = new Map();\n\t\ttransformations.set( OperationA, aGroup );\n\t}\n\n\taGroup.set( OperationB, transformationFunction );\n}\n\n/**\n * Returns a previously set transformation function for transforming an instance of `OperationA` by an instance of `OperationB`.\n *\n * If no transformation was set for given pair of operations, {@link module:engine/model/operation/transform~noUpdateTransformation}\n * is returned. This means that if no transformation was set, the `OperationA` instance will not change when transformed\n * by the `OperationB` instance.\n *\n * @private\n * @param {Function} OperationA\n * @param {Function} OperationB\n * @returns {Function} Function set to transform an instance of `OperationA` by an instance of `OperationB`.\n */\nfunction getTransformation( OperationA, OperationB ) {\n\tconst aGroup = transformations.get( OperationA );\n\n\tif ( aGroup && aGroup.has( OperationB ) ) {\n\t\treturn aGroup.get( OperationB );\n\t}\n\n\treturn noUpdateTransformation;\n}\n\n/**\n * A transformation function that only clones operation to transform, without changing it.\n *\n * @private\n * @param {module:engine/model/operation/operation~Operation} a Operation to transform.\n * @returns {Array.<module:engine/model/operation/operation~Operation>}\n */\nfunction noUpdateTransformation( a ) {\n\treturn [ a ];\n}\n\n/**\n * Transforms operation `a` by operation `b`.\n *\n * @param {module:engine/model/operation/operation~Operation} a Operation to be transformed.\n * @param {module:engine/model/operation/operation~Operation} b Operation to transform by.\n * @param {module:engine/model/operation/transform~TransformationContext} context Transformation context for this transformation.\n * @returns {Array.<module:engine/model/operation/operation~Operation>} Transformation result.\n */\nexport function transform( a, b, context = {} ) {\n\tconst transformationFunction = getTransformation( a.constructor, b.constructor );\n\n\ttry {\n\t\ta = a.clone();\n\n\t\treturn transformationFunction( a, b, context );\n\t} catch ( e ) {\n\t\t// @if CK_DEBUG // console.warn( 'Error during operation transformation!', e.message );\n\t\t// @if CK_DEBUG // console.warn( 'Transformed operation', a );\n\t\t// @if CK_DEBUG // console.warn( 'Operation transformed by', b );\n\t\t// @if CK_DEBUG // console.warn( 'context.aIsStrong', context.aIsStrong );\n\t\t// @if CK_DEBUG // console.warn( 'context.aWasUndone', context.aWasUndone );\n\t\t// @if CK_DEBUG // console.warn( 'context.bWasUndone', context.bWasUndone );\n\t\t// @if CK_DEBUG // console.warn( 'context.abRelation', context.abRelation );\n\t\t// @if CK_DEBUG // console.warn( 'context.baRelation', context.baRelation );\n\n\t\tthrow e;\n\t}\n}\n\n/**\n * Performs a transformation of two sets of operations - `operationsA` and `operationsB`. The transformation is two-way -\n * both transformed `operationsA` and transformed `operationsB` are returned.\n *\n * Note, that the first operation in each set should base on the same document state (\n * {@link module:engine/model/document~Document#version document version}).\n *\n * It is assumed that `operationsA` are \"more important\" during conflict resolution between two operations.\n *\n * New copies of both passed arrays and operations inside them are returned. Passed arguments are not altered.\n *\n * Base versions of the transformed operations sets are updated accordingly. For example, assume that base versions are `4`\n * and there are `3` operations in `operationsA` and `5` operations in `operationsB`. Then:\n *\n * * transformed `operationsA` will start from base version `9` (`4` base version + `5` operations B),\n * * transformed `operationsB` will start from base version `7` (`4` base version + `3` operations A).\n *\n * If no operation was broken into two during transformation, then both sets will end up with an operation that bases on version `11`:\n *\n * * transformed `operationsA` start from `9` and there are `3` of them, so the last will have `baseVersion` equal to `11`,\n * * transformed `operationsB` start from `7` and there are `5` of them, so the last will have `baseVersion` equal to `11`.\n *\n * @param {Array.<module:engine/model/operation/operation~Operation>} operationsA\n * @param {Array.<module:engine/model/operation/operation~Operation>} operationsB\n * @param {Object} options Additional transformation options.\n * @param {module:engine/model/document~Document|null} options.document Document which the operations change.\n * @param {Boolean} [options.useRelations=false] Whether during transformation relations should be used (used during undo for\n * better conflict resolution).\n * @param {Boolean} [options.padWithNoOps=false] Whether additional {@link module:engine/model/operation/nooperation~NoOperation}s\n * should be added to the transformation results to force the same last base version for both transformed sets (in case\n * if some operations got broken into multiple operations during transformation).\n * @returns {Object} Transformation result.\n * @returns {Array.<module:engine/model/operation/operation~Operation>} return.operationsA Transformed `operationsA`.\n * @returns {Array.<module:engine/model/operation/operation~Operation>} return.operationsB Transformed `operationsB`.\n * @returns {Map} return.originalOperations A map that links transformed operations to original operations. The keys are the transformed\n * operations and the values are the original operations from the input (`operationsA` and `operationsB`).\n */\nexport function transformSets( operationsA, operationsB, options ) {\n\t// Create new arrays so the originally passed arguments are not changed.\n\t// No need to clone operations, they are cloned as they are transformed.\n\toperationsA = operationsA.slice();\n\toperationsB = operationsB.slice();\n\n\tconst contextFactory = new ContextFactory( options.document, options.useRelations, options.forceWeakRemove );\n\tcontextFactory.setOriginalOperations( operationsA );\n\tcontextFactory.setOriginalOperations( operationsB );\n\n\tconst originalOperations = contextFactory.originalOperations;\n\n\t// If one of sets is empty there is simply nothing to transform, so return sets as they are.\n\tif ( operationsA.length == 0 || operationsB.length == 0 ) {\n\t\treturn { operationsA, operationsB, originalOperations };\n\t}\n\t//\n\t// Following is a description of transformation process:\n\t//\n\t// There are `operationsA` and `operationsB` to be transformed, both by both.\n\t//\n\t// So, suppose we have sets of two operations each: `operationsA` = `[ a1, a2 ]`, `operationsB` = `[ b1, b2 ]`.\n\t//\n\t// Remember, that we can only transform operations that base on the same context. We assert that `a1` and `b1` base on\n\t// the same context and we transform them. Then, we get `a1'` and `b1'`. `a2` bases on a context with `a1` -- `a2`\n\t// is an operation that followed `a1`. Similarly, `b2` bases on a context with `b1`.\n\t//\n\t// However, since `a1'` is a result of transformation by `b1`, `a1'` now also has a context with `b1`. This means that\n\t// we can safely transform `a1'` by `b2`. As we finish transforming `a1`, we also transformed all `operationsB`.\n\t// All `operationsB` also have context including `a1`. Now, we can properly transform `a2` by those operations.\n\t//\n\t// The transformation process can be visualized on a transformation diagram (\"diamond diagram\"):\n\t//\n\t// [the initial state]\n\t// [common for a1 and b1]\n\t//\n\t// *\n\t// / \\\n\t// / \\\n\t// b1 a1\n\t// / \\\n\t// / \\\n\t// * *\n\t// / \\ / \\\n\t// / \\ / \\\n\t// b2 a1' b1' a2\n\t// / \\ / \\\n\t// / \\ / \\\n\t// * * *\n\t// \\ / \\ /\n\t// \\ / \\ /\n\t// a1'' b2' a2' b1''\n\t// \\ / \\ /\n\t// \\ / \\ /\n\t// * *\n\t// \\ /\n\t// \\ /\n\t// a2'' b2''\n\t// \\ /\n\t// \\ /\n\t// *\n\t//\n\t// [the final state]\n\t//\n\t// The final state can be reached from the initial state by applying `a1`, `a2`, `b1''` and `b2''`, as well as by\n\t// applying `b1`, `b2`, `a1''`, `a2''`. Note how the operations get to a proper common state before each pair is\n\t// transformed.\n\t//\n\t// Another thing to consider is that an operation during transformation can be broken into multiple operations.\n\t// Suppose that `a1` * `b1` = `[ a11', a12' ]` (instead of `a1'` that we considered previously).\n\t//\n\t// In that case, we leave `a12'` for later and we continue transforming `a11'` until it is transformed by all `operationsB`\n\t// (in our case it is just `b2`). At this point, `b1` is transformed by \"whole\" `a1`, while `b2` is only transformed\n\t// by `a11'`. Similarly, `a12'` is only transformed by `b1`. This leads to a conclusion that we need to start transforming `a12'`\n\t// from the moment just after it was broken. So, `a12'` is transformed by `b2`. Now, \"the whole\" `a1` is transformed\n\t// by `operationsB`, while all `operationsB` are transformed by \"the whole\" `a1`. This means that we can continue with\n\t// following `operationsA` (in our case it is just `a2`).\n\t//\n\t// Of course, also `operationsB` can be broken. However, since we focus on transforming operation `a` to the end,\n\t// the only thing to do is to store both pieces of operation `b`, so that the next transformed operation `a` will\n\t// be transformed by both of them.\n\t//\n\t// *\n\t// / \\\n\t// / \\\n\t// / \\\n\t// b1 a1\n\t// / \\\n\t// / \\\n\t// / \\\n\t// * *\n\t// / \\ / \\\n\t// / a11' / \\\n\t// / \\ / \\\n\t// b2 * b1' a2\n\t// / / \\ / \\\n\t// / / a12' / \\\n\t// / / \\ / \\\n\t// * b2' * *\n\t// \\ / / \\ /\n\t// a11'' / b21'' \\ /\n\t// \\ / / \\ /\n\t// * * a2' b1''\n\t// \\ / \\ \\ /\n\t// a12'' b22''\\ \\ /\n\t// \\ / \\ \\ /\n\t// * a2'' *\n\t// \\ \\ /\n\t// \\ \\ b21'''\n\t// \\ \\ /\n\t// a2''' *\n\t// \\ /\n\t// \\ b22'''\n\t// \\ /\n\t// *\n\t//\n\t// Note, how `a1` is broken and transformed into `a11'` and `a12'`, while `b2'` got broken and transformed into `b21''` and `b22''`.\n\t//\n\t// Having all that on mind, here is an outline for the transformation process algorithm:\n\t//\n\t// 1. We have `operationsA` and `operationsB` array, which we dynamically update as the transformation process goes.\n\t//\n\t// 2. We take next (or first) operation from `operationsA` and check from which operation `b` we need to start transforming it.\n\t// All original `operationsA` are set to be transformed starting from the first operation `b`.\n\t//\n\t// 3. We take operations from `operationsB`, one by one, starting from the correct one, and transform operation `a`\n\t// by operation `b` (and vice versa). We update `operationsA` and `operationsB` by replacing the original operations\n\t// with the transformation results.\n\t//\n\t// 4. If operation is broken into multiple operations, we save all the new operations in the place of the\n\t// original operation.\n\t//\n\t// 5. Additionally, if operation `a` was broken, for the \"new\" operation, we remember from which operation `b` it should\n\t// be transformed by.\n\t//\n\t// 6. We continue transforming \"current\" operation `a` until it is transformed by all `operationsB`. Then, go to 2.\n\t// unless the last operation `a` was transformed.\n\t//\n\t// The actual implementation of the above algorithm is slightly different, as only one loop (while) is used.\n\t// The difference is that we have \"current\" `a` operation to transform and we store the index of the next `b` operation\n\t// to transform by. Each loop operates on two indexes then: index pointing to currently processed `a` operation and\n\t// index pointing to next `b` operation. Each loop is just one `a * b` + `b * a` transformation. After each loop\n\t// operation `b` index is updated. If all `b` operations were visited for the current `a` operation, we change\n\t// current `a` operation index to the next one.\n\t//\n\n\t// For each operation `a`, keeps information what is the index in `operationsB` from which the transformation should start.\n\tconst nextTransformIndex = new WeakMap();\n\n\t// For all the original `operationsA`, set that they should be transformed starting from the first of `operationsB`.\n\tfor ( const op of operationsA ) {\n\t\tnextTransformIndex.set( op, 0 );\n\t}\n\n\t// Additional data that is used for some postprocessing after the main transformation process is done.\n\tconst data = {\n\t\tnextBaseVersionA: operationsA[ operationsA.length - 1 ].baseVersion + 1,\n\t\tnextBaseVersionB: operationsB[ operationsB.length - 1 ].baseVersion + 1,\n\t\toriginalOperationsACount: operationsA.length,\n\t\toriginalOperationsBCount: operationsB.length\n\t};\n\n\t// Index of currently transformed operation `a`.\n\tlet i = 0;\n\n\t// While not all `operationsA` are transformed...\n\twhile ( i < operationsA.length ) {\n\t\t// Get \"current\" operation `a`.\n\t\tconst opA = operationsA[ i ];\n\n\t\t// For the \"current\" operation `a`, get the index of the next operation `b` to transform by.\n\t\tconst indexB = nextTransformIndex.get( opA );\n\n\t\t// If operation `a` was already transformed by every operation `b`, change \"current\" operation `a` to the next one.\n\t\tif ( indexB == operationsB.length ) {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst opB = operationsB[ indexB ];\n\n\t\t// Transform `a` by `b` and `b` by `a`.\n\t\tconst newOpsA = transform( opA, opB, contextFactory.getContext( opA, opB, true ) );\n\t\tconst newOpsB = transform( opB, opA, contextFactory.getContext( opB, opA, false ) );\n\t\t// As a result we get one or more `newOpsA` and one or more `newOpsB` operations.\n\n\t\t// Update contextual information about operations.\n\t\tcontextFactory.updateRelation( opA, opB );\n\n\t\tcontextFactory.setOriginalOperations( newOpsA, opA );\n\t\tcontextFactory.setOriginalOperations( newOpsB, opB );\n\n\t\t// For new `a` operations, update their index of the next operation `b` to transform them by.\n\t\t//\n\t\t// This is needed even if there was only one result (`a` was not broken) because that information is used\n\t\t// at the beginning of this loop every time.\n\t\tfor ( const newOpA of newOpsA ) {\n\t\t\t// Acknowledge, that operation `b` also might be broken into multiple operations.\n\t\t\t//\n\t\t\t// This is why we raise `indexB` not just by 1. If `newOpsB` are multiple operations, they will be\n\t\t\t// spliced in the place of `opB`. So we need to change `transformBy` accordingly, so that an operation won't\n\t\t\t// be transformed by the same operation (part of it) again.\n\t\t\tnextTransformIndex.set( newOpA, indexB + newOpsB.length );\n\t\t}\n\n\t\t// Update `operationsA` and `operationsB` with the transformed versions.\n\t\toperationsA.splice( i, 1, ...newOpsA );\n\t\toperationsB.splice( indexB, 1, ...newOpsB );\n\t}\n\n\tif ( options.padWithNoOps ) {\n\t\t// If no-operations padding is enabled, count how many extra `a` and `b` operations were generated.\n\t\tconst brokenOperationsACount = operationsA.length - data.originalOperationsACount;\n\t\tconst brokenOperationsBCount = operationsB.length - data.originalOperationsBCount;\n\n\t\t// Then, if that number is not the same, pad `operationsA` or `operationsB` with correct number of no-ops so\n\t\t// that the base versions are equalled.\n\t\t//\n\t\t// Note that only one array will be updated, as only one of those subtractions can be greater than zero.\n\t\tpadWithNoOps( operationsA, brokenOperationsBCount - brokenOperationsACount );\n\t\tpadWithNoOps( operationsB, brokenOperationsACount - brokenOperationsBCount );\n\t}\n\n\t// Finally, update base versions of transformed operations.\n\tupdateBaseVersions( operationsA, data.nextBaseVersionB );\n\tupdateBaseVersions( operationsB, data.nextBaseVersionA );\n\n\treturn { operationsA, operationsB, originalOperations };\n}\n\n// Gathers additional data about operations processed during transformation. Can be used to obtain contextual information\n// about two operations that are about to be transformed. This contextual information can be used for better conflict resolution.\nclass ContextFactory {\n\t// Creates `ContextFactory` instance.\n\t//\n\t// @param {module:engine/model/document~Document} document Document which the operations change.\n\t// @param {Boolean} useRelations Whether during transformation relations should be used (used during undo for\n\t// better conflict resolution).\n\t// @param {Boolean} [forceWeakRemove=false] If set to `false`, remove operation will be always stronger than move operation,\n\t// so the removed nodes won't end up back in the document root. When set to `true`, context data will be used.\n\tconstructor( document, useRelations, forceWeakRemove = false ) {\n\t\t// For each operation that is created during transformation process, we keep a reference to the original operation\n\t\t// which it comes from. The original operation works as a kind of \"identifier\". Every contextual information\n\t\t// gathered during transformation that we want to save for given operation, is actually saved for the original operation.\n\t\t// This way no matter if operation `a` is cloned, then transformed, even breaks, we still have access to the previously\n\t\t// gathered data through original operation reference.\n\t\tthis.originalOperations = new Map();\n\n\t\t// `model.History` instance which information about undone operations will be taken from.\n\t\tthis._history = document.history;\n\n\t\t// Whether additional context should be used.\n\t\tthis._useRelations = useRelations;\n\n\t\tthis._forceWeakRemove = !!forceWeakRemove;\n\n\t\t// Relations is a double-map structure (maps in map) where for two operations we store how those operations were related\n\t\t// to each other. Those relations are evaluated during transformation process. For every transformated pair of operations\n\t\t// we keep relations between them.\n\t\tthis._relations = new Map();\n\t}\n\n\t// Sets \"original operation\" for given operations.\n\t//\n\t// During transformation process, operations are cloned, then changed, then processed again, sometimes broken into two\n\t// or multiple operations. When gathering additional data it is important that all operations can be somehow linked\n\t// so a cloned and transformed \"version\" still kept track of the data assigned earlier to it.\n\t//\n\t// The original operation object will be used as such an universal linking id. Throughout the transformation process\n\t// all cloned operations will refer to \"the original operation\" when storing and reading additional data.\n\t//\n\t// If `takeFrom` is not set, each operation from `operations` array will be assigned itself as \"the original operation\".\n\t// This should be used as an initialization step.\n\t//\n\t// If `takeFrom` is set, each operation from `operations` will be assigned the same original operation as assigned\n\t// for `takeFrom` operation. This should be used to update original operations. It should be used in a way that\n\t// `operations` are the result of `takeFrom` transformation to ensure proper \"original operation propagation\".\n\t//\n\t// @param {Array.<module:engine/model/operation/operation~Operation>} operations\n\t// @param {module:engine/model/operation/operation~Operation|null} [takeFrom=null]\n\tsetOriginalOperations( operations, takeFrom = null ) {\n\t\tconst originalOperation = takeFrom ? this.originalOperations.get( takeFrom ) : null;\n\n\t\tfor ( const operation of operations ) {\n\t\t\tthis.originalOperations.set( operation, originalOperation || operation );\n\t\t}\n\t}\n\n\t// Saves a relation between operations `opA` and `opB`.\n\t//\n\t// Relations are then later used to help solve conflicts when operations are transformed.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\tupdateRelation( opA, opB ) {\n\t\t// The use of relations is described in a bigger detail in transformation functions.\n\t\t//\n\t\t// In brief, this function, for specified pairs of operation types, checks how positions defined in those operations relate.\n\t\t// Then those relations are saved. For example, for two move operations, it is saved if one of those operations target\n\t\t// position is before the other operation source position. This kind of information gives contextual information when\n\t\t// transformation is used during undo. Similar checks are done for other pairs of operations.\n\t\t//\n\t\tswitch ( opA.constructor ) {\n\t\t\tcase MoveOperation: {\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tif ( opA.targetPosition.isEqual( opB.sourcePosition ) || opB.movedRange.containsPosition( opA.targetPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertAtSource' );\n\t\t\t\t\t\t} else if ( opA.targetPosition.isEqual( opB.deletionPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertBetween' );\n\t\t\t\t\t\t} else if ( opA.targetPosition.isAfter( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'moveTargetAfter' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase MoveOperation: {\n\t\t\t\t\t\tif ( opA.targetPosition.isEqual( opB.sourcePosition ) || opA.targetPosition.isBefore( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertBefore' );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertAfter' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase SplitOperation: {\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tif ( opA.splitPosition.isBefore( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'splitBefore' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase MoveOperation: {\n\t\t\t\t\t\tif ( opA.splitPosition.isEqual( opB.sourcePosition ) || opA.splitPosition.isBefore( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'splitBefore' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase MergeOperation: {\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tif ( !opA.targetPosition.isEqual( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'mergeTargetNotMoved' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( opA.sourcePosition.isEqual( opB.targetPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'mergeSourceNotMoved' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( opA.sourcePosition.isEqual( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'mergeSameElement' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase SplitOperation: {\n\t\t\t\t\t\tif ( opA.sourcePosition.isEqual( opB.splitPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'splitAtSource' );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase MarkerOperation: {\n\t\t\t\tconst markerRange = opA.newRange;\n\n\t\t\t\tif ( !markerRange ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MoveOperation: {\n\t\t\t\t\t\tconst movedRange = Range._createFromPositionAndShift( opB.sourcePosition, opB.howMany );\n\n\t\t\t\t\t\tconst affectedLeft = movedRange.containsPosition( markerRange.start ) ||\n\t\t\t\t\t\t\tmovedRange.start.isEqual( markerRange.start );\n\n\t\t\t\t\t\tconst affectedRight = movedRange.containsPosition( markerRange.end ) ||\n\t\t\t\t\t\t\tmovedRange.end.isEqual( markerRange.end );\n\n\t\t\t\t\t\tif ( ( affectedLeft || affectedRight ) && !movedRange.containsRange( markerRange ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, {\n\t\t\t\t\t\t\t\tside: affectedLeft ? 'left' : 'right',\n\t\t\t\t\t\t\t\tpath: affectedLeft ? markerRange.start.path.slice() : markerRange.end.path.slice()\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tconst wasInLeftElement = markerRange.start.isEqual( opB.targetPosition );\n\t\t\t\t\t\tconst wasStartBeforeMergedElement = markerRange.start.isEqual( opB.deletionPosition );\n\t\t\t\t\t\tconst wasEndBeforeMergedElement = markerRange.end.isEqual( opB.deletionPosition );\n\t\t\t\t\t\tconst wasInRightElement = markerRange.end.isEqual( opB.sourcePosition );\n\n\t\t\t\t\t\tif ( wasInLeftElement || wasStartBeforeMergedElement || wasEndBeforeMergedElement || wasInRightElement ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, {\n\t\t\t\t\t\t\t\twasInLeftElement,\n\t\t\t\t\t\t\t\twasStartBeforeMergedElement,\n\t\t\t\t\t\t\t\twasEndBeforeMergedElement,\n\t\t\t\t\t\t\t\twasInRightElement\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Evaluates and returns contextual information about two given operations `opA` and `opB` which are about to be transformed.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\t// @returns {module:engine/model/operation/transform~TransformationContext}\n\tgetContext( opA, opB, aIsStrong ) {\n\t\treturn {\n\t\t\taIsStrong,\n\t\t\taWasUndone: this._wasUndone( opA ),\n\t\t\tbWasUndone: this._wasUndone( opB ),\n\t\t\tabRelation: this._useRelations ? this._getRelation( opA, opB ) : null,\n\t\t\tbaRelation: this._useRelations ? this._getRelation( opB, opA ) : null,\n\t\t\tforceWeakRemove: this._forceWeakRemove\n\t\t};\n\t}\n\n\t// Returns whether given operation `op` has already been undone.\n\t//\n\t// Information whether an operation was undone gives more context when making a decision when two operations are in conflict.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} op\n\t// @returns {Boolean}\n\t_wasUndone( op ) {\n\t\t// For `op`, get its original operation. After all, if `op` is a clone (or even transformed clone) of another\n\t\t// operation, literally `op` couldn't be undone. It was just generated. If anything, it was the operation it origins\n\t\t// from which was undone. So get that original operation.\n\t\tconst originalOp = this.originalOperations.get( op );\n\n\t\t// And check with the document if the original operation was undone.\n\t\treturn originalOp.wasUndone || this._history.isUndoneOperation( originalOp );\n\t}\n\n\t// Returns a relation between `opA` and an operation which is undone by `opB`. This can be `String` value if a relation\n\t// was set earlier or `null` if there was no relation between those operations.\n\t//\n\t// This is a little tricky to understand, so let's compare it to `ContextFactory#_wasUndone`.\n\t//\n\t// When `wasUndone( opB )` is used, we check if the `opB` has already been undone. It is obvious, that the\n\t// undoing operation must happen after the undone operation. So, essentially, we have `opB`, we take document history,\n\t// we look forward in the future and ask if in that future `opB` was undone.\n\t//\n\t// Relations is a backward process to `wasUndone()`.\n\t//\n\t// Long story short - using relations is asking what happened in the past. Looking back. This time we have an undoing\n\t// operation `opB` which has undone some other operation. When there is a transformation `opA` x `opB` and there is\n\t// a conflict to solve and `opB` is an undoing operation, we can look back in the history and see what was a relation\n\t// between `opA` and the operation which `opB` undone. Basing on that relation from the past, we can now make\n\t// a better decision when resolving a conflict between two operations, because we know more about the context of\n\t// those two operations.\n\t//\n\t// This is why this function does not return a relation directly between `opA` and `opB` because we need to look\n\t// back to search for a meaningful contextual information.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\t// @returns {String|null}\n\t_getRelation( opA, opB ) {\n\t\t// Get the original operation. Similarly as in `wasUndone()` it is used as an universal identifier for stored data.\n\t\tconst origB = this.originalOperations.get( opB );\n\t\tconst undoneB = this._history.getUndoneOperation( origB );\n\n\t\t// If `opB` is not undoing any operation, there is no relation.\n\t\tif ( !undoneB ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst origA = this.originalOperations.get( opA );\n\t\tconst relationsA = this._relations.get( origA );\n\n\t\t// Get all relations for `opA`, and check if there is a relation with `opB`-undone-counterpart. If so, return it.\n\t\tif ( relationsA ) {\n\t\t\treturn relationsA.get( undoneB ) || null;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t// Helper function for `ContextFactory#updateRelations`.\n\t//\n\t// @private\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\t// @param {String} relation\n\t_setRelation( opA, opB, relation ) {\n\t\t// As always, setting is for original operations, not the clones/transformed operations.\n\t\tconst origA = this.originalOperations.get( opA );\n\t\tconst origB = this.originalOperations.get( opB );\n\n\t\tlet relationsA = this._relations.get( origA );\n\n\t\tif ( !relationsA ) {\n\t\t\trelationsA = new Map();\n\t\t\tthis._relations.set( origA, relationsA );\n\t\t}\n\n\t\trelationsA.set( origB, relation );\n\t}\n}\n\n/**\n * Holds additional contextual information about a transformed pair of operations (`a` and `b`). Those information\n * can be used for better conflict resolving.\n *\n * @typedef {Object} module:engine/model/operation/transform~TransformationContext\n *\n * @property {Boolean} aIsStrong Whether `a` is strong operation in this transformation, or weak.\n * @property {Boolean} aWasUndone Whether `a` operation was undone.\n * @property {Boolean} bWasUndone Whether `b` operation was undone.\n * @property {String|null} abRelation The relation between `a` operation and an operation undone by `b` operation.\n * @property {String|null} baRelation The relation between `b` operation and an operation undone by `a` operation.\n */\n\n/**\n * An utility function that updates {@link module:engine/model/operation/operation~Operation#baseVersion base versions}\n * of passed operations.\n *\n * The function simply sets `baseVersion` as a base version of the first passed operation and then increments it for\n * each following operation in `operations`.\n *\n * @private\n * @param {Array.<module:engine/model/operation/operation~Operation>} operations Operations to update.\n * @param {Number} baseVersion Base version to set for the first operation in `operations`.\n */\nfunction updateBaseVersions( operations, baseVersion ) {\n\tfor ( const operation of operations ) {\n\t\toperation.baseVersion = baseVersion++;\n\t}\n}\n\n/**\n * Adds `howMany` instances of {@link module:engine/model/operation/nooperation~NoOperation} to `operations` set.\n *\n * @private\n * @param {Array.<module:engine/model/operation/operation~Operation>} operations\n * @param {Number} howMany\n */\nfunction padWithNoOps( operations, howMany ) {\n\tfor ( let i = 0; i < howMany; i++ ) {\n\t\toperations.push( new NoOperation( 0 ) );\n\t}\n}\n\n// -----------------------\n\nsetTransformation( AttributeOperation, AttributeOperation, ( a, b, context ) => {\n\tif ( a.key === b.key ) {\n\t\t// If operations attributes are in conflict, check if their ranges intersect and manage them properly.\n\n\t\t// First, we want to apply change to the part of a range that has not been changed by the other operation.\n\t\tconst operations = a.range.getDifference( b.range ).map( range => {\n\t\t\treturn new AttributeOperation( range, a.key, a.oldValue, a.newValue, 0 );\n\t\t} );\n\n\t\t// Then we take care of the common part of ranges.\n\t\tconst common = a.range.getIntersection( b.range );\n\n\t\tif ( common ) {\n\t\t\t// If this operation is more important, we also want to apply change to the part of the\n\t\t\t// original range that has already been changed by the other operation. Since that range\n\t\t\t// got changed we also have to update `oldValue`.\n\t\t\tif ( context.aIsStrong ) {\n\t\t\t\toperations.push( new AttributeOperation( common, b.key, b.newValue, a.newValue, 0 ) );\n\t\t\t}\n\t\t}\n\n\t\tif ( operations.length == 0 ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\n\t\treturn operations;\n\t} else {\n\t\t// If operations don't conflict, simply return an array containing just a clone of this operation.\n\t\treturn [ a ];\n\t}\n} );\n\nsetTransformation( AttributeOperation, InsertOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// The attribute operation range includes the position where nodes were inserted.\n\t// There are two possible scenarios: the inserted nodes were text and they should receive attributes or\n\t// the inserted nodes were elements and they should not receive attributes.\n\t//\n\tif ( a.range.start.hasSameParentAs( b.position ) && a.range.containsPosition( b.position ) ) {\n\t\t// If new nodes should not receive attributes, two separated ranges will be returned.\n\t\t// Otherwise, one expanded range will be returned.\n\t\tconst range = a.range._getTransformedByInsertion( b.position, b.howMany, !b.shouldReceiveAttributes );\n\t\tconst result = range.map( r => {\n\t\t\treturn new AttributeOperation( r, a.key, a.oldValue, a.newValue, a.baseVersion );\n\t\t} );\n\n\t\tif ( b.shouldReceiveAttributes ) {\n\t\t\t// `AttributeOperation#range` includes some newly inserted text.\n\t\t\t// The operation should also change the attribute of that text. An example:\n\t\t\t//\n\t\t\t// Bold should be applied on the following range:\n\t\t\t// <p>Fo[zb]ar</p>\n\t\t\t//\n\t\t\t// In meantime, new text is typed:\n\t\t\t// <p>Fozxxbar</p>\n\t\t\t//\n\t\t\t// Bold should be applied also on the new text:\n\t\t\t// <p>Fo[zxxb]ar</p>\n\t\t\t// <p>Fo<$text bold=\"true\">zxxb</$text>ar</p>\n\t\t\t//\n\t\t\t// There is a special case to consider here to consider.\n\t\t\t//\n\t\t\t// Consider setting an attribute with multiple possible values, for example `highlight`. The inserted text might\n\t\t\t// have already an attribute value applied and the `oldValue` property of the attribute operation might be wrong:\n\t\t\t//\n\t\t\t// Attribute `highlight=\"yellow\"` should be applied on the following range:\n\t\t\t// <p>Fo[zb]ar<p>\n\t\t\t//\n\t\t\t// In meantime, character `x` with `highlight=\"red\"` is typed:\n\t\t\t// <p>Fo[z<$text highlight=\"red\">x</$text>b]ar</p>\n\t\t\t//\n\t\t\t// In this case we cannot simply apply operation changing the attribute value from `null` to `\"yellow\"` for the whole range\n\t\t\t// because that would lead to an exception (`oldValue` is incorrect for `x`).\n\t\t\t//\n\t\t\t// We also cannot break the original range as this would mess up a scenario when there are multiple following\n\t\t\t// insert operations, because then only the first inserted character is included in those ranges:\n\t\t\t// <p>Fo[z][x][b]ar</p> --> <p>Fo[z][x]x[b]ar</p> --> <p>Fo[z][x]xx[b]ar</p>\n\t\t\t//\n\t\t\t// So, the attribute range needs be expanded, no matter what attributes are set on the inserted nodes:\n\t\t\t//\n\t\t\t// <p>Fo[z<$text highlight=\"red\">x</$text>b]ar</p> <--- Change from `null` to `yellow`, throwing an exception.\n\t\t\t//\n\t\t\t// But before that operation would be applied, we will add an additional attribute operation that will change\n\t\t\t// attributes on the inserted nodes in a way which would make the original operation correct:\n\t\t\t//\n\t\t\t// <p>Fo[z{<$text highlight=\"red\">}x</$text>b]ar</p> <--- Change range `{}` from `red` to `null`.\n\t\t\t// <p>Fo[zxb]ar</p> <--- Now change from `null` to `yellow` is completely fine.\n\t\t\t//\n\n\t\t\t// Generate complementary attribute operation. Be sure to add it before the original operation.\n\t\t\tconst op = _getComplementaryAttributeOperations( b, a.key, a.oldValue );\n\n\t\t\tif ( op ) {\n\t\t\t\tresult.unshift( op );\n\t\t\t}\n\t\t}\n\n\t\t// If nodes should not receive new attribute, we are done here.\n\t\treturn result;\n\t}\n\n\t// If insert operation is not expanding the attribute operation range, simply transform the range.\n\ta.range = a.range._getTransformedByInsertion( b.position, b.howMany, false )[ 0 ];\n\n\treturn [ a ];\n} );\n\n/**\n * Helper function for `AttributeOperation` x `InsertOperation` (and reverse) transformation.\n *\n * For given `insertOperation` it checks the inserted node if it has an attribute `key` set to a value different\n * than `newValue`. If so, it generates an `AttributeOperation` which changes the value of `key` attribute to `newValue`.\n *\n * @private\n * @param {module:engine/model/operation/insertoperation~InsertOperation} insertOperation\n * @param {String} key\n * @param {*} newValue\n * @returns {module:engine/model/operation/attributeoperation~AttributeOperation|null}\n */\nfunction _getComplementaryAttributeOperations( insertOperation, key, newValue ) {\n\tconst nodes = insertOperation.nodes;\n\n\t// At the beginning we store the attribute value from the first node.\n\tconst insertValue = nodes.getNode( 0 ).getAttribute( key );\n\n\tif ( insertValue == newValue ) {\n\t\treturn null;\n\t}\n\n\tconst range = new Range( insertOperation.position, insertOperation.position.getShiftedBy( insertOperation.howMany ) );\n\n\treturn new AttributeOperation( range, key, insertValue, newValue, 0 );\n}\n\nsetTransformation( AttributeOperation, MergeOperation, ( a, b ) => {\n\tconst ranges = [];\n\n\t// Case 1:\n\t//\n\t// Attribute change on the merged element. In this case, the merged element was moved to the graveyard.\n\t// An additional attribute operation that will change the (re)moved element needs to be generated.\n\t//\n\tif ( a.range.start.hasSameParentAs( b.deletionPosition ) ) {\n\t\tif ( a.range.containsPosition( b.deletionPosition ) || a.range.start.isEqual( b.deletionPosition ) ) {\n\t\t\tranges.push( Range._createFromPositionAndShift( b.graveyardPosition, 1 ) );\n\t\t}\n\t}\n\n\tconst range = a.range._getTransformedByMergeOperation( b );\n\n\t// Do not add empty (collapsed) ranges to the result. `range` may be collapsed if it contained only the merged element.\n\tif ( !range.isCollapsed ) {\n\t\tranges.push( range );\n\t}\n\n\t// Create `AttributeOperation`s out of the ranges.\n\treturn ranges.map( range => {\n\t\treturn new AttributeOperation( range, a.key, a.oldValue, a.newValue, a.baseVersion );\n\t} );\n} );\n\nsetTransformation( AttributeOperation, MoveOperation, ( a, b ) => {\n\tconst ranges = _breakRangeByMoveOperation( a.range, b );\n\n\t// Create `AttributeOperation`s out of the ranges.\n\treturn ranges.map( range => new AttributeOperation( range, a.key, a.oldValue, a.newValue, a.baseVersion ) );\n} );\n\n// Helper function for `AttributeOperation` x `MoveOperation` transformation.\n//\n// Takes the passed `range` and transforms it by move operation `moveOp` in a specific way. Only top-level nodes of `range`\n// are considered to be in the range. If move operation moves nodes deep from inside of the range, those nodes won't\n// be included in the result. In other words, top-level nodes of the ranges from the result are exactly the same as\n// top-level nodes of the original `range`.\n//\n// This is important for `AttributeOperation` because, for its range, it changes only the top-level nodes. So we need to\n// track only how those nodes have been affected by `MoveOperation`.\n//\n// @private\n// @param {module:engine/model/range~Range} range\n// @param {module:engine/model/operation/moveoperation~MoveOperation} moveOp\n// @returns {Array.<module:engine/model/range~Range>}\nfunction _breakRangeByMoveOperation( range, moveOp ) {\n\tconst moveRange = Range._createFromPositionAndShift( moveOp.sourcePosition, moveOp.howMany );\n\n\t// We are transforming `range` (original range) by `moveRange` (range moved by move operation). As usual when it comes to\n\t// transforming a ranges, we may have a common part of the ranges and we may have a difference part (zero to two ranges).\n\tlet common = null;\n\tlet difference = [];\n\n\t// Let's compare the ranges.\n\tif ( moveRange.containsRange( range, true ) ) {\n\t\t// If the whole original range is moved, treat it whole as a common part. There's also no difference part.\n\t\tcommon = range;\n\t} else if ( range.start.hasSameParentAs( moveRange.start ) ) {\n\t\t// If the ranges are \"on the same level\" (in the same parent) then move operation may move exactly those nodes\n\t\t// that are changed by the attribute operation. In this case we get common part and difference part in the usual way.\n\t\tdifference = range.getDifference( moveRange );\n\t\tcommon = range.getIntersection( moveRange );\n\t} else {\n\t\t// In any other situation we assume that original range is different than move range, that is that move operation\n\t\t// moves other nodes that attribute operation change. Even if the moved range is deep inside in the original range.\n\t\t//\n\t\t// Note that this is different than in `.getIntersection` (we would get a common part in that case) and different\n\t\t// than `.getDifference` (we would get two ranges).\n\t\tdifference = [ range ];\n\t}\n\n\tconst result = [];\n\n\t// The default behaviour of `_getTransformedByMove` might get wrong results for difference part, though, so\n\t// we do it by hand.\n\tfor ( let diff of difference ) {\n\t\t// First, transform the range by removing moved nodes. Since this is a difference, this is safe, `null` won't be returned\n\t\t// as the range is different than the moved range.\n\t\tdiff = diff._getTransformedByDeletion( moveOp.sourcePosition, moveOp.howMany );\n\n\t\t// Transform also `targetPosition`.\n\t\tconst targetPosition = moveOp.getMovedRangeStart();\n\n\t\t// Spread the range only if moved nodes are inserted only between the top-level nodes of the `diff` range.\n\t\tconst spread = diff.start.hasSameParentAs( targetPosition );\n\n\t\t// Transform by insertion of moved nodes.\n\t\tdiff = diff._getTransformedByInsertion( targetPosition, moveOp.howMany, spread );\n\n\t\tresult.push( ...diff );\n\t}\n\n\t// Common part can be simply transformed by the move operation. This is because move operation will not target to\n\t// that common part (the operation would have to target inside its own moved range).\n\tif ( common ) {\n\t\tresult.push(\n\t\t\tcommon._getTransformedByMove( moveOp.sourcePosition, moveOp.targetPosition, moveOp.howMany, false )[ 0 ]\n\t\t);\n\t}\n\n\treturn result;\n}\n\nsetTransformation( AttributeOperation, SplitOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// Split node is the last node in `AttributeOperation#range`.\n\t// `AttributeOperation#range` needs to be expanded to include the new (split) node.\n\t//\n\t// Attribute `type` to be changed to `numbered` but the `listItem` is split.\n\t// <listItem type=\"bulleted\">foobar</listItem>\n\t//\n\t// After split:\n\t// <listItem type=\"bulleted\">foo</listItem><listItem type=\"bulleted\">bar</listItem>\n\t//\n\t// After attribute change:\n\t// <listItem type=\"numbered\">foo</listItem><listItem type=\"numbered\">foo</listItem>\n\t//\n\tif ( a.range.end.isEqual( b.insertionPosition ) ) {\n\t\tif ( !b.graveyardPosition ) {\n\t\t\ta.range.end.offset++;\n\t\t}\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 2:\n\t//\n\t// Split position is inside `AttributeOperation#range`, at the same level, so the nodes to change are\n\t// not going to make a flat range.\n\t//\n\t// Content with range-to-change and split position:\n\t// <p>Fo[zb^a]r</p>\n\t//\n\t// After split:\n\t// <p>Fozb</p><p>ar</p>\n\t//\n\t// Make two separate ranges containing all nodes to change:\n\t// <p>Fo[zb]</p><p>[a]r</p>\n\t//\n\tif ( a.range.start.hasSameParentAs( b.splitPosition ) && a.range.containsPosition( b.splitPosition ) ) {\n\t\tconst secondPart = a.clone();\n\n\t\tsecondPart.range = new Range(\n\t\t\tb.moveTargetPosition.clone(),\n\t\t\ta.range.end._getCombined( b.splitPosition, b.moveTargetPosition )\n\t\t);\n\n\t\ta.range.end = b.splitPosition.clone();\n\t\ta.range.end.stickiness = 'toPrevious';\n\n\t\treturn [ a, secondPart ];\n\t}\n\n\t// The default case.\n\t//\n\ta.range = a.range._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, AttributeOperation, ( a, b ) => {\n\tconst result = [ a ];\n\n\t// Case 1:\n\t//\n\t// The attribute operation range includes the position where nodes were inserted.\n\t// There are two possible scenarios: the inserted nodes were text and they should receive attributes or\n\t// the inserted nodes were elements and they should not receive attributes.\n\t//\n\t// This is a mirror scenario to the one described in `AttributeOperation` x `InsertOperation` transformation,\n\t// although this case is a little less complicated. In this case we simply need to change attributes of the\n\t// inserted nodes and that's it.\n\t//\n\tif ( a.shouldReceiveAttributes && a.position.hasSameParentAs( b.range.start ) && b.range.containsPosition( a.position ) ) {\n\t\tconst op = _getComplementaryAttributeOperations( a, b.key, b.newValue );\n\n\t\tif ( op ) {\n\t\t\tresult.push( op );\n\t\t}\n\t}\n\n\t// The default case is: do nothing.\n\t// `AttributeOperation` does not change the model tree structure so `InsertOperation` does not need to be changed.\n\t//\n\treturn result;\n} );\n\nsetTransformation( InsertOperation, InsertOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Two insert operations insert nodes at the same position. Since they are the same, it needs to be decided\n\t// what will be the order of inserted nodes. However, there is no additional information to help in that\n\t// decision. Also, when `b` will be transformed by `a`, the same order must be maintained.\n\t//\n\t// To achieve that, we will check if the operation is strong.\n\t// If it is, it won't get transformed. If it is not, it will be moved.\n\t//\n\tif ( a.position.isEqual( b.position ) && context.aIsStrong ) {\n\t\treturn [ a ];\n\t}\n\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, MoveOperation, ( a, b ) => {\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedByMoveOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, SplitOperation, ( a, b ) => {\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, MergeOperation, ( a, b ) => {\n\ta.position = a.position._getTransformedByMergeOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( MarkerOperation, InsertOperation, ( a, b ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = a.oldRange._getTransformedByInsertOperation( b )[ 0 ];\n\t}\n\n\tif ( a.newRange ) {\n\t\ta.newRange = a.newRange._getTransformedByInsertOperation( b )[ 0 ];\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, MarkerOperation, ( a, b, context ) => {\n\tif ( a.name == b.name ) {\n\t\tif ( context.aIsStrong ) {\n\t\t\ta.oldRange = b.newRange ? b.newRange.clone() : null;\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, MergeOperation, ( a, b ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = a.oldRange._getTransformedByMergeOperation( b );\n\t}\n\n\tif ( a.newRange ) {\n\t\ta.newRange = a.newRange._getTransformedByMergeOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, MoveOperation, ( a, b, context ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = Range._createFromRanges( a.oldRange._getTransformedByMoveOperation( b ) );\n\t}\n\n\tif ( a.newRange ) {\n\t\tif ( context.abRelation ) {\n\t\t\tconst aNewRange = Range._createFromRanges( a.newRange._getTransformedByMoveOperation( b ) );\n\n\t\t\tif ( context.abRelation.side == 'left' && b.targetPosition.isEqual( a.newRange.start ) ) {\n\t\t\t\ta.newRange.start.path = context.abRelation.path;\n\t\t\t\ta.newRange.end = aNewRange.end;\n\n\t\t\t\treturn [ a ];\n\t\t\t} else if ( context.abRelation.side == 'right' && b.targetPosition.isEqual( a.newRange.end ) ) {\n\t\t\t\ta.newRange.start = aNewRange.start;\n\t\t\t\ta.newRange.end.path = context.abRelation.path;\n\n\t\t\t\treturn [ a ];\n\t\t\t}\n\t\t}\n\n\t\ta.newRange = Range._createFromRanges( a.newRange._getTransformedByMoveOperation( b ) );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, SplitOperation, ( a, b, context ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = a.oldRange._getTransformedBySplitOperation( b );\n\t}\n\n\tif ( a.newRange ) {\n\t\tif ( context.abRelation ) {\n\t\t\tconst aNewRange = a.newRange._getTransformedBySplitOperation( b );\n\n\t\t\tif ( a.newRange.start.isEqual( b.splitPosition ) && context.abRelation.wasStartBeforeMergedElement ) {\n\t\t\t\ta.newRange.start = Position._createAt( b.insertionPosition );\n\t\t\t} else if ( a.newRange.start.isEqual( b.splitPosition ) && !context.abRelation.wasInLeftElement ) {\n\t\t\t\ta.newRange.start = Position._createAt( b.moveTargetPosition );\n\t\t\t}\n\n\t\t\tif ( a.newRange.end.isEqual( b.splitPosition ) && context.abRelation.wasInRightElement ) {\n\t\t\t\ta.newRange.end = Position._createAt( b.moveTargetPosition );\n\t\t\t} else if ( a.newRange.end.isEqual( b.splitPosition ) && context.abRelation.wasEndBeforeMergedElement ) {\n\t\t\t\ta.newRange.end = Position._createAt( b.insertionPosition );\n\t\t\t} else {\n\t\t\t\ta.newRange.end = aNewRange.end;\n\t\t\t}\n\n\t\t\treturn [ a ];\n\t\t}\n\n\t\ta.newRange = a.newRange._getTransformedBySplitOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( MergeOperation, InsertOperation, ( a, b ) => {\n\tif ( a.sourcePosition.hasSameParentAs( b.position ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedByInsertOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( MergeOperation, MergeOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Same merge operations.\n\t//\n\t// Both operations have same source and target positions. So the element already got merged and there is\n\t// theoretically nothing to do.\n\t//\n\tif ( a.sourcePosition.isEqual( b.sourcePosition ) && a.targetPosition.isEqual( b.targetPosition ) ) {\n\t\t// There are two ways that we can provide a do-nothing operation.\n\t\t//\n\t\t// First is simply a NoOperation instance. We will use it if `b` operation was not undone.\n\t\t//\n\t\t// Second is a merge operation that has the source operation in the merged element - in the graveyard -\n\t\t// same target position and `howMany` equal to `0`. So it is basically merging an empty element from graveyard\n\t\t// which is almost the same as NoOperation.\n\t\t//\n\t\t// This way the merge operation can be later transformed by split operation\n\t\t// to provide correct undo. This will be used if `b` operation was undone (only then it is correct).\n\t\t//\n\t\tif ( !context.bWasUndone ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t} else {\n\t\t\tconst path = b.graveyardPosition.path.slice();\n\t\t\tpath.push( 0 );\n\n\t\t\ta.sourcePosition = new Position( b.graveyardPosition.root, path );\n\t\t\ta.howMany = 0;\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// Case 2:\n\t//\n\t// Same merge source position but different target position.\n\t//\n\t// This can happen during collaboration. For example, if one client merged a paragraph to the previous paragraph\n\t// and the other person removed that paragraph and merged the same paragraph to something before:\n\t//\n\t// Client A:\n\t// <p>Foo</p><p>Bar</p><p>[]Xyz</p>\n\t// <p>Foo</p><p>BarXyz</p>\n\t//\n\t// Client B:\n\t// <p>Foo</p>[<p>Bar</p>]<p>Xyz</p>\n\t// <p>Foo</p><p>[]Xyz</p>\n\t// <p>FooXyz</p>\n\t//\n\t// In this case we need to decide where finally \"Xyz\" will land:\n\t//\n\t// <p>FooXyz</p> graveyard: <p>Bar</p>\n\t// <p>Foo</p> graveyard: <p>BarXyz</p>\n\t//\n\t// Let's move it in a way so that a merge operation that does not target to graveyard is more important so that\n\t// nodes does not end up in the graveyard. It makes sense. Both for Client A and for Client B \"Xyz\" finally did not\n\t// end up in the graveyard (see above).\n\t//\n\t// If neither or both operations point to graveyard, then let `aIsStrong` decide.\n\t//\n\tif (\n\t\ta.sourcePosition.isEqual( b.sourcePosition ) && !a.targetPosition.isEqual( b.targetPosition ) &&\n\t\t!context.bWasUndone && context.abRelation != 'splitAtSource'\n\t) {\n\t\tconst aToGraveyard = a.targetPosition.root.rootName == '$graveyard';\n\t\tconst bToGraveyard = b.targetPosition.root.rootName == '$graveyard';\n\n\t\t// If `aIsWeak` it means that `a` points to graveyard while `b` doesn't. Don't move nodes then.\n\t\tconst aIsWeak = aToGraveyard && !bToGraveyard;\n\n\t\t// If `bIsWeak` it means that `b` points to graveyard while `a` doesn't. Force moving nodes then.\n\t\tconst bIsWeak = bToGraveyard && !aToGraveyard;\n\n\t\t// Force move if `b` is weak or neither operation is weak but `a` is stronger through `context.aIsStrong`.\n\t\tconst forceMove = bIsWeak || ( !aIsWeak && context.aIsStrong );\n\n\t\tif ( forceMove ) {\n\t\t\tconst sourcePosition = b.targetPosition._getTransformedByMergeOperation( b );\n\t\t\tconst targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\t\t\treturn [ new MoveOperation( sourcePosition, a.howMany, targetPosition, 0 ) ];\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.sourcePosition.hasSameParentAs( b.targetPosition ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedByMergeOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\t// Handle positions in graveyard.\n\t// If graveyard positions are same and `a` operation is strong - do not transform.\n\tif ( !a.graveyardPosition.isEqual( b.graveyardPosition ) || !context.aIsStrong ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMergeOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MergeOperation, MoveOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// The element to merge got removed.\n\t//\n\t// Merge operation does support merging elements which are not siblings. So it would not be a problem\n\t// from technical point of view. However, if the element was removed, the intention of the user deleting it\n\t// was to have it all deleted, together with its children. From user experience point of view, moving back the\n\t// removed nodes might be unexpected. This means that in this scenario we will block the merging.\n\t//\n\t// The exception of this rule would be if the remove operation was later undone.\n\t//\n\tconst removedRange = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );\n\n\tif ( b.type == 'remove' && !context.bWasUndone && !context.forceWeakRemove ) {\n\t\tif ( a.deletionPosition.hasSameParentAs( b.sourcePosition ) && removedRange.containsPosition( a.sourcePosition ) ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.sourcePosition.hasSameParentAs( b.targetPosition ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\tif ( a.sourcePosition.hasSameParentAs( b.sourcePosition ) ) {\n\t\ta.howMany -= b.howMany;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedByMoveOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedByMoveOperation( b );\n\n\t// `MergeOperation` graveyard position is like `MoveOperation` target position. It is a position where element(s) will\n\t// be moved. Like in other similar cases, we need to consider the scenario when those positions are same.\n\t// Here, we will treat `MergeOperation` like it is always strong (see `InsertOperation` x `InsertOperation` for comparison).\n\t// This means that we won't transform graveyard position if it is equal to move operation target position.\n\tif ( !a.graveyardPosition.isEqual( b.targetPosition ) ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMoveOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MergeOperation, SplitOperation, ( a, b, context ) => {\n\tif ( b.graveyardPosition ) {\n\t\t// If `b` operation defines graveyard position, a node from graveyard will be moved. This means that we need to\n\t\t// transform `a.graveyardPosition` accordingly.\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByDeletion( b.graveyardPosition, 1 );\n\n\t\t// This is a scenario foreseen in `MergeOperation` x `MergeOperation`, with two identical merge operations.\n\t\t//\n\t\t// So, there was `MergeOperation` x `MergeOperation` transformation earlier. Now, `a` is a merge operation which\n\t\t// source position is in graveyard. Interestingly, split operation wants to use the node to be merged by `a`. This\n\t\t// means that `b` is undoing that merge operation from earlier, which caused `a` to be in graveyard.\n\t\t//\n\t\t// If that's the case, at this point, we will only \"fix\" `a.howMany`. It was earlier set to `0` in\n\t\t// `MergeOperation` x `MergeOperation` transformation. Later transformations in this function will change other\n\t\t// properties.\n\t\t//\n\t\tif ( a.deletionPosition.isEqual( b.graveyardPosition ) ) {\n\t\t\ta.howMany = b.howMany;\n\t\t}\n\t}\n\n\t// Case 1:\n\t//\n\t// Merge operation moves nodes to the place where split happens.\n\t// This is a classic situation when there are two paragraphs, and there is a split (enter) after the first\n\t// paragraph and there is a merge (delete) at the beginning of the second paragraph:\n\t//\n\t// <p>Foo{}</p><p>[]Bar</p>.\n\t//\n\t// Split is after `Foo`, while merge is from `Bar` to the end of `Foo`.\n\t//\n\t// State after split:\n\t// <p>Foo</p><p></p><p>Bar</p>\n\t//\n\t// Now, `Bar` should be merged to the new paragraph:\n\t// <p>Foo</p><p>Bar</p>\n\t//\n\t// Instead of merging it to the original paragraph:\n\t// <p>FooBar</p><p></p>\n\t//\n\t// This means that `targetPosition` needs to be transformed. This is the default case though.\n\t// For example, if the split would be after `F`, `targetPosition` should also be transformed.\n\t//\n\t// There are three exceptions, though, when we want to keep `targetPosition` as it was.\n\t//\n\t// First exception is when the merge target position is inside an element (not at the end, as usual). This\n\t// happens when the merge operation earlier was transformed by \"the same\" merge operation. If merge operation\n\t// targets inside the element we want to keep the original target position (and not transform it) because\n\t// we have additional context telling us that we want to merge to the original element. We can check if the\n\t// merge operation points inside element by checking what is `SplitOperation#howMany`. Since merge target position\n\t// is same as split position, if `howMany` is non-zero, it means that the merge target position is inside an element.\n\t//\n\t// Second exception is when the element to merge is in the graveyard and split operation uses it. In that case\n\t// if target position would be transformed, the merge operation would target at the source position:\n\t//\n\t// root: <p>Foo</p>\t\t\t\tgraveyard: <p></p>\n\t//\n\t// SplitOperation: root [ 0, 3 ] using graveyard [ 0 ] (howMany = 0)\n\t// MergeOperation: graveyard [ 0, 0 ] -> root [ 0, 3 ] (howMany = 0)\n\t//\n\t// Since split operation moves the graveyard node back to the root, the merge operation source position changes.\n\t// We would like to merge from the empty <p> to the \"Foo\" <p>:\n\t//\n\t// root: <p>Foo</p><p></p>\t\t\tgraveyard:\n\t//\n\t// MergeOperation#sourcePosition = root [ 1, 0 ]\n\t//\n\t// If `targetPosition` is transformed, it would become root [ 1, 0 ] as well. It has to be kept as it was.\n\t//\n\t// Third exception is connected with relations. If this happens during undo and we have explicit information\n\t// that target position has not been affected by the operation which is undone by this split then this split should\n\t// not move the target position either.\n\t//\n\tif ( a.targetPosition.isEqual( b.splitPosition ) ) {\n\t\tconst mergeInside = b.howMany != 0;\n\t\tconst mergeSplittingElement = b.graveyardPosition && a.deletionPosition.isEqual( b.graveyardPosition );\n\n\t\tif ( mergeInside || mergeSplittingElement || context.abRelation == 'mergeTargetNotMoved' ) {\n\t\t\ta.sourcePosition = a.sourcePosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// Case 2:\n\t//\n\t// Merge source is at the same position as split position. This sometimes happen, mostly during undo.\n\t// The decision here is mostly to choose whether merge source position should stay where it is (so it will be at the end of the\n\t// split element) or should be move to the beginning of the new element.\n\t//\n\tif ( a.sourcePosition.isEqual( b.splitPosition ) ) {\n\t\t// Use context to check if `SplitOperation` is not undoing a merge operation, that didn't change the `a` operation.\n\t\t// This scenario happens the undone merge operation moved nodes at the source position of `a` operation.\n\t\t// In that case `a` operation source position should stay where it is.\n\t\tif ( context.abRelation == 'mergeSourceNotMoved' ) {\n\t\t\ta.howMany = 0;\n\t\t\ta.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\n\t\t// This merge operation might have been earlier transformed by a merge operation which both merged the same element.\n\t\t// See that case in `MergeOperation` x `MergeOperation` transformation. In that scenario, if the merge operation has been undone,\n\t\t// the special case is not applied.\n\t\t//\n\t\t// Now, the merge operation is transformed by the split which has undone that previous merge operation.\n\t\t// So now we are fixing situation which was skipped in `MergeOperation` x `MergeOperation` case.\n\t\t//\n\t\tif ( context.abRelation == 'mergeSameElement' || a.sourcePosition.offset > 0 ) {\n\t\t\ta.sourcePosition = b.moveTargetPosition.clone();\n\t\t\ta.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.sourcePosition.hasSameParentAs( b.splitPosition ) ) {\n\t\ta.howMany = b.splitPosition.offset;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedBySplitOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( MoveOperation, InsertOperation, ( a, b ) => {\n\tconst moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\tconst transformed = moveRange._getTransformedByInsertOperation( b, false )[ 0 ];\n\n\ta.sourcePosition = transformed.start;\n\ta.howMany = transformed.end.offset - transformed.start.offset;\n\n\t// See `InsertOperation` x `MoveOperation` transformation for details on this case.\n\t//\n\t// In summary, both operations point to the same place, so the order of nodes needs to be decided.\n\t// `MoveOperation` is considered weaker, so it is always transformed, unless there was a certain relation\n\t// between operations.\n\t//\n\tif ( !a.targetPosition.isEqual( b.position ) ) {\n\t\ta.targetPosition = a.targetPosition._getTransformedByInsertOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MoveOperation, MoveOperation, ( a, b, context ) => {\n\t//\n\t// Setting and evaluating some variables that will be used in special cases and default algorithm.\n\t//\n\t// Create ranges from `MoveOperations` properties.\n\tconst rangeA = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\tconst rangeB = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );\n\n\t// Assign `context.aIsStrong` to a different variable, because the value may change during execution of\n\t// this algorithm and we do not want to override original `context.aIsStrong` that will be used in later transformations.\n\tlet aIsStrong = context.aIsStrong;\n\n\t// This will be used to decide the order of nodes if both operations target at the same position.\n\t// By default, use strong/weak operation mechanism.\n\tlet insertBefore = !context.aIsStrong;\n\n\t// If the relation is set, then use it to decide nodes order.\n\tif ( context.abRelation == 'insertBefore' || context.baRelation == 'insertAfter' ) {\n\t\tinsertBefore = true;\n\t} else if ( context.abRelation == 'insertAfter' || context.baRelation == 'insertBefore' ) {\n\t\tinsertBefore = false;\n\t}\n\n\t// `a.targetPosition` could be affected by the `b` operation. We will transform it.\n\tlet newTargetPosition;\n\n\tif ( a.targetPosition.isEqual( b.targetPosition ) && insertBefore ) {\n\t\tnewTargetPosition = a.targetPosition._getTransformedByDeletion(\n\t\t\tb.sourcePosition,\n\t\t\tb.howMany\n\t\t);\n\t} else {\n\t\tnewTargetPosition = a.targetPosition._getTransformedByMove(\n\t\t\tb.sourcePosition,\n\t\t\tb.targetPosition,\n\t\t\tb.howMany\n\t\t);\n\t}\n\n\t//\n\t// Special case #1 + mirror.\n\t//\n\t// Special case when both move operations' target positions are inside nodes that are\n\t// being moved by the other move operation. So in other words, we move ranges into inside of each other.\n\t// This case can't be solved reasonably (on the other hand, it should not happen often).\n\tif ( _moveTargetIntoMovedRange( a, b ) && _moveTargetIntoMovedRange( b, a ) ) {\n\t\t// Instead of transforming operation, we return a reverse of the operation that we transform by.\n\t\t// So when the results of this \"transformation\" will be applied, `b` MoveOperation will get reversed.\n\t\treturn [ b.getReversed() ];\n\t}\n\t//\n\t// End of special case #1.\n\t//\n\n\t//\n\t// Special case #2.\n\t//\n\t// Check if `b` operation targets inside `rangeA`.\n\tconst bTargetsToA = rangeA.containsPosition( b.targetPosition );\n\n\t// If `b` targets to `rangeA` and `rangeA` contains `rangeB`, `b` operation has no influence on `a` operation.\n\t// You might say that operation `b` is captured inside operation `a`.\n\tif ( bTargetsToA && rangeA.containsRange( rangeB, true ) ) {\n\t\t// There is a mini-special case here, where `rangeB` is on other level than `rangeA`. That's why\n\t\t// we need to transform `a` operation anyway.\n\t\trangeA.start = rangeA.start._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\t\trangeA.end = rangeA.end._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\n\t\treturn _makeMoveOperationsFromRanges( [ rangeA ], newTargetPosition );\n\t}\n\n\t//\n\t// Special case #2 mirror.\n\t//\n\tconst aTargetsToB = rangeB.containsPosition( a.targetPosition );\n\n\tif ( aTargetsToB && rangeB.containsRange( rangeA, true ) ) {\n\t\t// `a` operation is \"moved together\" with `b` operation.\n\t\t// Here, just move `rangeA` \"inside\" `rangeB`.\n\t\trangeA.start = rangeA.start._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\t\trangeA.end = rangeA.end._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\n\t\treturn _makeMoveOperationsFromRanges( [ rangeA ], newTargetPosition );\n\t}\n\t//\n\t// End of special case #2.\n\t//\n\n\t//\n\t// Special case #3 + mirror.\n\t//\n\t// `rangeA` has a node which is an ancestor of `rangeB`. In other words, `rangeB` is inside `rangeA`\n\t// but not on the same tree level. In such case ranges have common part but we have to treat it\n\t// differently, because in such case those ranges are not really conflicting and should be treated like\n\t// two separate ranges. Also we have to discard two difference parts.\n\tconst aCompB = compareArrays( a.sourcePosition.getParentPath(), b.sourcePosition.getParentPath() );\n\n\tif ( aCompB == 'prefix' || aCompB == 'extension' ) {\n\t\t// Transform `rangeA` by `b` operation and make operation out of it, and that's all.\n\t\t// Note that this is a simplified version of default case, but here we treat the common part (whole `rangeA`)\n\t\t// like a one difference part.\n\t\trangeA.start = rangeA.start._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\t\trangeA.end = rangeA.end._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\n\t\treturn _makeMoveOperationsFromRanges( [ rangeA ], newTargetPosition );\n\t}\n\t//\n\t// End of special case #3.\n\t//\n\n\t//\n\t// Default case - ranges are on the same level or are not connected with each other.\n\t//\n\t// Modifier for default case.\n\t// Modifies `aIsStrong` flag in certain conditions.\n\t//\n\t// If only one of operations is a remove operation, we force remove operation to be the \"stronger\" one\n\t// to provide more expected results.\n\tif ( a.type == 'remove' && b.type != 'remove' && !context.aWasUndone && !context.forceWeakRemove ) {\n\t\taIsStrong = true;\n\t} else if ( a.type != 'remove' && b.type == 'remove' && !context.bWasUndone && !context.forceWeakRemove ) {\n\t\taIsStrong = false;\n\t}\n\n\t// Handle operation's source ranges - check how `rangeA` is affected by `b` operation.\n\t// This will aggregate transformed ranges.\n\tconst ranges = [];\n\n\t// Get the \"difference part\" of `a` operation source range.\n\t// This is an array with one or two ranges. Two ranges if `rangeB` is inside `rangeA`.\n\tconst difference = rangeA.getDifference( rangeB );\n\n\tfor ( const range of difference ) {\n\t\t// Transform those ranges by `b` operation. For example if `b` moved range from before those ranges, fix those ranges.\n\t\trange.start = range.start._getTransformedByDeletion( b.sourcePosition, b.howMany );\n\t\trange.end = range.end._getTransformedByDeletion( b.sourcePosition, b.howMany );\n\n\t\t// If `b` operation targets into `rangeA` on the same level, spread `rangeA` into two ranges.\n\t\tconst shouldSpread = compareArrays( range.start.getParentPath(), b.getMovedRangeStart().getParentPath() ) == 'same';\n\t\tconst newRanges = range._getTransformedByInsertion( b.getMovedRangeStart(), b.howMany, shouldSpread );\n\n\t\tranges.push( ...newRanges );\n\t}\n\n\t// Then, we have to manage the \"common part\" of both move ranges.\n\tconst common = rangeA.getIntersection( rangeB );\n\n\tif ( common !== null && aIsStrong ) {\n\t\t// Calculate the new position of that part of original range.\n\t\tcommon.start = common.start._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\t\tcommon.end = common.end._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\n\t\t// Take care of proper range order.\n\t\t//\n\t\t// Put `common` at appropriate place. Keep in mind that we are interested in original order.\n\t\t// Basically there are only three cases: there is zero, one or two difference ranges.\n\t\t//\n\t\t// If there is zero difference ranges, just push `common` in the array.\n\t\tif ( ranges.length === 0 ) {\n\t\t\tranges.push( common );\n\t\t}\n\t\t// If there is one difference range, we need to check whether common part was before it or after it.\n\t\telse if ( ranges.length == 1 ) {\n\t\t\tif ( rangeB.start.isBefore( rangeA.start ) || rangeB.start.isEqual( rangeA.start ) ) {\n\t\t\t\tranges.unshift( common );\n\t\t\t} else {\n\t\t\t\tranges.push( common );\n\t\t\t}\n\t\t}\n\t\t// If there are more ranges (which means two), put common part between them. This is the only scenario\n\t\t// where there could be two difference ranges so we don't have to make any comparisons.\n\t\telse {\n\t\t\tranges.splice( 1, 0, common );\n\t\t}\n\t}\n\n\tif ( ranges.length === 0 ) {\n\t\t// If there are no \"source ranges\", nothing should be changed.\n\t\t// Note that this can happen only if `aIsStrong == false` and `rangeA.isEqual( rangeB )`.\n\t\treturn [ new NoOperation( a.baseVersion ) ];\n\t}\n\n\treturn _makeMoveOperationsFromRanges( ranges, newTargetPosition );\n} );\n\nsetTransformation( MoveOperation, SplitOperation, ( a, b, context ) => {\n\tlet newTargetPosition = a.targetPosition.clone();\n\n\t// Do not transform if target position is same as split insertion position and this split comes from undo.\n\t// This should be done on relations but it is too much work for now as it would require relations working in collaboration.\n\t// We need to make a decision how we will resolve such conflict and this is less harmful way.\n\tif ( !a.targetPosition.isEqual( b.insertionPosition ) || !b.graveyardPosition || context.abRelation == 'moveTargetAfter' ) {\n\t\tnewTargetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\t}\n\n\t// Case 1:\n\t//\n\t// Last element in the moved range got split.\n\t//\n\t// In this case the default range transformation will not work correctly as the element created by\n\t// split operation would be outside the range. The range to move needs to be fixed manually.\n\t//\n\tconst moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\n\tif ( moveRange.end.isEqual( b.insertionPosition ) ) {\n\t\t// Do it only if this is a \"natural\" split, not a one that comes from undo.\n\t\t// If this is undo split, only `targetPosition` needs to be changed (if the move is a remove).\n\t\tif ( !b.graveyardPosition ) {\n\t\t\ta.howMany++;\n\t\t}\n\n\t\ta.targetPosition = newTargetPosition;\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 2:\n\t//\n\t// Split happened between the moved nodes. In this case two ranges to move need to be generated.\n\t//\n\t// Characters `ozba` are moved to the end of paragraph `Xyz` but split happened.\n\t// <p>F[oz|ba]r</p><p>Xyz</p>\n\t//\n\t// After split:\n\t// <p>F[oz</p><p>ba]r</p><p>Xyz</p>\n\t//\n\t// Correct ranges:\n\t// <p>F[oz]</p><p>[ba]r</p><p>Xyz</p>\n\t//\n\t// After move:\n\t// <p>F</p><p>r</p><p>Xyzozba</p>\n\t//\n\tif ( moveRange.start.hasSameParentAs( b.splitPosition ) && moveRange.containsPosition( b.splitPosition ) ) {\n\t\tlet rightRange = new Range( b.splitPosition, moveRange.end );\n\t\trightRange = rightRange._getTransformedBySplitOperation( b );\n\n\t\tconst ranges = [\n\t\t\tnew Range( moveRange.start, b.splitPosition ),\n\t\t\trightRange\n\t\t];\n\n\t\treturn _makeMoveOperationsFromRanges( ranges, newTargetPosition );\n\t}\n\n\t// Case 3:\n\t//\n\t// Move operation targets at the split position. We need to decide if the nodes should be inserted\n\t// at the end of the split element or at the beginning of the new element.\n\t//\n\tif ( a.targetPosition.isEqual( b.splitPosition ) && context.abRelation == 'insertAtSource' ) {\n\t\tnewTargetPosition = b.moveTargetPosition;\n\t}\n\n\t// Case 4:\n\t//\n\t// Move operation targets just after the split element. We need to decide if the nodes should be inserted\n\t// between two parts of split element, or after the new element.\n\t//\n\t// Split at `|`, while move operation moves `<p>Xyz</p>` and targets at `^`:\n\t// <p>Foo|bar</p>^<p>baz</p>\n\t// <p>Foo</p>^<p>bar</p><p>baz</p> or <p>Foo</p><p>bar</p>^<p>baz</p>?\n\t//\n\t// If there is no contextual information between operations (for example, they come from collaborative\n\t// editing), we don't want to put some unrelated content (move) between parts of related content (split parts).\n\t// However, if the split is from undo, in the past, the moved content might be targeting between the\n\t// split parts, meaning that was exactly user's intention:\n\t//\n\t// <p>Foo</p>^<p>bar</p>\t\t<--- original situation, in \"past\".\n\t// <p>Foobar</p>^\t\t\t\t<--- after merge target position is transformed.\n\t// <p>Foo|bar</p>^\t\t\t\t<--- then the merge is undone, and split happens, which leads us to current situation.\n\t//\n\t// In this case it is pretty clear that the intention was to put new paragraph between those nodes,\n\t// so we need to transform accordingly. We can detect this scenario thanks to relations.\n\t//\n\tif ( a.targetPosition.isEqual( b.insertionPosition ) && context.abRelation == 'insertBetween' ) {\n\t\tnewTargetPosition = a.targetPosition;\n\t}\n\n\t// The default case.\n\t//\n\tconst transformed = moveRange._getTransformedBySplitOperation( b );\n\tconst ranges = [ transformed ];\n\n\t// Case 5:\n\t//\n\t// Moved range contains graveyard element used by split operation. Add extra move operation to the result.\n\t//\n\tif ( b.graveyardPosition ) {\n\t\tconst movesGraveyardElement = moveRange.start.isEqual( b.graveyardPosition ) || moveRange.containsPosition( b.graveyardPosition );\n\n\t\tif ( a.howMany > 1 && movesGraveyardElement && !context.aWasUndone ) {\n\t\t\tranges.push( Range._createFromPositionAndShift( b.insertionPosition, 1 ) );\n\t\t}\n\t}\n\n\treturn _makeMoveOperationsFromRanges( ranges, newTargetPosition );\n} );\n\nsetTransformation( MoveOperation, MergeOperation, ( a, b, context ) => {\n\tconst movedRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\n\tif ( b.deletionPosition.hasSameParentAs( a.sourcePosition ) && movedRange.containsPosition( b.sourcePosition ) ) {\n\t\tif ( a.type == 'remove' && !context.forceWeakRemove ) {\n\t\t\t// Case 1:\n\t\t\t//\n\t\t\t// The element to remove got merged.\n\t\t\t//\n\t\t\t// Merge operation does support merging elements which are not siblings. So it would not be a problem\n\t\t\t// from technical point of view. However, if the element was removed, the intention of the user\n\t\t\t// deleting it was to have it all deleted. From user experience point of view, moving back the\n\t\t\t// removed nodes might be unexpected. This means that in this scenario we will reverse merging and remove the element.\n\t\t\t//\n\t\t\tif ( !context.aWasUndone ) {\n\t\t\t\tconst results = [];\n\n\t\t\t\tlet gyMoveSource = b.graveyardPosition.clone();\n\t\t\t\tlet splitNodesMoveSource = b.targetPosition._getTransformedByMergeOperation( b );\n\n\t\t\t\tif ( a.howMany > 1 ) {\n\t\t\t\t\tresults.push( new MoveOperation( a.sourcePosition, a.howMany - 1, a.targetPosition, 0 ) );\n\n\t\t\t\t\tgyMoveSource = gyMoveSource._getTransformedByMove( a.sourcePosition, a.targetPosition, a.howMany - 1 );\n\t\t\t\t\tsplitNodesMoveSource = splitNodesMoveSource._getTransformedByMove( a.sourcePosition, a.targetPosition, a.howMany - 1 );\n\t\t\t\t}\n\n\t\t\t\tconst gyMoveTarget = b.deletionPosition._getCombined( a.sourcePosition, a.targetPosition );\n\t\t\t\tconst gyMove = new MoveOperation( gyMoveSource, 1, gyMoveTarget, 0 );\n\n\t\t\t\tconst splitNodesMoveTargetPath = gyMove.getMovedRangeStart().path.slice();\n\t\t\t\tsplitNodesMoveTargetPath.push( 0 );\n\n\t\t\t\tconst splitNodesMoveTarget = new Position( gyMove.targetPosition.root, splitNodesMoveTargetPath );\n\t\t\t\tsplitNodesMoveSource = splitNodesMoveSource._getTransformedByMove( gyMoveSource, gyMoveTarget, 1 );\n\t\t\t\tconst splitNodesMove = new MoveOperation( splitNodesMoveSource, b.howMany, splitNodesMoveTarget, 0 );\n\n\t\t\t\tresults.push( gyMove );\n\t\t\t\tresults.push( splitNodesMove );\n\n\t\t\t\treturn results;\n\t\t\t}\n\t\t} else {\n\t\t\t// Case 2:\n\t\t\t//\n\t\t\t// The element to move got merged and it was the only element to move.\n\t\t\t// In this case just don't do anything, leave the node in the graveyard. Without special case\n\t\t\t// it would be a move operation that moves 0 nodes, so maybe it is better just to return no-op.\n\t\t\t//\n\t\t\tif ( a.howMany == 1 ) {\n\t\t\t\tif ( !context.bWasUndone ) {\n\t\t\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t\t\t} else {\n\t\t\t\t\ta.sourcePosition = b.graveyardPosition.clone();\n\t\t\t\t\ta.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\t\t\t\t\treturn [ a ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tconst moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\tconst transformed = moveRange._getTransformedByMergeOperation( b );\n\n\ta.sourcePosition = transformed.start;\n\ta.howMany = transformed.end.offset - transformed.start.offset;\n\ta.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( RenameOperation, InsertOperation, ( a, b ) => {\n\ta.position = a.position._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, MergeOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// Element to rename got merged, so it was moved to `b.graveyardPosition`.\n\t//\n\tif ( a.position.isEqual( b.deletionPosition ) ) {\n\t\ta.position = b.graveyardPosition.clone();\n\t\ta.position.stickiness = 'toNext';\n\n\t\treturn [ a ];\n\t}\n\n\ta.position = a.position._getTransformedByMergeOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, MoveOperation, ( a, b ) => {\n\ta.position = a.position._getTransformedByMoveOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, RenameOperation, ( a, b, context ) => {\n\tif ( a.position.isEqual( b.position ) ) {\n\t\tif ( context.aIsStrong ) {\n\t\t\ta.oldName = b.newName;\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, SplitOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// The element to rename has been split. In this case, the new element should be also renamed.\n\t//\n\t// User decides to change the paragraph to a list item:\n\t// <paragraph>Foobar</paragraph>\n\t//\n\t// However, in meantime, split happens:\n\t// <paragraph>Foo</paragraph><paragraph>bar</paragraph>\n\t//\n\t// As a result, rename both elements:\n\t// <listItem>Foo</listItem><listItem>bar</listItem>\n\t//\n\tconst renamePath = a.position.path;\n\tconst splitPath = b.splitPosition.getParentPath();\n\n\tif ( compareArrays( renamePath, splitPath ) == 'same' && !b.graveyardPosition ) {\n\t\tconst extraRename = new RenameOperation( a.position.getShiftedBy( 1 ), a.oldName, a.newName, 0 );\n\n\t\treturn [ a, extraRename ];\n\t}\n\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( RootAttributeOperation, RootAttributeOperation, ( a, b, context ) => {\n\tif ( a.root === b.root && a.key === b.key ) {\n\t\tif ( !context.aIsStrong || a.newValue === b.newValue ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t} else {\n\t\t\ta.oldValue = b.newValue;\n\t\t}\n\t}\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( SplitOperation, InsertOperation, ( a, b ) => {\n\t// The default case.\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.position ) && a.splitPosition.offset < b.position.offset ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.splitPosition = a.splitPosition._getTransformedByInsertOperation( b );\n\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\treturn [ a ];\n} );\n\nsetTransformation( SplitOperation, MergeOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Split element got merged. If two different elements were merged, clients will have different content.\n\t//\n\t// Example. Merge at `{}`, split at `[]`:\n\t// <heading>Foo</heading>{}<paragraph>B[]ar</paragraph>\n\t//\n\t// On merge side it will look like this:\n\t// <heading>FooB[]ar</heading>\n\t// <heading>FooB</heading><heading>ar</heading>\n\t//\n\t// On split side it will look like this:\n\t// <heading>Foo</heading>{}<paragraph>B</paragraph><paragraph>ar</paragraph>\n\t// <heading>FooB</heading><paragraph>ar</paragraph>\n\t//\n\t// Clearly, the second element is different for both clients.\n\t//\n\t// We could use the removed merge element from graveyard as a split element but then clients would have a different\n\t// model state (in graveyard), because the split side client would still have an element in graveyard (removed by merge).\n\t//\n\t// To overcome this, in `SplitOperation` x `MergeOperation` transformation we will add additional `SplitOperation`\n\t// in the graveyard, which will actually clone the merged-and-deleted element. Then, that cloned element will be\n\t// used for splitting. Example below.\n\t//\n\t// Original state:\n\t// <heading>Foo</heading>{}<paragraph>B[]ar</paragraph>\n\t//\n\t// Merge side client:\n\t//\n\t// After merge:\n\t// <heading>FooB[]ar</heading> graveyard: <paragraph></paragraph>\n\t//\n\t// Extra split:\n\t// <heading>FooB[]ar</heading> graveyard: <paragraph></paragraph><paragraph></paragraph>\n\t//\n\t// Use the \"cloned\" element from graveyard:\n\t// <heading>FooB</heading><paragraph>ar</paragraph> graveyard: <paragraph></paragraph>\n\t//\n\t// Split side client:\n\t//\n\t// After split:\n\t// <heading>Foo</heading>{}<paragraph>B</paragraph><paragraph>ar</paragraph>\n\t//\n\t// After merge:\n\t// <heading>FooB</heading><paragraph>ar</paragraph> graveyard: <paragraph></paragraph>\n\t//\n\t// This special case scenario only applies if the original split operation clones the split element.\n\t// If the original split operation has `graveyardPosition` set, it all doesn't have sense because split operation\n\t// knows exactly which element it should use. So there would be no original problem with different contents.\n\t//\n\t// Additionally, the special case applies only if the merge wasn't already undone.\n\t//\n\tif ( !a.graveyardPosition && !context.bWasUndone && a.splitPosition.hasSameParentAs( b.sourcePosition ) ) {\n\t\tconst splitPath = b.graveyardPosition.path.slice();\n\t\tsplitPath.push( 0 );\n\n\t\tconst splitPosition = new Position( b.graveyardPosition.root, splitPath );\n\t\tconst insertionPosition = SplitOperation.getInsertionPosition( new Position( b.graveyardPosition.root, splitPath ) );\n\n\t\tconst additionalSplit = new SplitOperation( splitPosition, 0, null, 0 );\n\t\tadditionalSplit.insertionPosition = insertionPosition;\n\n\t\ta.splitPosition = a.splitPosition._getTransformedByMergeOperation( b );\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\t\ta.graveyardPosition = additionalSplit.insertionPosition.clone();\n\t\ta.graveyardPosition.stickiness = 'toNext';\n\n\t\treturn [ additionalSplit, a ];\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.deletionPosition ) && !a.splitPosition.isAfter( b.deletionPosition ) ) {\n\t\ta.howMany--;\n\t}\n\n\tif ( a.splitPosition.hasSameParentAs( b.targetPosition ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.splitPosition = a.splitPosition._getTransformedByMergeOperation( b );\n\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\tif ( a.graveyardPosition ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMergeOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( SplitOperation, MoveOperation, ( a, b, context ) => {\n\tconst rangeToMove = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );\n\n\tif ( a.graveyardPosition ) {\n\t\t// Case 1:\n\t\t//\n\t\t// Split operation graveyard node was moved. In this case move operation is stronger. Since graveyard element\n\t\t// is already moved to the correct position, we need to only move the nodes after the split position.\n\t\t// This will be done by `MoveOperation` instead of `SplitOperation`.\n\t\t//\n\t\tconst gyElementMoved = rangeToMove.start.isEqual( a.graveyardPosition ) || rangeToMove.containsPosition( a.graveyardPosition );\n\n\t\tif ( !context.bWasUndone && gyElementMoved ) {\n\t\t\tconst sourcePosition = a.splitPosition._getTransformedByMoveOperation( b );\n\n\t\t\tconst newParentPosition = a.graveyardPosition._getTransformedByMoveOperation( b );\n\t\t\tconst newTargetPath = newParentPosition.path.slice();\n\t\t\tnewTargetPath.push( 0 );\n\n\t\t\tconst newTargetPosition = new Position( newParentPosition.root, newTargetPath );\n\t\t\tconst moveOp = new MoveOperation( sourcePosition, a.howMany, newTargetPosition, 0 );\n\n\t\t\treturn [ moveOp ];\n\t\t}\n\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMoveOperation( b );\n\t}\n\n\t// Case 2:\n\t//\n\t// If the split position is inside the moved range, we need to shift the split position to a proper place.\n\t// The position cannot be moved together with moved range because that would result in splitting of an incorrect element.\n\t//\n\t// Characters `bc` should be moved to the second paragraph while split position is between them:\n\t// <paragraph>A[b|c]d</paragraph><paragraph>Xyz</paragraph>\n\t//\n\t// After move, new split position is incorrect:\n\t// <paragraph>Ad</paragraph><paragraph>Xb|cyz</paragraph>\n\t//\n\t// Correct split position:\n\t// <paragraph>A|d</paragraph><paragraph>Xbcyz</paragraph>\n\t//\n\t// After split:\n\t// <paragraph>A</paragraph><paragraph>d</paragraph><paragraph>Xbcyz</paragraph>\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.sourcePosition ) && rangeToMove.containsPosition( a.splitPosition ) ) {\n\t\tconst howManyRemoved = b.howMany - ( a.splitPosition.offset - b.sourcePosition.offset );\n\t\ta.howMany -= howManyRemoved;\n\n\t\tif ( a.splitPosition.hasSameParentAs( b.targetPosition ) && a.splitPosition.offset < b.targetPosition.offset ) {\n\t\t\ta.howMany += b.howMany;\n\t\t}\n\n\t\ta.splitPosition = b.sourcePosition.clone();\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 3:\n\t//\n\t// Split is at a position where nodes were moved.\n\t//\n\t// This is a scenario described in `MoveOperation` x `SplitOperation` transformation but from the\n\t// \"split operation point of view\".\n\t//\n\tconst splitAtTarget = a.splitPosition.isEqual( b.targetPosition );\n\n\tif ( splitAtTarget && ( context.baRelation == 'insertAtSource' || context.abRelation == 'splitBefore' ) ) {\n\t\ta.howMany += b.howMany;\n\t\ta.splitPosition = a.splitPosition._getTransformedByDeletion( b.sourcePosition, b.howMany );\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\t\treturn [ a ];\n\t}\n\n\t// The default case.\n\t// Don't change `howMany` if move operation does not really move anything.\n\t//\n\tif ( !b.sourcePosition.isEqual( b.targetPosition ) ) {\n\t\tif ( a.splitPosition.hasSameParentAs( b.sourcePosition ) && a.splitPosition.offset <= b.sourcePosition.offset ) {\n\t\t\ta.howMany -= b.howMany;\n\t\t}\n\n\t\tif ( a.splitPosition.hasSameParentAs( b.targetPosition ) && a.splitPosition.offset < b.targetPosition.offset ) {\n\t\t\ta.howMany += b.howMany;\n\t\t}\n\t}\n\n\t// Change position stickiness to force a correct transformation.\n\ta.splitPosition.stickiness = 'toNone';\n\ta.splitPosition = a.splitPosition._getTransformedByMoveOperation( b );\n\ta.splitPosition.stickiness = 'toNext';\n\n\tif ( a.graveyardPosition ) {\n\t\ta.insertionPosition = a.insertionPosition._getTransformedByMoveOperation( b );\n\t} else {\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( SplitOperation, SplitOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Split at the same position.\n\t//\n\t// If there already was a split at the same position as in `a` operation, it means that the intention\n\t// conveyed by `a` operation has already been fulfilled and `a` should not do anything (to avoid double split).\n\t//\n\t// However, there is a difference if these are new splits or splits created by undo. These have different\n\t// intentions. Also splits moving back different elements from graveyard have different intentions. They\n\t// are just different operations.\n\t//\n\t// So we cancel split operation only if it was really identical.\n\t//\n\t// Also, there is additional case, where split operations aren't identical and should not be cancelled, however the\n\t// default transformation is incorrect too.\n\t//\n\tif ( a.splitPosition.isEqual( b.splitPosition ) ) {\n\t\tif ( !a.graveyardPosition && !b.graveyardPosition ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\n\t\tif ( a.graveyardPosition && b.graveyardPosition && a.graveyardPosition.isEqual( b.graveyardPosition ) ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\n\t\t// Use context to know that the `a.splitPosition` should stay where it is.\n\t\t// This happens during undo when first a merge operation moved nodes to `a.splitPosition` and now `b` operation undoes that merge.\n\t\tif ( context.abRelation == 'splitBefore' ) {\n\t\t\t// Since split is at the same position, there are no nodes left to split.\n\t\t\ta.howMany = 0;\n\n\t\t\t// Note: there was `if ( a.graveyardPosition )` here but it was uncovered in tests and I couldn't find any scenarios for now.\n\t\t\t// That would have to be a `SplitOperation` that didn't come from undo but is transformed by operations that were undone.\n\t\t\t// It could happen if `context` is enabled in collaboration.\n\t\t\ta.graveyardPosition = a.graveyardPosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// Case 2:\n\t//\n\t// Same node is using to split different elements. This happens in undo when previously same element was merged to\n\t// two different elements. This is described in `MergeOperation` x `MergeOperation` transformation.\n\t//\n\t// In this case we will follow the same logic. We will assume that `insertionPosition` is same for both\n\t// split operations. This might not always be true but in the real cases that were experienced it was. After all,\n\t// if these splits are reverses of merge operations that were merging the same element, then the `insertionPosition`\n\t// should be same for both of those splits.\n\t//\n\t// Again, we will decide which operation is stronger by checking if split happens in graveyard or in non-graveyard root.\n\t//\n\tif ( a.graveyardPosition && b.graveyardPosition && a.graveyardPosition.isEqual( b.graveyardPosition ) ) {\n\t\tconst aInGraveyard = a.splitPosition.root.rootName == '$graveyard';\n\t\tconst bInGraveyard = b.splitPosition.root.rootName == '$graveyard';\n\n\t\t// If `aIsWeak` it means that `a` points to graveyard while `b` doesn't. Don't move nodes then.\n\t\tconst aIsWeak = aInGraveyard && !bInGraveyard;\n\n\t\t// If `bIsWeak` it means that `b` points to graveyard while `a` doesn't. Force moving nodes then.\n\t\tconst bIsWeak = bInGraveyard && !aInGraveyard;\n\n\t\t// Force move if `b` is weak or neither operation is weak but `a` is stronger through `context.aIsStrong`.\n\t\tconst forceMove = bIsWeak || ( !aIsWeak && context.aIsStrong );\n\n\t\tif ( forceMove ) {\n\t\t\tconst result = [];\n\n\t\t\t// First we need to move any nodes split by `b` back to where they were.\n\t\t\t// Do it only if `b` actually moved something.\n\t\t\tif ( b.howMany ) {\n\t\t\t\tresult.push( new MoveOperation( b.moveTargetPosition, b.howMany, b.splitPosition, 0 ) );\n\t\t\t}\n\n\t\t\t// Then we need to move nodes from `a` split position to their new element.\n\t\t\t// Do it only if `a` actually should move something.\n\t\t\tif ( a.howMany ) {\n\t\t\t\tresult.push( new MoveOperation( a.splitPosition, a.howMany, a.moveTargetPosition, 0 ) );\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\tif ( a.graveyardPosition ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedBySplitOperation( b );\n\t}\n\n\t// Case 3:\n\t//\n\t// Position where operation `b` inserted a new node after split is the same as the operation `a` split position.\n\t// As in similar cases, there is ambiguity if the split should be before the new node (created by `b`) or after.\n\t//\n\tif ( a.splitPosition.isEqual( b.insertionPosition ) && context.abRelation == 'splitBefore' ) {\n\t\ta.howMany++;\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 4:\n\t//\n\t// This is a mirror to the case 2. above.\n\t//\n\tif ( b.splitPosition.isEqual( a.insertionPosition ) && context.baRelation == 'splitBefore' ) {\n\t\tconst newPositionPath = b.insertionPosition.path.slice();\n\t\tnewPositionPath.push( 0 );\n\n\t\tconst newPosition = new Position( b.insertionPosition.root, newPositionPath );\n\t\tconst moveOp = new MoveOperation( a.insertionPosition, 1, newPosition, 0 );\n\n\t\treturn [ a, moveOp ];\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.splitPosition ) && a.splitPosition.offset < b.splitPosition.offset ) {\n\t\ta.howMany -= b.howMany;\n\t}\n\n\ta.splitPosition = a.splitPosition._getTransformedBySplitOperation( b );\n\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\treturn [ a ];\n} );\n\n// Checks whether `MoveOperation` `targetPosition` is inside a node from the moved range of the other `MoveOperation`.\n//\n// @private\n// @param {module:engine/model/operation/moveoperation~MoveOperation} a\n// @param {module:engine/model/operation/moveoperation~MoveOperation} b\n// @returns {Boolean}\nfunction _moveTargetIntoMovedRange( a, b ) {\n\treturn a.targetPosition._getTransformedByDeletion( b.sourcePosition, b.howMany ) === null;\n}\n\n// Helper function for `MoveOperation` x `MoveOperation` transformation. Converts given ranges and target position to\n// move operations and returns them.\n//\n// Ranges and target position will be transformed on-the-fly when generating operations.\n//\n// Given `ranges` should be in the order of how they were in the original transformed operation.\n//\n// Given `targetPosition` is the target position of the first range from `ranges`.\n//\n// @private\n// @param {Array.<module:engine/model/range~Range>} ranges\n// @param {module:engine/model/position~Position} targetPosition\n// @returns {Array.<module:engine/model/operation/moveoperation~MoveOperation>}\nfunction _makeMoveOperationsFromRanges( ranges, targetPosition ) {\n\t// At this moment we have some ranges and a target position, to which those ranges should be moved.\n\t// Order in `ranges` array is the go-to order of after transformation.\n\t//\n\t// We are almost done. We have `ranges` and `targetPosition` to make operations from.\n\t// Unfortunately, those operations may affect each other. Precisely, first operation after move\n\t// may affect source range and target position of second and third operation. Same with second\n\t// operation affecting third.\n\t//\n\t// We need to fix those source ranges and target positions once again, before converting `ranges` to operations.\n\tconst operations = [];\n\n\t// Keep in mind that nothing will be transformed if there is just one range in `ranges`.\n\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t// Create new operation out of a range and target position.\n\t\tconst range = ranges[ i ];\n\t\tconst op = new MoveOperation(\n\t\t\trange.start,\n\t\t\trange.end.offset - range.start.offset,\n\t\t\ttargetPosition,\n\t\t\t0\n\t\t);\n\n\t\toperations.push( op );\n\n\t\t// Transform other ranges by the generated operation.\n\t\tfor ( let j = i + 1; j < ranges.length; j++ ) {\n\t\t\t// All ranges in `ranges` array should be:\n\t\t\t//\n\t\t\t// * non-intersecting (these are part of original operation source range), and\n\t\t\t// * `targetPosition` does not target into them (opposite would mean that transformed operation targets \"inside itself\").\n\t\t\t//\n\t\t\t// This means that the transformation will be \"clean\" and always return one result.\n\t\t\tranges[ j ] = ranges[ j ]._getTransformedByMove( op.sourcePosition, op.targetPosition, op.howMany )[ 0 ];\n\t\t}\n\n\t\ttargetPosition = targetPosition._getTransformedByMove( op.sourcePosition, op.targetPosition, op.howMany );\n\t}\n\n\treturn operations;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 undo/basecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { transformSets } from '@ckeditor/ckeditor5-engine/src/model/operation/transform';\n\n/**\n * Base class for undo feature commands: {@link module:undo/undocommand~UndoCommand} and {@link module:undo/redocommand~RedoCommand}.\n *\n * @protected\n * @extends module:core/command~Command\n */\nexport default class BaseCommand extends Command {\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * Stack of items stored by the command. These are pairs of:\n\t\t *\n\t\t * * {@link module:engine/model/batch~Batch batch} saved by the command,\n\t\t * * {@link module:engine/model/selection~Selection selection} state at the moment of saving the batch.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array} #_stack\n\t\t */\n\t\tthis._stack = [];\n\n\t\t/**\n\t\t * Stores all batches that were created by this command.\n\t\t *\n\t\t * @protected\n\t\t * @member {WeakSet.<module:engine/model/batch~Batch>} #_createdBatches\n\t\t */\n\t\tthis._createdBatches = new WeakSet();\n\n\t\t// Refresh state, so the command is inactive right after initialization.\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = this._stack.length > 0;\n\t}\n\n\t/**\n\t * Stores a batch in the command, together with the selection state of the {@link module:engine/model/document~Document document}\n\t * created by the editor which this command is registered to.\n\t *\n\t * @param {module:engine/model/batch~Batch} batch The batch to add.\n\t */\n\taddBatch( batch ) {\n\t\tconst docSelection = this.editor.model.document.selection;\n\n\t\tconst selection = {\n\t\t\tranges: docSelection.hasOwnRange ? Array.from( docSelection.getRanges() ) : [],\n\t\t\tisBackward: docSelection.isBackward\n\t\t};\n\n\t\tthis._stack.push( { batch, selection } );\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Removes all items from the stack.\n\t */\n\tclearStack() {\n\t\tthis._stack = [];\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Restores the {@link module:engine/model/document~Document#selection document selection} state after a batch was undone.\n\t *\n\t * @protected\n\t * @param {Array.<module:engine/model/range~Range>} ranges Ranges to be restored.\n\t * @param {Boolean} isBackward A flag describing whether the restored range was selected forward or backward.\n\t * @param {Array.<module:engine/model/operation/operation~Operation>} operations Operations which has been applied\n\t * since selection has been stored.\n\t */\n\t_restoreSelection( ranges, isBackward, operations ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\t// This will keep the transformed selection ranges.\n\t\tconst selectionRanges = [];\n\n\t\t// Transform all ranges from the restored selection.\n\t\tfor ( const range of ranges ) {\n\t\t\tconst transformed = transformSelectionRange( range, operations );\n\n\t\t\t// For each `range` from `ranges`, we take only one transformed range.\n\t\t\t// This is because we want to prevent situation where single-range selection\n\t\t\t// got transformed to multi-range selection. We will take the first range that\n\t\t\t// is not in the graveyard.\n\t\t\tconst newRange = transformed.find(\n\t\t\t\trange => range.start.root != document.graveyard\n\t\t\t);\n\n\t\t\t// `transformedRange` might be `undefined` if transformed range ended up in graveyard.\n\t\t\tif ( newRange ) {\n\t\t\t\tselectionRanges.push( newRange );\n\t\t\t}\n\t\t}\n\n\t\t// `selectionRanges` may be empty if all ranges ended up in graveyard. If that is the case, do not restore selection.\n\t\tif ( selectionRanges.length ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( selectionRanges, { backward: isBackward } );\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Undoes a batch by reversing that batch, transforming reversed batch and finally applying it.\n\t * This is a helper method for {@link #execute}.\n\t *\n\t * @protected\n\t * @param {module:engine/model/batch~Batch} batchToUndo The batch to be undone.\n\t * @param {module:engine/model/batch~Batch} undoingBatch The batch that will contain undoing changes.\n\t */\n\t_undo( batchToUndo, undoingBatch ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\t// All changes done by the command execution will be saved as one batch.\n\t\tthis._createdBatches.add( undoingBatch );\n\n\t\tconst operationsToUndo = batchToUndo.operations.slice().filter( operation => operation.isDocumentOperation );\n\t\toperationsToUndo.reverse();\n\n\t\t// We will process each operation from `batchToUndo`, in reverse order. If there were operations A, B and C in undone batch,\n\t\t// we need to revert them in reverse order, so first C' (reversed C), then B', then A'.\n\t\tfor ( const operationToUndo of operationsToUndo ) {\n\t\t\tconst nextBaseVersion = operationToUndo.baseVersion + 1;\n\t\t\tconst historyOperations = Array.from( document.history.getOperations( nextBaseVersion ) );\n\n\t\t\tconst transformedSets = transformSets(\n\t\t\t\t[ operationToUndo.getReversed() ],\n\t\t\t\thistoryOperations,\n\t\t\t\t{\n\t\t\t\t\tuseRelations: true,\n\t\t\t\t\tdocument: this.editor.model.document,\n\t\t\t\t\tpadWithNoOps: false,\n\t\t\t\t\tforceWeakRemove: true\n\t\t\t\t}\n\t\t\t);\n\n\t\t\tconst reversedOperations = transformedSets.operationsA;\n\n\t\t\t// After reversed operation has been transformed by all history operations, apply it.\n\t\t\tfor ( const operation of reversedOperations ) {\n\t\t\t\t// Before applying, add the operation to the `undoingBatch`.\n\t\t\t\tundoingBatch.addOperation( operation );\n\t\t\t\tmodel.applyOperation( operation );\n\n\t\t\t\tdocument.history.setOperationAsUndone( operationToUndo, operation );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Transforms given range `range` by given `operations`.\n// Returns an array containing one or more ranges, which are result of the transformation.\nfunction transformSelectionRange( range, operations ) {\n\tconst transformed = range.getTransformedByOperations( operations );\n\n\t// After `range` got transformed, we have an array of ranges. Some of those\n\t// ranges may be \"touching\" -- they can be next to each other and could be merged.\n\t// First, we have to sort those ranges to assure that they are in order.\n\ttransformed.sort( ( a, b ) => a.start.isBefore( b.start ) ? -1 : 1 );\n\n\t// Then, we check if two consecutive ranges are touching.\n\tfor ( let i = 1; i < transformed.length; i++ ) {\n\t\tconst a = transformed[ i - 1 ];\n\t\tconst b = transformed[ i ];\n\n\t\tif ( a.end.isTouching( b.start ) ) {\n\t\t\t// And join them together if they are.\n\t\t\ta.end = b.end;\n\t\t\ttransformed.splice( i, 1 );\n\t\t\ti--;\n\t\t}\n\t}\n\n\treturn transformed;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 undo/undocommand\n */\n\nimport BaseCommand from './basecommand';\n\n/**\n * The undo command stores {@link module:engine/model/batch~Batch batches} applied to the\n * {@link module:engine/model/document~Document document} and is able to undo a batch by reversing it and transforming by\n * batches from {@link module:engine/model/document~Document#history history} that happened after the reversed batch.\n *\n * The undo command also takes care of restoring the {@link module:engine/model/document~Document#selection document selection}.\n *\n * @extends module:undo/basecommand~BaseCommand\n */\nexport default class UndoCommand extends BaseCommand {\n\t/**\n\t * Executes the command. This method reverts a {@link module:engine/model/batch~Batch batch} added to the command's stack, transforms\n\t * and applies the reverted version on the {@link module:engine/model/document~Document document} and removes the batch from the stack.\n\t * Then, it restores the {@link module:engine/model/document~Document#selection document selection}.\n\t *\n\t * @fires execute\n\t * @fires revert\n\t * @param {module:engine/model/batch~Batch} [batch] A batch that should be undone. If not set, the last added batch will be undone.\n\t */\n\texecute( batch = null ) {\n\t\t// If batch is not given, set `batchIndex` to the last index in command stack.\n\t\tconst batchIndex = batch ? this._stack.findIndex( a => a.batch == batch ) : this._stack.length - 1;\n\n\t\tconst item = this._stack.splice( batchIndex, 1 )[ 0 ];\n\t\tconst undoingBatch = this.editor.model.createBatch( 'transparent' );\n\n\t\t// All changes has to be done in one `enqueueChange` callback so other listeners will not\n\t\t// step between consecutive operations, or won't do changes to the document before selection is properly restored.\n\t\tthis.editor.model.enqueueChange( undoingBatch, () => {\n\t\t\tthis._undo( item.batch, undoingBatch );\n\n\t\t\tconst operations = this.editor.model.document.history.getOperations( item.batch.baseVersion );\n\t\t\tthis._restoreSelection( item.selection.ranges, item.selection.isBackward, operations );\n\n\t\t\tthis.fire( 'revert', item.batch, undoingBatch );\n\t\t} );\n\n\t\tthis.refresh();\n\t}\n}\n\n/**\n * Fired when execution of the command reverts some batch.\n *\n * @event revert\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 undo/redocommand\n */\n\nimport BaseCommand from './basecommand';\n\n/**\n * The redo command stores {@link module:engine/model/batch~Batch batches} that were used to undo a batch by\n * {@link module:undo/undocommand~UndoCommand}. It is able to redo a previously undone batch by reversing the undoing\n * batches created by `UndoCommand`. The reversed batch is transformed by all the batches from\n * {@link module:engine/model/document~Document#history history} that happened after the reversed undo batch.\n *\n * The redo command also takes care of restoring the {@link module:engine/model/document~Document#selection document selection}.\n *\n * @extends module:undo/basecommand~BaseCommand\n */\nexport default class RedoCommand extends BaseCommand {\n\t/**\n\t * Executes the command. This method reverts the last {@link module:engine/model/batch~Batch batch} added to\n\t * the command's stack, applies the reverted and transformed version on the\n\t * {@link module:engine/model/document~Document document} and removes the batch from the stack.\n\t * Then, it restores the {@link module:engine/model/document~Document#selection document selection}.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst item = this._stack.pop();\n\t\tconst redoingBatch = this.editor.model.createBatch( 'transparent' );\n\n\t\t// All changes have to be done in one `enqueueChange` callback so other listeners will not step between consecutive\n\t\t// operations, or won't do changes to the document before selection is properly restored.\n\t\tthis.editor.model.enqueueChange( redoingBatch, () => {\n\t\t\tconst lastOperation = item.batch.operations[ item.batch.operations.length - 1 ];\n\t\t\tconst nextBaseVersion = lastOperation.baseVersion + 1;\n\t\t\tconst operations = this.editor.model.document.history.getOperations( nextBaseVersion );\n\n\t\t\tthis._restoreSelection( item.selection.ranges, item.selection.isBackward, operations );\n\t\t\tthis._undo( item.batch, redoingBatch );\n\t\t} );\n\n\t\tthis.refresh();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 undo/undoediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport UndoCommand from './undocommand';\nimport RedoCommand from './redocommand';\n\n/**\n * The undo engine feature.\n *\n * It introduces the `'undo'` and `'redo'` commands to the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class UndoEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'UndoEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The command that manages undo {@link module:engine/model/batch~Batch batches} stack (history).\n\t\t * Created and registered during the {@link #init feature initialization}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:undo/undocommand~UndoCommand} #_undoCommand\n\t\t */\n\n\t\t/**\n\t\t * The command that manages redo {@link module:engine/model/batch~Batch batches} stack (history).\n\t\t * Created and registered during the {@link #init feature initialization}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:undo/undocommand~UndoCommand} #_redoCommand\n\t\t */\n\n\t\t/**\n\t\t * Keeps track of which batches were registered in undo.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakSet.<module:engine/model/batch~Batch>}\n\t\t */\n\t\tthis._batchRegistry = new WeakSet();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Create commands.\n\t\tthis._undoCommand = new UndoCommand( editor );\n\t\tthis._redoCommand = new RedoCommand( editor );\n\n\t\t// Register command to the editor.\n\t\teditor.commands.add( 'undo', this._undoCommand );\n\t\teditor.commands.add( 'redo', this._redoCommand );\n\n\t\tthis.listenTo( editor.model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\t// Do not register batch if the operation is not a document operation.\n\t\t\t// This prevents from creating empty undo steps, where all operations where non-document operations.\n\t\t\t// Non-document operations creates and alters content in detached tree fragments (for example, document fragments).\n\t\t\t// Most of time this is preparing data before it is inserted into actual tree (for example during copy & paste).\n\t\t\t// Such operations should not be reversed.\n\t\t\tif ( !operation.isDocumentOperation ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst batch = operation.batch;\n\n\t\t\tconst isRedoBatch = this._redoCommand._createdBatches.has( batch );\n\t\t\tconst isUndoBatch = this._undoCommand._createdBatches.has( batch );\n\t\t\tconst isRegisteredBatch = this._batchRegistry.has( batch );\n\n\t\t\t// If changes are not a part of a batch or this is not a new batch, omit those changes.\n\t\t\tif ( isRegisteredBatch || ( batch.type == 'transparent' && !isRedoBatch && !isUndoBatch ) ) {\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tif ( isRedoBatch ) {\n\t\t\t\t\t// If this batch comes from `redoCommand`, add it to `undoCommand` stack.\n\t\t\t\t\tthis._undoCommand.addBatch( batch );\n\t\t\t\t} else if ( !isUndoBatch ) {\n\t\t\t\t\t// A default batch - these are new changes in the document, not introduced by undo feature.\n\t\t\t\t\t// Add them to `undoCommand` stack and clear `redoCommand` stack.\n\t\t\t\t\tthis._undoCommand.addBatch( batch );\n\t\t\t\t\tthis._redoCommand.clearStack();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add the batch to the registry so it will not be processed again.\n\t\t\tthis._batchRegistry.add( batch );\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.listenTo( this._undoCommand, 'revert', ( evt, undoneBatch, undoingBatch ) => {\n\t\t\tthis._redoCommand.addBatch( undoingBatch );\n\t\t} );\n\n\t\teditor.keystrokes.set( 'CTRL+Z', 'undo' );\n\t\teditor.keystrokes.set( 'CTRL+Y', 'redo' );\n\t\teditor.keystrokes.set( 'CTRL+SHIFT+Z', 'redo' );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M5.042 9.367l2.189 1.837a.75.75 0 01-.965 1.149l-3.788-3.18a.747.747 0 01-.21-.284.75.75 0 01.17-.945L6.23 4.762a.75.75 0 11.964 1.15L4.863 7.866h8.917A.75.75 0 0114 7.9a4 4 0 11-1.477 7.718l.344-1.489a2.5 2.5 0 101.094-4.73l.008-.032H5.042z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M14.958 9.367l-2.189 1.837a.75.75 0 00.965 1.149l3.788-3.18a.747.747 0 00.21-.284.75.75 0 00-.17-.945L13.77 4.762a.75.75 0 10-.964 1.15l2.331 1.955H6.22A.75.75 0 006 7.9a4 4 0 101.477 7.718l-.344-1.489A2.5 2.5 0 116.039 9.4l-.008-.032h8.927z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module undo/undoui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport undoIcon from '../theme/assets/icons/undo.svg';\nimport redoIcon from '../theme/assets/icons/redo.svg';\n/**\n * The undo UI feature. It introduces the `'undo'` and `'redo'` buttons to the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class UndoUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const locale = editor.locale;\n const t = editor.t;\n const localizedUndoIcon = locale.uiLanguageDirection == 'ltr' ? undoIcon : redoIcon;\n const localizedRedoIcon = locale.uiLanguageDirection == 'ltr' ? redoIcon : undoIcon;\n this._addButton('undo', t('di'), 'CTRL+Z', localizedUndoIcon);\n this._addButton('redo', t('dj'), 'CTRL+Y', localizedRedoIcon);\n }\n /**\n\t * Creates a button for the specified command.\n\t *\n\t * @private\n\t * @param {String} name Command name.\n\t * @param {String} label Button label.\n\t * @param {String} keystroke Command keystroke.\n\t * @param {String} Icon Source of the icon.\n\t */\n _addButton(name, label, keystroke, Icon) {\n const editor = this.editor;\n editor.ui.componentFactory.add(name, locale => {\n const command = editor.commands.get(name);\n const view = new ButtonView(locale);\n view.set({\n label,\n icon: Icon,\n keystroke,\n tooltip: true\n });\n view.bind('isEnabled').to(command, 'isEnabled');\n this.listenTo(view, 'execute', () => {\n editor.execute(name);\n editor.editing.view.focus();\n });\n return view;\n });\n }\n}","/**\n * @license Copyright (c) 2003-2020, 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 undo/undo\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport UndoEditing from './undoediting';\nimport UndoUI from './undoui';\n\n/**\n * The undo feature.\n *\n * This is a \"glue\" plugin which loads the {@link module:undo/undoediting~UndoEditing undo editing feature}\n * and {@link module:undo/undoui~UndoUI undo UI feature}.\n *\n * Below is the explanation of the undo mechanism working together with {@link module:engine/model/history~History History}:\n *\n * Whenever a {@link module:engine/model/operation/operation~Operation operation} is applied to the\n * {@link module:engine/model/document~Document document}, it is saved to `History` as is.\n * The {@link module:engine/model/batch~Batch batch} that owns that operation is also saved, in\n * {@link module:undo/undocommand~UndoCommand}, together with the selection that was present in the document before the\n * operation was applied. A batch is saved instead of the operation because changes are undone batch-by-batch, not operation-by-operation\n * and a batch is seen as one undo step.\n *\n * After some changes happen to the document, the `History` and `UndoCommand` stack can be represented as follows:\n *\n *\t\t History Undo stack\n *\t\t============== ==================================\n *\t\t[operation A1] [batch A]\n *\t\t[operation B1] [batch B]\n *\t\t[operation B2] [batch C]\n *\t\t[operation C1]\n *\t\t[operation C2]\n *\t\t[operation B3]\n *\t\t[operation C3]\n *\n * Where operations starting with the same letter are from same batch.\n *\n * Undoing a batch means that a set of operations which will reverse the effects of that batch needs to be generated.\n * For example, if a batch added several letters, undoing the batch should remove them. It is important to apply undoing\n * operations in the reversed order, so if a batch has operation `X`, `Y`, `Z`, reversed operations `Zr`, `Yr` and `Xr`\n * need to be applied. Otherwise reversed operation `Xr` would operate on a wrong document state, because operation `X`\n * does not know that operations `Y` and `Z` happened.\n *\n * After operations from an undone batch got {@link module:engine/model/operation/operation~Operation#getReversed reversed},\n * one needs to make sure if they are ready to be applied. In the scenario above, operation `C3` is the last operation and `C3r`\n * bases on up-to-date document state, so it can be applied to the document.\n *\n *\t\t History Undo stack\n *\t\t================= ==================================\n *\t\t[ operation A1 ] [ batch A ]\n *\t\t[ operation B1 ] [ batch B ]\n *\t\t[ operation B2 ] [ processing undoing batch C ]\n *\t\t[ operation C1 ]\n *\t\t[ operation C2 ]\n *\t\t[ operation B3 ]\n *\t\t[ operation C3 ]\n *\t\t[ operation C3r ]\n *\n * Next is operation `C2`, reversed to `C2r`. `C2r` bases on `C2`, so it bases on the wrong document state. It needs to be\n * transformed by operations from history that happened after it, so it \"knows\" about them. Let us assume that `C2' = C2r * B3 * C3 * C3r`,\n * where `*` means \"transformed by\". Rest of operations from that batch are processed in the same fashion.\n *\n *\t\t History Undo stack Redo stack\n *\t\t================= ================================== ==================================\n *\t\t[ operation A1 ] [ batch A ] [ batch Cr ]\n *\t\t[ operation B1 ] [ batch B ]\n *\t\t[ operation B2 ]\n *\t\t[ operation C1 ]\n *\t\t[ operation C2 ]\n *\t\t[ operation B3 ]\n *\t\t[ operation C3 ]\n *\t\t[ operation C3r ]\n *\t\t[ operation C2' ]\n *\t\t[ operation C1' ]\n *\n * Selective undo works on the same basis, however, instead of undoing the last batch in the undo stack, any batch can be undone.\n * The same algorithm applies: operations from a batch (i.e. `A1`) are reversed and then transformed by operations stored in history.\n *\n * Redo also is very similar to undo. It has its own stack that is filled with undoing (reversed batches). Operations from\n * batch that is re-done are reversed-back, transformed in proper order and applied to the document.\n *\n *\t\t History Undo stack Redo stack\n *\t\t================= ================================== ==================================\n *\t\t[ operation A1 ] [ batch A ]\n *\t\t[ operation B1 ] [ batch B ]\n *\t\t[ operation B2 ] [ batch Crr ]\n *\t\t[ operation C1 ]\n *\t\t[ operation C2 ]\n *\t\t[ operation B3 ]\n *\t\t[ operation C3 ]\n *\t\t[ operation C3r ]\n *\t\t[ operation C2' ]\n *\t\t[ operation C1' ]\n *\t\t[ operation C1'r]\n *\t\t[ operation C2'r]\n *\t\t[ operation C3rr]\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Undo extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ UndoEditing, UndoUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Undo';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 core/contextplugin\n */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The base class for {@link module:core/context~Context} plugin classes.\n *\n * A context plugin can either be initialized for an {@link module:core/editor/editor~Editor editor} or for\n * a {@link module:core/context~Context context}. In other words, it can either\n * work within one editor instance or with one or more editor instances that use a single context.\n * It is the context plugin's role to implement handling for both modes.\n *\n * There are a few rules for interaction between the editor plugins and context plugins:\n *\n * * A context plugin can require another context plugin.\n * * An {@link module:core/plugin~Plugin editor plugin} can require a context plugin.\n * * A context plugin MUST NOT require an {@link module:core/plugin~Plugin editor plugin}.\n *\n * @implements module:core/plugin~PluginInterface\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class ContextPlugin {\n\t/**\n\t * Creates a new plugin instance.\n\t *\n\t * @param {module:core/context~Context|module:core/editor/editor~Editor} context\n\t */\n\tconstructor( context ) {\n\t\t/**\n\t\t * The context instance.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:core/context~Context|module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.context = context;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get isContextPlugin() {\n\t\treturn true;\n\t}\n}\n\nmix( ContextPlugin, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 core/pendingactions\n */\n\nimport ContextPlugin from './contextplugin';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * The list of pending editor actions.\n *\n * This plugin should be used to synchronise plugins that execute long-lasting actions\n * (e.g. file upload) with the editor integration. It gives the developer who integrates the editor\n * an easy way to check if there are any actions pending whenever such information is needed.\n * All plugins that register a pending action also provide a message about the action that is ongoing\n * which can be displayed to the user. This lets them decide if they want to interrupt the action or wait.\n *\n * Adding and updating a pending action:\n *\n * \t\tconst pendingActions = editor.plugins.get( 'PendingActions' );\n * \t\tconst action = pendingActions.add( 'Upload in progress: 0%.' );\n *\n *\t\t// You can update the message:\n * \t\taction.message = 'Upload in progress: 10%.';\n *\n * Removing a pending action:\n *\n * \t\tconst pendingActions = editor.plugins.get( 'PendingActions' );\n * \t\tconst action = pendingActions.add( 'Unsaved changes.' );\n *\n * \t\tpendingActions.remove( action );\n *\n * Getting pending actions:\n *\n * \t\tconst pendingActions = editor.plugins.get( 'PendingActions' );\n *\n * \t\tconst action1 = pendingActions.add( 'Action 1' );\n * \t\tconst action2 = pendingActions.add( 'Action 2' );\n *\n * \t\tpendingActions.first; // Returns action1\n * \t\tArray.from( pendingActions ); // Returns [ action1, action2 ]\n *\n * This plugin is used by features like {@link module:upload/filerepository~FileRepository} to register their ongoing actions\n * and by features like {@link module:autosave/autosave~Autosave} to detect whether there are any ongoing actions.\n * Read more about saving the data in the {@glink builds/guides/integration/saving-data Saving and getting data} guide.\n *\n * @extends module:core/contextplugin~ContextPlugin\n */\nexport default class PendingActions extends ContextPlugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'PendingActions';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\t/**\n\t\t * Defines whether there is any registered pending action.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #hasAny\n\t\t */\n\t\tthis.set( 'hasAny', false );\n\n\t\t/**\n\t\t * A list of pending actions.\n\t\t *\n\t\t * @private\n\t\t * @type {module:utils/collection~Collection}\n\t\t */\n\t\tthis._actions = new Collection( { idProperty: '_id' } );\n\t\tthis._actions.delegate( 'add', 'remove' ).to( this );\n\t}\n\n\t/**\n\t * Adds an action to the list of pending actions.\n\t *\n\t * This method returns an action object with an observable message property.\n\t * The action object can be later used in the {@link #remove} method. It also allows you to change the message.\n\t *\n\t * @param {String} message The action message.\n\t * @returns {Object} An observable object that represents a pending action.\n\t */\n\tadd( message ) {\n\t\tif ( typeof message !== 'string' ) {\n\t\t\t/**\n\t\t\t * The message must be a string.\n\t\t\t *\n\t\t\t * @error pendingactions-add-invalid-message\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'pendingactions-add-invalid-message: The message must be a string.', this );\n\t\t}\n\n\t\tconst action = Object.create( ObservableMixin );\n\n\t\taction.set( 'message', message );\n\t\tthis._actions.add( action );\n\t\tthis.hasAny = true;\n\n\t\treturn action;\n\t}\n\n\t/**\n\t * Removes an action from the list of pending actions.\n\t *\n\t * @param {Object} action An action object.\n\t */\n\tremove( action ) {\n\t\tthis._actions.remove( action );\n\t\tthis.hasAny = !!this._actions.length;\n\t}\n\n\t/**\n\t * Returns the first action from the list or null when list is empty\n\t *\n\t * returns {Object|null} The pending action object.\n\t */\n\tget first() {\n\t\treturn this._actions.get( 0 );\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._actions[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Fired when an action is added to the list.\n\t *\n\t * @event add\n\t * @param {Object} action The added action.\n\t */\n\n\t/**\n\t * Fired when an action is removed from the list.\n\t *\n\t * @event remove\n\t * @param {Object} action The removed action.\n\t */\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 upload/filereader\n */\n\n/* globals window */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Wrapper over the native `FileReader`.\n */\nexport default class FileReader {\n\t/**\n\t * Creates an instance of the FileReader.\n\t */\n\tconstructor() {\n\t\tconst reader = new window.FileReader();\n\n\t\t/**\n\t\t * Instance of native FileReader.\n\t\t *\n\t\t * @private\n\t\t * @member {FileReader} #_reader\n\t\t */\n\t\tthis._reader = reader;\n\n\t\tthis._data = undefined;\n\n\t\t/**\n\t\t * Number of bytes loaded.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #loaded\n\t\t */\n\t\tthis.set( 'loaded', 0 );\n\n\t\treader.onprogress = evt => {\n\t\t\tthis.loaded = evt.loaded;\n\t\t};\n\t}\n\n\t/**\n\t * Returns error that occurred during file reading.\n\t *\n\t * @returns {Error}\n\t */\n\tget error() {\n\t\treturn this._reader.error;\n\t}\n\n\t/**\n\t * Holds the data of an already loaded file. The file must be first loaded\n\t * by using {@link module:upload/filereader~FileReader#read `read()`}.\n\t *\n\t * @type {File|undefined}\n\t */\n\tget data() {\n\t\treturn this._data;\n\t}\n\n\t/**\n\t * Reads the provided file.\n\t *\n\t * @param {File} file Native File object.\n\t * @returns {Promise.<String>} Returns a promise that will be resolved with file's content.\n\t * The promise will be rejected in case of an error or when the reading process is aborted.\n\t */\n\tread( file ) {\n\t\tconst reader = this._reader;\n\t\tthis.total = file.size;\n\n\t\treturn new Promise( ( resolve, reject ) => {\n\t\t\treader.onload = () => {\n\t\t\t\tconst result = reader.result;\n\n\t\t\t\tthis._data = result;\n\n\t\t\t\tresolve( result );\n\t\t\t};\n\n\t\t\treader.onerror = () => {\n\t\t\t\treject( 'error' );\n\t\t\t};\n\n\t\t\treader.onabort = () => {\n\t\t\t\treject( 'aborted' );\n\t\t\t};\n\n\t\t\tthis._reader.readAsDataURL( file );\n\t\t} );\n\t}\n\n\t/**\n\t * Aborts file reader.\n\t */\n\tabort() {\n\t\tthis._reader.abort();\n\t}\n}\n\nmix( FileReader, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module upload/filerepository\n */\n/* globals console */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport PendingActions from '@ckeditor/ckeditor5-core/src/pendingactions';\nimport CKEditorError, { attachLinkToDocumentation } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport FileReader from './filereader.js';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid.js';\n/**\n * File repository plugin. A central point for managing file upload.\n *\n * To use it, first you need an upload adapter. Upload adapter's job is to handle communication with the server\n * (sending the file and handling server's response). You can use one of the existing plugins introducing upload adapters\n * (e.g. {@link module:easy-image/cloudservicesuploadadapter~CloudServicesUploadAdapter} or\n * {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter}) or write your own one – see\n * the {@glink framework/guides/deep-dive/upload-adapter \"Custom image upload adapter\" deep dive guide}.\n *\n * Then, you can use {@link module:upload/filerepository~FileRepository#createLoader `createLoader()`} and the returned\n * {@link module:upload/filerepository~FileLoader} instance to load and upload files.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FileRepository extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'FileRepository';\n }\n /**\n\t * @inheritDoc\n\t */\n static get requires() {\n return [PendingActions];\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n /**\n\t\t * Collection of loaders associated with this repository.\n\t\t *\n\t\t * @member {module:utils/collection~Collection} #loaders\n\t\t */\n this.loaders = new Collection();\n // Keeps upload in a sync with pending actions.\n this.loaders.on('add', () => this._updatePendingAction());\n this.loaders.on('remove', () => this._updatePendingAction());\n /**\n\t\t * Loaders mappings used to retrieve loaders references.\n\t\t *\n\t\t * @private\n\t\t * @member {Map<File|Promise, FileLoader>} #_loadersMap\n\t\t */\n this._loadersMap = new Map();\n /**\n\t\t * Reference to a pending action registered in a {@link module:core/pendingactions~PendingActions} plugin\n\t\t * while upload is in progress. When there is no upload then value is `null`.\n\t\t *\n\t\t * @private\n\t\t * @member {Object} #_pendingAction\n\t\t */\n this._pendingAction = null;\n /**\n\t\t * A factory function which should be defined before using `FileRepository`.\n\t\t *\n\t\t * It should return a new instance of {@link module:upload/filerepository~UploadAdapter} that will be used to upload files.\n\t\t * {@link module:upload/filerepository~FileLoader} instance associated with the adapter\n\t\t * will be passed to that function.\n\t\t *\n\t\t * For more information and example see {@link module:upload/filerepository~UploadAdapter}.\n\t\t *\n\t\t * @member {Function} #createUploadAdapter\n\t\t */\n /**\n\t\t * Number of bytes uploaded.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #uploaded\n\t\t */\n this.set('uploaded', 0);\n /**\n\t\t * Number of total bytes to upload.\n\t\t *\n\t\t * It might be different than the file size because of headers and additional data.\n\t\t * It contains `null` if value is not available yet, so it's better to use {@link #uploadedPercent} to monitor\n\t\t * the progress.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number|null} #uploadTotal\n\t\t */\n this.set('uploadTotal', null);\n /**\n\t\t * Upload progress in percents.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #uploadedPercent\n\t\t */\n this.bind('uploadedPercent').to(this, 'uploaded', this, 'uploadTotal', (uploaded, total) => {\n return total ? uploaded / total * 100 : 0;\n });\n }\n /**\n\t * Returns the loader associated with specified file or promise.\n\t *\n\t * To get loader by id use `fileRepository.loaders.get( id )`.\n\t *\n\t * @param {File|Promise.<File>} fileOrPromise Native file or promise handle.\n\t * @returns {module:upload/filerepository~FileLoader|null}\n\t */\n getLoader(fileOrPromise) {\n return this._loadersMap.get(fileOrPromise) || null;\n }\n /**\n\t * Creates a loader instance for the given file.\n\t *\n\t * Requires {@link #createUploadAdapter} factory to be defined.\n\t *\n\t * @param {File|Promise.<File>} fileOrPromise Native File object or native Promise object which resolves to a File.\n\t * @returns {module:upload/filerepository~FileLoader|null}\n\t */\n createLoader(fileOrPromise) {\n if (!this.createUploadAdapter) {\n /**\n\t\t\t * You need to enable an upload adapter in order to be able to upload files.\n\t\t\t *\n\t\t\t * This warning shows up when {@link module:upload/filerepository~FileRepository} is being used\n\t\t\t * without {@link #createUploadAdapter definining an upload adapter}.\n\t\t\t *\n\t\t\t * **If you see this warning when using one of the {@glink builds/index CKEditor 5 Builds}**\n\t\t\t * it means that you did not configure any of the upload adapters available by default in those builds.\n\t\t\t *\n\t\t\t * See the {@glink features/image-upload/image-upload comprehensive \"Image upload overview\"} to learn which upload\n\t\t\t * adapters are available in the builds and how to configure them.\n\t\t\t *\n\t\t\t * **If you see this warning when using a custom build** there is a chance that you enabled\n\t\t\t * a feature like {@link module:image/imageupload~ImageUpload},\n\t\t\t * or {@link module:image/imageupload/imageuploadui~ImageUploadUI} but you did not enable any upload adapter.\n\t\t\t * You can choose one of the existing upload adapters listed in the\n\t\t\t * {@glink features/image-upload/image-upload \"Image upload overview\"}.\n\t\t\t *\n\t\t\t * You can also implement your {@glink framework/guides/deep-dive/upload-adapter own image upload adapter}.\n\t\t\t *\n\t\t\t * @error filerepository-no-upload-adapter\n\t\t\t */\n console.warn(attachLinkToDocumentation('filerepository-no-upload-adapter: Upload adapter is not defined.'));\n return null;\n }\n const loader = new FileLoader(Promise.resolve(fileOrPromise), this.createUploadAdapter);\n this.loaders.add(loader);\n this._loadersMap.set(fileOrPromise, loader);\n // Store also file => loader mapping so loader can be retrieved by file instance returned upon Promise resolution.\n if (fileOrPromise instanceof Promise) {\n loader.file.then(file => {\n this._loadersMap.set(file, loader);\n }) // Every then() must have a catch().\n // File loader state (and rejections) are handled in read() and upload().\n // Also, see the \"does not swallow the file promise rejection\" test.\n.catch(() => {\n });\n }\n loader.on('change:uploaded', () => {\n let aggregatedUploaded = 0;\n for (const loader of this.loaders) {\n aggregatedUploaded += loader.uploaded;\n }\n this.uploaded = aggregatedUploaded;\n });\n loader.on('change:uploadTotal', () => {\n let aggregatedTotal = 0;\n for (const loader of this.loaders) {\n if (loader.uploadTotal) {\n aggregatedTotal += loader.uploadTotal;\n }\n }\n this.uploadTotal = aggregatedTotal;\n });\n return loader;\n }\n /**\n\t * Destroys the given loader.\n\t *\n\t * @param {File|Promise|module:upload/filerepository~FileLoader} fileOrPromiseOrLoader File or Promise associated\n\t * with that loader or loader itself.\n\t */\n destroyLoader(fileOrPromiseOrLoader) {\n const loader = fileOrPromiseOrLoader instanceof FileLoader ? fileOrPromiseOrLoader : this.getLoader(fileOrPromiseOrLoader);\n loader._destroy();\n this.loaders.remove(loader);\n this._loadersMap.forEach((value, key) => {\n if (value === loader) {\n this._loadersMap.delete(key);\n }\n });\n }\n /**\n\t * Registers or deregisters pending action bound with upload progress.\n\t *\n\t * @private\n\t */\n _updatePendingAction() {\n const pendingActions = this.editor.plugins.get(PendingActions);\n if (this.loaders.length) {\n if (!this._pendingAction) {\n const t = this.editor.t;\n const getMessage = value => `${ t('ai') } ${ parseInt(value) }%.`;\n this._pendingAction = pendingActions.add(getMessage(this.uploadedPercent));\n this._pendingAction.bind('message').to(this, 'uploadedPercent', getMessage);\n }\n } else {\n pendingActions.remove(this._pendingAction);\n this._pendingAction = null;\n }\n }\n}\nmix(FileRepository, ObservableMixin);\n/**\n * File loader class.\n *\n * It is used to control the process of reading the file and uploading it using the specified upload adapter.\n */\nclass FileLoader {\n /**\n\t * Creates a new instance of `FileLoader`.\n\t *\n\t * @param {Promise.<File>} filePromise A promise which resolves to a file instance.\n\t * @param {Function} uploadAdapterCreator The function which returns {@link module:upload/filerepository~UploadAdapter} instance.\n\t */\n constructor(filePromise, uploadAdapterCreator) {\n /**\n\t\t * Unique id of FileLoader instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n this.id = uid();\n /**\n\t\t * Additional wrapper over the initial file promise passed to this loader.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:upload/filerepository~FilePromiseWrapper}\n\t\t */\n this._filePromiseWrapper = this._createFilePromiseWrapper(filePromise);\n /**\n\t\t * Adapter instance associated with this file loader.\n\t\t *\n\t\t * @private\n\t\t * @member {module:upload/filerepository~UploadAdapter}\n\t\t */\n this._adapter = uploadAdapterCreator(this);\n /**\n\t\t * FileReader used by FileLoader.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:upload/filereader~FileReader}\n\t\t */\n this._reader = new FileReader();\n /**\n\t\t * Current status of FileLoader. It can be one of the following:\n\t\t *\n\t\t * * 'idle',\n\t\t * * 'reading',\n\t\t * * 'uploading',\n\t\t * * 'aborted',\n\t\t * * 'error'.\n\t\t *\n\t\t * When reading status can change in a following way:\n\t\t *\n\t\t * `idle` -> `reading` -> `idle`\n\t\t * `idle` -> `reading -> `aborted`\n\t\t * `idle` -> `reading -> `error`\n\t\t *\n\t\t * When uploading status can change in a following way:\n\t\t *\n\t\t * `idle` -> `uploading` -> `idle`\n\t\t * `idle` -> `uploading` -> `aborted`\n\t\t * `idle` -> `uploading` -> `error`\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {String} #status\n\t\t */\n this.set('status', 'idle');\n /**\n\t\t * Number of bytes uploaded.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #uploaded\n\t\t */\n this.set('uploaded', 0);\n /**\n\t\t * Number of total bytes to upload.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number|null} #uploadTotal\n\t\t */\n this.set('uploadTotal', null);\n /**\n\t\t * Upload progress in percents.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #uploadedPercent\n\t\t */\n this.bind('uploadedPercent').to(this, 'uploaded', this, 'uploadTotal', (uploaded, total) => {\n return total ? uploaded / total * 100 : 0;\n });\n /**\n\t\t * Response of the upload.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Object|null} #uploadResponse\n\t\t */\n this.set('uploadResponse', null);\n }\n /**\n\t * A `Promise` which resolves to a `File` instance associated with this file loader.\n\t *\n\t * @type {Promise.<File|null>}\n\t */\n get file() {\n if (!this._filePromiseWrapper) {\n // Loader was destroyed, return promise which resolves to null.\n return Promise.resolve(null);\n } else {\n // The `this._filePromiseWrapper.promise` is chained and not simply returned to handle a case when:\n //\n //\t\t* The `loader.file.then( ... )` is called by external code (returned promise is pending).\n //\t\t* Then `loader._destroy()` is called (call is synchronous) which destroys the `loader`.\n //\t\t* Promise returned by the first `loader.file.then( ... )` call is resolved.\n //\n // Returning `this._filePromiseWrapper.promise` will still resolve to a `File` instance so there\n // is an additional check needed in the chain to see if `loader` was destroyed in the meantime.\n return this._filePromiseWrapper.promise.then(file => this._filePromiseWrapper ? file : null);\n }\n }\n /**\n\t * Returns the file data. To read its data, you need for first load the file\n\t * by using the {@link module:upload/filerepository~FileLoader#read `read()`} method.\n\t *\n\t * @type {File|undefined}\n\t */\n get data() {\n return this._reader.data;\n }\n /**\n\t * Reads file using {@link module:upload/filereader~FileReader}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-read-wrong-status` when status\n\t * is different than `idle`.\n\t *\n\t * Example usage:\n\t *\n\t *\tfileLoader.read()\n\t *\t\t.then( data => { ... } )\n\t *\t\t.catch( err => {\n\t *\t\t\tif ( err === 'aborted' ) {\n\t *\t\t\t\tconsole.log( 'Reading aborted.' );\n\t *\t\t\t} else {\n\t *\t\t\t\tconsole.log( 'Reading error.', err );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @returns {Promise.<String>} Returns promise that will be resolved with read data. Promise will be rejected if error\n\t * occurs or if read process is aborted.\n\t */\n read() {\n if (this.status != 'idle') {\n throw new CKEditorError('filerepository-read-wrong-status: You cannot call read if the status is different than idle.', this);\n }\n this.status = 'reading';\n return this.file.then(file => this._reader.read(file)).then(data => {\n this.status = 'idle';\n return data;\n }).catch(err => {\n if (err === 'aborted') {\n this.status = 'aborted';\n throw 'aborted';\n }\n this.status = 'error';\n throw this._reader.error ? this._reader.error : err;\n });\n }\n /**\n\t * Reads file using the provided {@link module:upload/filerepository~UploadAdapter}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-upload-wrong-status` when status\n\t * is different than `idle`.\n\t * Example usage:\n\t *\n\t *\tfileLoader.upload()\n\t *\t\t.then( data => { ... } )\n\t *\t\t.catch( e => {\n\t *\t\t\tif ( e === 'aborted' ) {\n\t *\t\t\t\tconsole.log( 'Uploading aborted.' );\n\t *\t\t\t} else {\n\t *\t\t\t\tconsole.log( 'Uploading error.', e );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @returns {Promise.<Object>} Returns promise that will be resolved with response data. Promise will be rejected if error\n\t * occurs or if read process is aborted.\n\t */\n upload() {\n if (this.status != 'idle') {\n throw new CKEditorError('filerepository-upload-wrong-status: You cannot call upload if the status is different than idle.', this);\n }\n this.status = 'uploading';\n return this.file.then(() => this._adapter.upload()).then(data => {\n this.uploadResponse = data;\n this.status = 'idle';\n return data;\n }).catch(err => {\n if (this.status === 'aborted') {\n throw 'aborted';\n }\n this.status = 'error';\n throw err;\n });\n }\n /**\n\t * Aborts loading process.\n\t */\n abort() {\n const status = this.status;\n this.status = 'aborted';\n if (!this._filePromiseWrapper.isFulfilled) {\n // Edge case: file loader is aborted before read() is called\n // so it might happen that no one handled the rejection of this promise.\n // See https://github.com/ckeditor/ckeditor5-upload/pull/100\n this._filePromiseWrapper.promise.catch(() => {\n });\n this._filePromiseWrapper.rejecter('aborted');\n } else if (status == 'reading') {\n this._reader.abort();\n } else if (status == 'uploading' && this._adapter.abort) {\n this._adapter.abort();\n }\n this._destroy();\n }\n /**\n\t * Performs cleanup.\n\t *\n\t * @private\n\t */\n _destroy() {\n this._filePromiseWrapper = undefined;\n this._reader = undefined;\n this._adapter = undefined;\n this.uploadResponse = undefined;\n }\n /**\n\t * Wraps a given file promise into another promise giving additional\n\t * control (resolving, rejecting, checking if fulfilled) over it.\n\t *\n\t * @private\n\t * @param filePromise The initial file promise to be wrapped.\n\t * @returns {module:upload/filerepository~FilePromiseWrapper}\n\t */\n _createFilePromiseWrapper(filePromise) {\n const wrapper = {};\n wrapper.promise = new Promise((resolve, reject) => {\n wrapper.rejecter = reject;\n wrapper.isFulfilled = false;\n filePromise.then(file => {\n wrapper.isFulfilled = true;\n resolve(file);\n }).catch(err => {\n wrapper.isFulfilled = true;\n reject(err);\n });\n });\n return wrapper;\n }\n}\nmix(FileLoader, ObservableMixin); /**\n * Upload adapter interface used by the {@link module:upload/filerepository~FileRepository file repository}\n * to handle file upload. An upload adapter is a bridge between the editor and server that handles file uploads.\n * It should contain a logic necessary to initiate an upload process and monitor its progress.\n *\n * Learn how to develop your own upload adapter for CKEditor 5 in the\n * {@glink framework/guides/deep-dive/upload-adapter \"Custom upload adapter\" guide}.\n *\n * @interface UploadAdapter\n */\n /**\n * Executes the upload process.\n * This method should return a promise that will resolve when data will be uploaded to server. Promise should be\n * resolved with an object containing information about uploaded file:\n *\n *\t\t{\n *\t\t\tdefault: 'http://server/default-size.image.png'\n *\t\t}\n *\n * Additionally, other image sizes can be provided:\n *\n *\t\t{\n *\t\t\tdefault: 'http://server/default-size.image.png',\n *\t\t\t'160': 'http://server/size-160.image.png',\n *\t\t\t'500': 'http://server/size-500.image.png',\n *\t\t\t'1000': 'http://server/size-1000.image.png',\n *\t\t\t'1052': 'http://server/default-size.image.png'\n *\t\t}\n *\n * NOTE: When returning multiple images, the widest returned one should equal the default one. It is essential to\n * correctly set `width` attribute of the image. See this discussion:\n * https://github.com/ckeditor/ckeditor5-easy-image/issues/4 for more information.\n *\n * Take a look at {@link module:upload/filerepository~UploadAdapter example Adapter implementation} and\n * {@link module:upload/filerepository~FileRepository#createUploadAdapter createUploadAdapter method}.\n *\n * @method module:upload/filerepository~UploadAdapter#upload\n * @returns {Promise.<Object>} Promise that should be resolved when data is uploaded.\n */\n /**\n * Aborts the upload process.\n * After aborting it should reject promise returned from {@link #upload upload()}.\n *\n * Take a look at {@link module:upload/filerepository~UploadAdapter example Adapter implementation} and\n * {@link module:upload/filerepository~FileRepository#createUploadAdapter createUploadAdapter method}.\n *\n * @method module:upload/filerepository~UploadAdapter#abort\n */\n /**\n * Object returned by {@link module:upload/filerepository~FileLoader#_createFilePromiseWrapper} method\n * to add more control over the initial file promise passed to {@link module:upload/filerepository~FileLoader}.\n *\n * @protected\n * @typedef {Object} module:upload/filerepository~FilePromiseWrapper\n * @property {Promise.<File>} promise Wrapper promise which can be chained for further processing.\n * @property {Function} rejecter Rejects the promise when called.\n * @property {Boolean} isFulfilled Whether original promise is already fulfilled.\n */","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals window, document */\n\n/**\n * @module adapter-ckfinder/utils\n */\n\nconst TOKEN_COOKIE_NAME = 'ckCsrfToken';\nconst TOKEN_LENGTH = 40;\nconst tokenCharset = 'abcdefghijklmnopqrstuvwxyz0123456789';\n\n/**\n * Returns the CSRF token value. The value is a hash stored in `document.cookie`\n * under the `ckCsrfToken` key. The CSRF token can be used to secure the communication\n * between the web browser and the CKFinder server.\n *\n * @returns {String}\n */\nexport function getCsrfToken() {\n\tlet token = getCookie( TOKEN_COOKIE_NAME );\n\n\tif ( !token || token.length != TOKEN_LENGTH ) {\n\t\ttoken = generateToken( TOKEN_LENGTH );\n\t\tsetCookie( TOKEN_COOKIE_NAME, token );\n\t}\n\n\treturn token;\n}\n\n/**\n * Returns the value of the cookie with a given name or `null` if the cookie is not found.\n *\n * @param {String} name\n * @returns {String|null}\n */\nexport function getCookie( name ) {\n\tname = name.toLowerCase();\n\tconst parts = document.cookie.split( ';' );\n\n\tfor ( const part of parts ) {\n\t\tconst pair = part.split( '=' );\n\t\tconst key = decodeURIComponent( pair[ 0 ].trim().toLowerCase() );\n\n\t\tif ( key === name ) {\n\t\t\treturn decodeURIComponent( pair[ 1 ] );\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Sets the value of the cookie with a given name.\n *\n * @param {String} name\n * @param {String} value\n */\nexport function setCookie( name, value ) {\n\tdocument.cookie = encodeURIComponent( name ) + '=' + encodeURIComponent( value ) + ';path=/';\n}\n\n// Generates the CSRF token with the given length.\n//\n// @private\n// @param {Number} length\n// @returns {string}\nfunction generateToken( length ) {\n\tlet result = '';\n\tconst randValues = new Uint8Array( length );\n\n\twindow.crypto.getRandomValues( randValues );\n\n\tfor ( let j = 0; j < randValues.length; j++ ) {\n\t\tconst character = tokenCharset.charAt( randValues[ j ] % tokenCharset.length );\n\t\tresult += Math.random() > 0.5 ? character.toUpperCase() : character;\n\t}\n\n\treturn result;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/* globals XMLHttpRequest, FormData */\n/**\n * @module adapter-ckfinder/uploadadapter\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';\nimport { getCsrfToken } from './utils';\n/**\n * A plugin that enables file uploads in CKEditor 5 using the CKFinder server–side connector.\n *\n * See the {@glink features/image-upload/ckfinder \"CKFinder file manager integration\" guide} to learn how to configure\n * and use this feature as well as find out more about the full integration with the file manager\n * provided by the {@link module:ckfinder/ckfinder~CKFinder} plugin.\n *\n * Check out the {@glink features/image-upload/image-upload comprehensive \"Image upload overview\"} to learn about\n * other ways to upload images into CKEditor 5.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CKFinderUploadAdapter extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get requires() {\n return [FileRepository];\n }\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'CKFinderUploadAdapter';\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const url = this.editor.config.get('ckfinder.uploadUrl');\n if (!url) {\n return;\n }\n // Register CKFinderAdapter\n this.editor.plugins.get(FileRepository).createUploadAdapter = loader => new UploadAdapter(loader, url, this.editor.t);\n }\n}\n/**\n * Upload adapter for CKFinder.\n *\n * @private\n * @implements module:upload/filerepository~UploadAdapter\n */\nclass UploadAdapter {\n /**\n\t * Creates a new adapter instance.\n\t *\n\t * @param {module:upload/filerepository~FileLoader} loader\n\t * @param {String} url\n\t * @param {module:utils/locale~Locale#t} t\n\t */\n constructor(loader, url, t) {\n /**\n\t\t * FileLoader instance to use during the upload.\n\t\t *\n\t\t * @member {module:upload/filerepository~FileLoader} #loader\n\t\t */\n this.loader = loader;\n /**\n\t\t * Upload URL.\n\t\t *\n\t\t * @member {String} #url\n\t\t */\n this.url = url;\n /**\n\t\t * Locale translation method.\n\t\t *\n\t\t * @member {module:utils/locale~Locale#t} #t\n\t\t */\n this.t = t;\n }\n /**\n\t * Starts the upload process.\n\t *\n\t * @see module:upload/filerepository~UploadAdapter#upload\n\t * @returns {Promise.<Object>}\n\t */\n upload() {\n return this.loader.file.then(file => {\n return new Promise((resolve, reject) => {\n this._initRequest();\n this._initListeners(resolve, reject, file);\n this._sendRequest(file);\n });\n });\n }\n /**\n\t * Aborts the upload process.\n\t *\n\t * @see module:upload/filerepository~UploadAdapter#abort\n\t */\n abort() {\n if (this.xhr) {\n this.xhr.abort();\n }\n }\n /**\n\t * Initializes the XMLHttpRequest object.\n\t *\n\t * @private\n\t */\n _initRequest() {\n const xhr = this.xhr = new XMLHttpRequest();\n xhr.open('POST', this.url, true);\n xhr.responseType = 'json';\n }\n /**\n\t * Initializes XMLHttpRequest listeners.\n\t *\n\t * @private\n\t * @param {Function} resolve Callback function to be called when the request is successful.\n\t * @param {Function} reject Callback function to be called when the request cannot be completed.\n\t * @param {File} file File instance to be uploaded.\n\t */\n _initListeners(resolve, reject, file) {\n const xhr = this.xhr;\n const loader = this.loader;\n const t = this.t;\n const genericError = t('a') + ` ${ file.name }.`;\n xhr.addEventListener('error', () => reject(genericError));\n xhr.addEventListener('abort', () => reject());\n xhr.addEventListener('load', () => {\n const response = xhr.response;\n if (!response || !response.uploaded) {\n return reject(response && response.error && response.error.message ? response.error.message : genericError);\n }\n resolve({ default: response.url });\n });\n // Upload progress when it's supported.\n /* istanbul ignore else */\n if (xhr.upload) {\n xhr.upload.addEventListener('progress', evt => {\n if (evt.lengthComputable) {\n loader.uploadTotal = evt.total;\n loader.uploaded = evt.loaded;\n }\n });\n }\n }\n /**\n\t * Prepares the data and sends the request.\n\t *\n\t * @private\n\t * @param {File} file File instance to be uploaded.\n\t */\n _sendRequest(file) {\n // Prepare form data.\n const data = new FormData();\n data.append('upload', file);\n data.append('ckCsrfToken', getCsrfToken());\n // Send request.\n this.xhr.send(data);\n }\n}","/**\n * @license Copyright (c) 2003-2020, 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 autoformat/blockautoformatediting\n */\n\nimport LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange';\n\n/**\n * The block autoformatting engine. It allows to format various block patterns. For example,\n * it can be configured to turn a paragraph starting with `*` and followed by a space into a list item.\n *\n * The autoformatting operation is integrated with the undo manager,\n * so the autoformatting step can be undone if the user's intention was not to format the text.\n *\n * See the constructors documentation to learn how to create custom inline autoformatters. You can also use\n * the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters\n * (lists, headings, bold and italic).\n */\nexport default class BlockAutoformatEditing {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BlockAutoformatEditing';\n\t}\n\n\t/**\n\t * Creates a listener triggered on `change` event in the document.\n\t * Calls the callback when inserted text matches the regular expression or the command name\n\t * if provided instead of the callback.\n\t *\n\t * Examples of usage:\n\t *\n\t * To convert a paragraph to heading 1 when `- ` is typed, using just the command name:\n\t *\n\t *\t\tnew BlockAutoformatEditing( editor, /^\\- $/, 'heading1' );\n\t *\n\t * To convert a paragraph to heading 1 when `- ` is typed, using just the callback:\n\t *\n\t *\t\tnew BlockAutoformatEditing( editor, /^\\- $/, ( context ) => {\n\t *\t\t\tconst { match } = context;\n\t *\t\t\tconst headingLevel = match[ 1 ].length;\n\t *\n\t *\t\t\teditor.execute( 'heading', {\n\t *\t\t\t\tformatId: `heading${ headingLevel }`\n\t *\t\t\t} );\n\t * \t\t} );\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {RegExp} pattern The regular expression to execute on just inserted text.\n\t * @param {Function|String} callbackOrCommand The callback to execute or the command to run when the text is matched.\n\t * In case of providing the callback, it receives the following parameter:\n\t * * {Object} match RegExp.exec() result of matching the pattern to inserted text.\n\t */\n\tconstructor( editor, pattern, callbackOrCommand ) {\n\t\tlet callback;\n\t\tlet command = null;\n\n\t\tif ( typeof callbackOrCommand == 'function' ) {\n\t\t\tcallback = callbackOrCommand;\n\t\t} else {\n\t\t\t// We assume that the actual command name was provided.\n\t\t\tcommand = editor.commands.get( callbackOrCommand );\n\n\t\t\tcallback = () => {\n\t\t\t\teditor.execute( callbackOrCommand );\n\t\t\t};\n\t\t}\n\n\t\teditor.model.document.on( 'change', ( evt, batch ) => {\n\t\t\tif ( command && !command.isEnabled ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( batch.type == 'transparent' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst changes = Array.from( editor.model.document.differ.getChanges() );\n\t\t\tconst entry = changes[ 0 ];\n\n\t\t\t// Typing is represented by only a single change.\n\t\t\tif ( changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst blockToFormat = entry.position.parent;\n\n\t\t\t// Block formatting should trigger only if the entire content of a paragraph is a single text node... (see ckeditor5#5671).\n\t\t\tif ( !blockToFormat.is( 'paragraph' ) || blockToFormat.childCount !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst match = pattern.exec( blockToFormat.getChild( 0 ).data );\n\n\t\t\t// ...and this text node's data match the pattern.\n\t\t\tif ( !match ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Use enqueueChange to create new batch to separate typing batch from the auto-format changes.\n\t\t\teditor.model.enqueueChange( writer => {\n\t\t\t\t// Matched range.\n\t\t\t\tconst start = writer.createPositionAt( blockToFormat, 0 );\n\t\t\t\tconst end = writer.createPositionAt( blockToFormat, match[ 0 ].length );\n\t\t\t\tconst range = new LiveRange( start, end );\n\n\t\t\t\tconst wasChanged = callback( { match } );\n\n\t\t\t\t// Remove matched text.\n\t\t\t\tif ( wasChanged !== false ) {\n\t\t\t\t\twriter.remove( range );\n\t\t\t\t}\n\n\t\t\t\trange.detach();\n\t\t\t} );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 autoformat/inlineautoformatediting\n */\n\nimport getLastTextLine from '@ckeditor/ckeditor5-typing/src/utils/getlasttextline';\n\n/**\n * The inline autoformatting engine. It allows to format various inline patterns. For example,\n * it can be configured to make \"foo\" bold when typed `**foo**` (the `**` markers will be removed).\n *\n * The autoformatting operation is integrated with the undo manager,\n * so the autoformatting step can be undone if the user's intention was not to format the text.\n *\n * See the constructors documentation to learn how to create custom inline autoformatters. You can also use\n * the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters\n * (lists, headings, bold and italic).\n */\nexport default class InlineAutoformatEditing {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'InlineAutoformatEditing';\n\t}\n\n\t/**\n\t * Enables autoformatting mechanism for a given {@link module:core/editor/editor~Editor}.\n\t *\n\t * It formats the matched text by applying the given model attribute or by running the provided formatting callback.\n\t * On every change applied to the model the autoformatting engine checks the text on the left of the selection\n\t * and executes the provided action if the text matches given criteria (regular expression or callback).\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {Function|RegExp} testRegexpOrCallback The regular expression or callback to execute on text.\n\t * Provided regular expression *must* have three capture groups. The first and the third capture group\n\t * should match opening and closing delimiters. The second capture group should match the text to format.\n\t *\n\t *\t\t// Matches the `**bold text**` pattern.\n\t *\t\t// There are three capturing groups:\n\t *\t\t// - The first to match the starting `**` delimiter.\n\t *\t\t// - The second to match the text to format.\n\t *\t\t// - The third to match the ending `**` delimiter.\n\t *\t\tnew InlineAutoformatEditing( editor, /(\\*\\*)([^\\*]+?)(\\*\\*)$/g, 'bold' );\n\t *\n\t * When a function is provided instead of the regular expression, it will be executed with the text to match as a parameter.\n\t * The function should return proper \"ranges\" to delete and format.\n\t *\n\t *\t\t{\n\t *\t\t\tremove: [\n\t *\t\t\t\t[ 0, 1 ],\t// Remove the first letter from the given text.\n\t *\t\t\t\t[ 5, 6 ]\t// Remove the 6th letter from the given text.\n\t *\t\t\t],\n\t *\t\t\tformat: [\n\t *\t\t\t\t[ 1, 5 ]\t// Format all letters from 2nd to 5th.\n\t *\t\t\t]\n\t *\t\t}\n\t *\n\t * @param {Function|String} attributeOrCallback The name of attribute to apply on matching text or a callback for manual\n\t * formatting. If callback is passed it should return `false` if changes should not be applied (e.g. if a command is disabled).\n\t *\n\t *\t\t// Use attribute name:\n\t *\t\tnew InlineAutoformatEditing( editor, /(\\*\\*)([^\\*]+?)(\\*\\*)$/g, 'bold' );\n\t *\n\t *\t\t// Use formatting callback:\n\t *\t\tnew InlineAutoformatEditing( editor, /(\\*\\*)([^\\*]+?)(\\*\\*)$/g, ( writer, rangesToFormat ) => {\n\t *\t\t\tconst command = editor.commands.get( 'bold' );\n\t *\n\t *\t\t\tif ( !command.isEnabled ) {\n\t *\t\t\t\treturn false;\n\t *\t\t\t}\n\t *\n\t *\t\t\tconst validRanges = editor.model.schema.getValidRanges( rangesToFormat, 'bold' );\n\t *\n\t *\t\t\tfor ( let range of validRanges ) {\n\t *\t\t\t\twriter.setAttribute( 'bold', true, range );\n\t *\t\t\t}\n\t *\t\t} );\n\t */\n\tconstructor( editor, testRegexpOrCallback, attributeOrCallback ) {\n\t\tlet regExp;\n\t\tlet attributeKey;\n\t\tlet testCallback;\n\t\tlet formatCallback;\n\n\t\tif ( testRegexpOrCallback instanceof RegExp ) {\n\t\t\tregExp = testRegexpOrCallback;\n\t\t} else {\n\t\t\ttestCallback = testRegexpOrCallback;\n\t\t}\n\n\t\tif ( typeof attributeOrCallback == 'string' ) {\n\t\t\tattributeKey = attributeOrCallback;\n\t\t} else {\n\t\t\tformatCallback = attributeOrCallback;\n\t\t}\n\n\t\t// A test callback run on changed text.\n\t\ttestCallback = testCallback || ( text => {\n\t\t\tlet result;\n\t\t\tconst remove = [];\n\t\t\tconst format = [];\n\n\t\t\twhile ( ( result = regExp.exec( text ) ) !== null ) {\n\t\t\t\t// There should be full match and 3 capture groups.\n\t\t\t\tif ( result && result.length < 4 ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tlet {\n\t\t\t\t\tindex,\n\t\t\t\t\t'1': leftDel,\n\t\t\t\t\t'2': content,\n\t\t\t\t\t'3': rightDel\n\t\t\t\t} = result;\n\n\t\t\t\t// Real matched string - there might be some non-capturing groups so we need to recalculate starting index.\n\t\t\t\tconst found = leftDel + content + rightDel;\n\t\t\t\tindex += result[ 0 ].length - found.length;\n\n\t\t\t\t// Start and End offsets of delimiters to remove.\n\t\t\t\tconst delStart = [\n\t\t\t\t\tindex,\n\t\t\t\t\tindex + leftDel.length\n\t\t\t\t];\n\t\t\t\tconst delEnd = [\n\t\t\t\t\tindex + leftDel.length + content.length,\n\t\t\t\t\tindex + leftDel.length + content.length + rightDel.length\n\t\t\t\t];\n\n\t\t\t\tremove.push( delStart );\n\t\t\t\tremove.push( delEnd );\n\n\t\t\t\tformat.push( [ index + leftDel.length, index + leftDel.length + content.length ] );\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tremove,\n\t\t\t\tformat\n\t\t\t};\n\t\t} );\n\n\t\t// A format callback run on matched text.\n\t\tformatCallback = formatCallback || ( ( writer, rangesToFormat ) => {\n\t\t\tconst validRanges = editor.model.schema.getValidRanges( rangesToFormat, attributeKey );\n\n\t\t\tfor ( const range of validRanges ) {\n\t\t\t\twriter.setAttribute( attributeKey, true, range );\n\t\t\t}\n\n\t\t\t// After applying attribute to the text, remove given attribute from the selection.\n\t\t\t// This way user is able to type a text without attribute used by auto formatter.\n\t\t\twriter.removeSelectionAttribute( attributeKey );\n\t\t} );\n\n\t\teditor.model.document.on( 'change', ( evt, batch ) => {\n\t\t\tif ( batch.type == 'transparent' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst model = editor.model;\n\t\t\tconst selection = model.document.selection;\n\n\t\t\t// Do nothing if selection is not collapsed.\n\t\t\tif ( !selection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst changes = Array.from( model.document.differ.getChanges() );\n\t\t\tconst entry = changes[ 0 ];\n\n\t\t\t// Typing is represented by only a single change.\n\t\t\tif ( changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst focus = selection.focus;\n\t\t\tconst block = focus.parent;\n\t\t\tconst { text, range } = getLastTextLine( model.createRange( model.createPositionAt( block, 0 ), focus ), model );\n\t\t\tconst testOutput = testCallback( text );\n\t\t\tconst rangesToFormat = testOutputToRanges( range.start, testOutput.format, model );\n\t\t\tconst rangesToRemove = testOutputToRanges( range.start, testOutput.remove, model );\n\n\t\t\tif ( !( rangesToFormat.length && rangesToRemove.length ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Use enqueueChange to create new batch to separate typing batch from the auto-format changes.\n\t\t\tmodel.enqueueChange( writer => {\n\t\t\t\t// Apply format.\n\t\t\t\tconst hasChanged = formatCallback( writer, rangesToFormat );\n\n\t\t\t\t// Strict check on `false` to have backward compatibility (when callbacks were returning `undefined`).\n\t\t\t\tif ( hasChanged === false ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Remove delimiters - use reversed order to not mix the offsets while removing.\n\t\t\t\tfor ( const range of rangesToRemove.reverse() ) {\n\t\t\t\t\twriter.remove( range );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n}\n\n// Converts output of the test function provided to the InlineAutoformatEditing and converts it to the model ranges\n// inside provided block.\n//\n// @private\n// @param {module:engine/model/position~Position} start\n// @param {Array.<Array>} arrays\n// @param {module:engine/model/model~Model} model\nfunction testOutputToRanges( start, arrays, model ) {\n\treturn arrays\n\t\t.filter( array => ( array[ 0 ] !== undefined && array[ 1 ] !== undefined ) )\n\t\t.map( array => {\n\t\t\treturn model.createRange( start.getShiftedBy( array[ 0 ] ), start.getShiftedBy( array[ 1 ] ) );\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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. `<softBreak>`).\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 `<paragraph>` content:\n *\n *\t\t<paragraph>Foo bar baz<paragraph>\n *\n * However, in below case, `text` will be set to \"baz\" and `range` will be set only on \"baz\".\n *\n *\t\t<paragraph>Foo<softBreak></softBreak>bar<softBreak></softBreak>baz<paragraph>\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-2020, 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 autoformat/autoformat\n */\n\nimport BlockAutoformatEditing from './blockautoformatediting';\nimport InlineAutoformatEditing from './inlineautoformatediting';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * Enables a set of predefined autoformatting actions.\n *\n * For a detailed overview, check the {@glink features/autoformat Autoformatting feature documentation}\n * and the {@glink api/autoformat package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Autoformat extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Autoformat';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tthis._addListAutoformats();\n\t\tthis._addBasicStylesAutoformats();\n\t\tthis._addHeadingAutoformats();\n\t\tthis._addBlockQuoteAutoformats();\n\t\tthis._addCodeBlockAutoformats();\n\t}\n\n\t/**\n\t * Adds autoformatting related to the {@link module:list/list~List}.\n\t *\n\t * When typed:\n\t * - `* ` or `- ` – A paragraph will be changed to a bulleted list.\n\t * - `1. ` or `1) ` – A paragraph will be changed to a numbered list (\"1\" can be any digit or a list of digits).\n\t *\n\t * @private\n\t */\n\t_addListAutoformats() {\n\t\tconst commands = this.editor.commands;\n\n\t\tif ( commands.get( 'bulletedList' ) ) {\n\t\t\t// eslint-disable-next-line no-new\n\t\t\tnew BlockAutoformatEditing( this.editor, /^[*-]\\s$/, 'bulletedList' );\n\t\t}\n\n\t\tif ( commands.get( 'numberedList' ) ) {\n\t\t\t// eslint-disable-next-line no-new\n\t\t\tnew BlockAutoformatEditing( this.editor, /^1[.|)]\\s$/, 'numberedList' );\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to the {@link module:basic-styles/bold~Bold},\n\t * {@link module:basic-styles/italic~Italic} and {@link module:basic-styles/code~Code}.\n\t *\n\t * When typed:\n\t * - `**foobar**` – `**` characters are removed and `foobar` is set to bold,\n\t * - `__foobar__` – `__` characters are removed and `foobar` is set to bold,\n\t * - `*foobar*` – `*` characters are removed and `foobar` is set to italic,\n\t * - `_foobar_` – `_` characters are removed and `foobar` is set to italic,\n\t * - ``` `foobar` – ``` ` ``` characters are removed and `foobar` is set to code.\n\t *\n\t * @private\n\t */\n\t_addBasicStylesAutoformats() {\n\t\tconst commands = this.editor.commands;\n\n\t\tif ( commands.get( 'bold' ) ) {\n\t\t\t/* eslint-disable no-new */\n\t\t\tconst boldCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'bold' );\n\n\t\t\tnew InlineAutoformatEditing( this.editor, /(\\*\\*)([^*]+)(\\*\\*)$/g, boldCallback );\n\t\t\tnew InlineAutoformatEditing( this.editor, /(__)([^_]+)(__)$/g, boldCallback );\n\t\t\t/* eslint-enable no-new */\n\t\t}\n\n\t\tif ( commands.get( 'italic' ) ) {\n\t\t\t/* eslint-disable no-new */\n\t\t\tconst italicCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'italic' );\n\n\t\t\t// The italic autoformatter cannot be triggered by the bold markers, so we need to check the\n\t\t\t// text before the pattern (e.g. `(?:^|[^\\*])`).\n\t\t\tnew InlineAutoformatEditing( this.editor, /(?:^|[^*])(\\*)([^*_]+)(\\*)$/g, italicCallback );\n\t\t\tnew InlineAutoformatEditing( this.editor, /(?:^|[^_])(_)([^_]+)(_)$/g, italicCallback );\n\t\t\t/* eslint-enable no-new */\n\t\t}\n\n\t\tif ( commands.get( 'code' ) ) {\n\t\t\t/* eslint-disable no-new */\n\t\t\tconst codeCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'code' );\n\n\t\t\tnew InlineAutoformatEditing( this.editor, /(`)([^`]+)(`)$/g, codeCallback );\n\t\t\t/* eslint-enable no-new */\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to {@link module:heading/heading~Heading}.\n\t *\n\t * It is using a number at the end of the command name to associate it with the proper trigger:\n\t *\n\t * * `heading` with value `heading1` will be executed when typing `#`,\n\t * * `heading` with value `heading2` will be executed when typing `##`,\n\t * * ... up to `heading6` and `######`.\n\t *\n\t * @private\n\t */\n\t_addHeadingAutoformats() {\n\t\tconst command = this.editor.commands.get( 'heading' );\n\n\t\tif ( command ) {\n\t\t\tcommand.modelElements\n\t\t\t\t.filter( name => name.match( /^heading[1-6]$/ ) )\n\t\t\t\t.forEach( commandValue => {\n\t\t\t\t\tconst level = commandValue[ 7 ];\n\t\t\t\t\tconst pattern = new RegExp( `^(#{${ level }})\\\\s$` );\n\n\t\t\t\t\t// eslint-disable-next-line no-new\n\t\t\t\t\tnew BlockAutoformatEditing( this.editor, pattern, () => {\n\t\t\t\t\t\tif ( !command.isEnabled ) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis.editor.execute( 'heading', { value: commandValue } );\n\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to {@link module:block-quote/blockquote~BlockQuote}.\n\t *\n\t * When typed:\n\t * * `> ` – A paragraph will be changed to a block quote.\n\t *\n\t * @private\n\t */\n\t_addBlockQuoteAutoformats() {\n\t\tif ( this.editor.commands.get( 'blockQuote' ) ) {\n\t\t\t// eslint-disable-next-line no-new\n\t\t\tnew BlockAutoformatEditing( this.editor, /^>\\s$/, 'blockQuote' );\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to {@link module:code-block/codeblock~CodeBlock}.\n\t *\n\t * When typed:\n\t * - `` ``` `` – A paragraph will be changed to a code block.\n\t *\n\t * @private\n\t */\n\t_addCodeBlockAutoformats() {\n\t\tif ( this.editor.commands.get( 'codeBlock' ) ) {\n\t\t\t// eslint-disable-next-line no-new\n\t\t\tnew BlockAutoformatEditing( this.editor, /^```$/, 'codeBlock' );\n\t\t}\n\t}\n}\n\n// Helper function for getting `InlineAutoformatEditing` callbacks that checks if command is enabled.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @param {String} attributeKey\n// @returns {Function}\nfunction getCallbackFunctionForInlineAutoformat( editor, attributeKey ) {\n\treturn ( writer, rangesToFormat ) => {\n\t\tconst command = editor.commands.get( attributeKey );\n\n\t\tif ( !command.isEnabled ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst validRanges = editor.model.schema.getValidRanges( rangesToFormat, attributeKey );\n\n\t\tfor ( const range of validRanges ) {\n\t\t\twriter.setAttribute( attributeKey, true, range );\n\t\t}\n\n\t\t// After applying attribute to the text, remove given attribute from the selection.\n\t\t// This way user is able to type a text without attribute used by auto formatter.\n\t\twriter.removeSelectionAttribute( attributeKey );\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/attributecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\n/**\n * An extension of the base {@link module:core/command~Command} class, which provides utilities for a command\n * that toggles a single attribute on a text or an element.\n *\n * `AttributeCommand` uses {@link module:engine/model/document~Document#selection}\n * to decide which nodes (if any) should be changed, and applies or removes the attribute from them.\n *\n * The command checks the {@link module:engine/model/model~Model#schema} to decide if it can be enabled\n * for the current selection and to which nodes the attribute can be applied.\n *\n * @extends module:core/command~Command\n */\nexport default class AttributeCommand extends Command {\n\t/**\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {String} attributeKey Attribute that will be set by the command.\n\t */\n\tconstructor( editor, attributeKey ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The attribute that will be set by the command.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.attributeKey = attributeKey;\n\n\t\t/**\n\t\t * Flag indicating whether the command is active. The command is active when the\n\t\t * {@link module:engine/model/selection~Selection#hasAttribute selection has the attribute} which means that:\n\t\t *\n\t\t * * If the selection is not empty – That the attribute is set on the first node in the selection that allows this attribute.\n\t\t * * If the selection is empty – That the selection has the attribute itself (which means that newly typed\n\t\t * text will have this attribute, too).\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #value\n\t\t */\n\t}\n\n\t/**\n\t * Updates the command's {@link #value} and {@link #isEnabled} based on the current selection.\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tthis.value = this._getValueFromFirstAllowedNode();\n\t\tthis.isEnabled = model.schema.checkAttributeInSelection( doc.selection, this.attributeKey );\n\t}\n\n\t/**\n\t * Executes the command — applies the attribute to the selection or removes it from the selection.\n\t *\n\t * If the command is active (`value == true`), it will remove attributes. Otherwise, it will set attributes.\n\t *\n\t * The execution result differs, depending on the {@link module:engine/model/document~Document#selection}:\n\t *\n\t * * If the selection is on a range, the command applies the attribute to all nodes in that range\n\t * (if they are allowed to have this attribute by the {@link module:engine/model/schema~Schema schema}).\n\t * * If the selection is collapsed in a non-empty node, the command applies the attribute to the\n\t * {@link module:engine/model/document~Document#selection} itself (note that typed characters copy attributes from the selection).\n\t * * If the selection is collapsed in an empty node, the command applies the attribute to the parent node of the selection (note\n\t * that the selection inherits all attributes from a node if it is in an empty node).\n\t *\n\t * @fires execute\n\t * @param {Object} [options] Command options.\n\t * @param {Boolean} [options.forceValue] If set, it will force the command behavior. If `true`, the command will apply the attribute,\n\t * otherwise the command will remove the attribute.\n\t * If not set, the command will look for its current value to decide what it should do.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\t\tconst value = ( options.forceValue === undefined ) ? !this.value : options.forceValue;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\tif ( value ) {\n\t\t\t\t\twriter.setSelectionAttribute( this.attributeKey, true );\n\t\t\t\t} else {\n\t\t\t\t\twriter.removeSelectionAttribute( this.attributeKey );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst ranges = model.schema.getValidRanges( selection.getRanges(), this.attributeKey );\n\n\t\t\t\tfor ( const range of ranges ) {\n\t\t\t\t\tif ( value ) {\n\t\t\t\t\t\twriter.setAttribute( this.attributeKey, value, range );\n\t\t\t\t\t} else {\n\t\t\t\t\t\twriter.removeAttribute( this.attributeKey, range );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the attribute value of the first node in the selection that allows the attribute.\n\t * For the collapsed selection returns the selection attribute.\n\t *\n\t * @private\n\t * @returns {Boolean} The attribute value.\n\t */\n\t_getValueFromFirstAllowedNode() {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst selection = model.document.selection;\n\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn selection.hasAttribute( this.attributeKey );\n\t\t}\n\n\t\tfor ( const range of selection.getRanges() ) {\n\t\t\tfor ( const item of range.getItems() ) {\n\t\t\t\tif ( schema.checkAttribute( item, this.attributeKey ) ) {\n\t\t\t\t\treturn item.hasAttribute( this.attributeKey );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/bold/boldediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport AttributeCommand from '../attributecommand';\n\nconst BOLD = 'bold';\n\n/**\n * The bold editing feature.\n *\n * It registers the `'bold'` command and introduces the `bold` attribute in the model which renders to the view\n * as a `<strong>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BoldEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BoldEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\t// Allow bold attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: BOLD } );\n\t\teditor.model.schema.setAttributeProperties( BOLD, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\t// Build converter from model to view for data and editing pipelines.\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: BOLD,\n\t\t\tview: 'strong',\n\t\t\tupcastAlso: [\n\t\t\t\t'b',\n\t\t\t\tviewElement => {\n\t\t\t\t\tconst fontWeight = viewElement.getStyle( 'font-weight' );\n\n\t\t\t\t\tif ( !fontWeight ) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Value of the `font-weight` attribute can be defined as a string or a number.\n\t\t\t\t\tif ( fontWeight == 'bold' || Number( fontWeight ) >= 600 ) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tname: true,\n\t\t\t\t\t\t\tstyles: [ 'font-weight' ]\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t// Create bold command.\n\t\teditor.commands.add( BOLD, new AttributeCommand( editor, BOLD ) );\n\n\t\t// Set the Ctrl+B keystroke.\n\t\teditor.keystrokes.set( 'CTRL+B', BOLD );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module basic-styles/bold/boldui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport boldIcon from '../../theme/assets/icons/bold.svg';\nconst BOLD = 'bold';\n/**\n * The bold UI feature. It introduces the Bold button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BoldUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n // Add bold button to feature components.\n editor.ui.componentFactory.add(BOLD, locale => {\n const command = editor.commands.get(BOLD);\n const view = new ButtonView(locale);\n view.set({\n label: t('g'),\n icon: boldIcon,\n keystroke: 'CTRL+B',\n tooltip: true,\n isToggleable: true\n });\n view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n // Execute command.\n this.listenTo(view, 'execute', () => {\n editor.execute(BOLD);\n editor.editing.view.focus();\n });\n return view;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M10.187 17H5.773c-.637 0-1.092-.138-1.364-.415-.273-.277-.409-.718-.409-1.323V4.738c0-.617.14-1.062.419-1.332.279-.27.73-.406 1.354-.406h4.68c.69 0 1.288.041 1.793.124.506.083.96.242 1.36.478.341.197.644.447.906.75a3.262 3.262 0 01.808 2.162c0 1.401-.722 2.426-2.167 3.075C15.05 10.175 16 11.315 16 13.01a3.756 3.756 0 01-2.296 3.504 6.1 6.1 0 01-1.517.377c-.571.073-1.238.11-2 .11zm-.217-6.217H7v4.087h3.069c1.977 0 2.965-.69 2.965-2.072 0-.707-.256-1.22-.768-1.537-.512-.319-1.277-.478-2.296-.478zM7 5.13v3.619h2.606c.729 0 1.292-.067 1.69-.2a1.6 1.6 0 00.91-.765c.165-.267.247-.566.247-.897 0-.707-.26-1.176-.778-1.409-.519-.232-1.31-.348-2.375-.348H7z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/italic/italicediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport AttributeCommand from '../attributecommand';\n\nconst ITALIC = 'italic';\n\n/**\n * The italic editing feature.\n *\n * It registers the `'italic'` command, the <kbd>Ctrl+I</kbd> keystroke and introduces the `italic` attribute in the model\n * which renders to the view as an `<i>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ItalicEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ItalicEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow italic attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: ITALIC } );\n\t\teditor.model.schema.setAttributeProperties( ITALIC, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: ITALIC,\n\t\t\tview: 'i',\n\t\t\tupcastAlso: [\n\t\t\t\t'em',\n\t\t\t\t{\n\t\t\t\t\tstyles: {\n\t\t\t\t\t\t'font-style': 'italic'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t// Create italic command.\n\t\teditor.commands.add( ITALIC, new AttributeCommand( editor, ITALIC ) );\n\n\t\t// Set the Ctrl+I keystroke.\n\t\teditor.keystrokes.set( 'CTRL+I', ITALIC );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module basic-styles/italic/italicui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport italicIcon from '../../theme/assets/icons/italic.svg';\nconst ITALIC = 'italic';\n/**\n * The italic UI feature. It introduces the Italic button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ItalicUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n // Add bold button to feature components.\n editor.ui.componentFactory.add(ITALIC, locale => {\n const command = editor.commands.get(ITALIC);\n const view = new ButtonView(locale);\n view.set({\n label: t('d'),\n icon: italicIcon,\n keystroke: 'CTRL+I',\n tooltip: true,\n isToggleable: true\n });\n view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n // Execute command.\n this.listenTo(view, 'execute', () => {\n editor.execute(ITALIC);\n editor.editing.view.focus();\n });\n return view;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M9.586 14.633l.021.004c-.036.335.095.655.393.962.082.083.173.15.274.201h1.474a.6.6 0 110 1.2H5.304a.6.6 0 010-1.2h1.15c.474-.07.809-.182 1.005-.334.157-.122.291-.32.404-.597l2.416-9.55a1.053 1.053 0 00-.281-.823 1.12 1.12 0 00-.442-.296H8.15a.6.6 0 010-1.2h6.443a.6.6 0 110 1.2h-1.195c-.376.056-.65.155-.823.296-.215.175-.423.439-.623.79l-2.366 9.347z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 utils/first\n */\n\n/**\n * Returns first item of the given `iterable`.\n *\n * @param {Iterable.<*>} iterable\n * @returns {*}\n */\nexport default function first( iterable ) {\n\tconst iteratorItem = iterable.next();\n\n\tif ( iteratorItem.done ) {\n\t\treturn null;\n\t}\n\n\treturn iteratorItem.value;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 block-quote/blockquotecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The block quote command plugin.\n *\n * @extends module:core/command~Command\n */\nexport default class BlockQuoteCommand extends Command {\n\t/**\n\t * Whether the selection starts in a block quote.\n\t *\n\t * @observable\n\t * @readonly\n\t * @member {Boolean} #value\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.value = this._getValue();\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Executes the command. When the command {@link #value is on}, all top-most block quotes within\n\t * the selection will be removed. If it is off, all selected blocks will be wrapped with\n\t * a block quote.\n\t *\n\t * @fires execute\n\t * @param {Object} [options] Command options.\n\t * @param {Boolean} [options.forceValue] If set, it will force the command behavior. If `true`, the command will apply a block quote,\n\t * otherwise the command will remove the block quote. If not set, the command will act basing on its current value.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst selection = model.document.selection;\n\n\t\tconst blocks = Array.from( selection.getSelectedBlocks() );\n\n\t\tconst value = ( options.forceValue === undefined ) ? !this.value : options.forceValue;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( !value ) {\n\t\t\t\tthis._removeQuote( writer, blocks.filter( findQuote ) );\n\t\t\t} else {\n\t\t\t\tconst blocksToQuote = blocks.filter( block => {\n\t\t\t\t\t// Already quoted blocks needs to be considered while quoting too\n\t\t\t\t\t// in order to reuse their <bQ> elements.\n\t\t\t\t\treturn findQuote( block ) || checkCanBeQuoted( schema, block );\n\t\t\t\t} );\n\n\t\t\t\tthis._applyQuote( writer, blocksToQuote );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the command's {@link #value}.\n\t *\n\t * @private\n\t * @returns {Boolean} The current value.\n\t */\n\t_getValue() {\n\t\tconst selection = this.editor.model.document.selection;\n\n\t\tconst firstBlock = first( selection.getSelectedBlocks() );\n\n\t\t// In the current implementation, the block quote must be an immediate parent of a block element.\n\t\treturn !!( firstBlock && findQuote( firstBlock ) );\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\tif ( this.value ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst schema = this.editor.model.schema;\n\n\t\tconst firstBlock = first( selection.getSelectedBlocks() );\n\n\t\tif ( !firstBlock ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn checkCanBeQuoted( schema, firstBlock );\n\t}\n\n\t/**\n\t * Removes the quote from given blocks.\n\t *\n\t * If blocks which are supposed to be \"unquoted\" are in the middle of a quote,\n\t * start it or end it, then the quote will be split (if needed) and the blocks\n\t * will be moved out of it, so other quoted blocks remained quoted.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @param {Array.<module:engine/model/element~Element>} blocks\n\t */\n\t_removeQuote( writer, blocks ) {\n\t\t// Unquote all groups of block. Iterate in the reverse order to not break following ranges.\n\t\tgetRangesOfBlockGroups( writer, blocks ).reverse().forEach( groupRange => {\n\t\t\tif ( groupRange.start.isAtStart && groupRange.end.isAtEnd ) {\n\t\t\t\twriter.unwrap( groupRange.start.parent );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The group of blocks are at the beginning of an <bQ> so let's move them left (out of the <bQ>).\n\t\t\tif ( groupRange.start.isAtStart ) {\n\t\t\t\tconst positionBefore = writer.createPositionBefore( groupRange.start.parent );\n\n\t\t\t\twriter.move( groupRange, positionBefore );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The blocks are in the middle of an <bQ> so we need to split the <bQ> after the last block\n\t\t\t// so we move the items there.\n\t\t\tif ( !groupRange.end.isAtEnd ) {\n\t\t\t\twriter.split( groupRange.end );\n\t\t\t}\n\n\t\t\t// Now we are sure that groupRange.end.isAtEnd is true, so let's move the blocks right.\n\n\t\t\tconst positionAfter = writer.createPositionAfter( groupRange.end.parent );\n\n\t\t\twriter.move( groupRange, positionAfter );\n\t\t} );\n\t}\n\n\t/**\n\t * Applies the quote to given blocks.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @param {Array.<module:engine/model/element~Element>} blocks\n\t */\n\t_applyQuote( writer, blocks ) {\n\t\tconst quotesToMerge = [];\n\n\t\t// Quote all groups of block. Iterate in the reverse order to not break following ranges.\n\t\tgetRangesOfBlockGroups( writer, blocks ).reverse().forEach( groupRange => {\n\t\t\tlet quote = findQuote( groupRange.start );\n\n\t\t\tif ( !quote ) {\n\t\t\t\tquote = writer.createElement( 'blockQuote' );\n\n\t\t\t\twriter.wrap( groupRange, quote );\n\t\t\t}\n\n\t\t\tquotesToMerge.push( quote );\n\t\t} );\n\n\t\t// Merge subsequent <bQ> elements. Reverse the order again because this time we want to go through\n\t\t// the <bQ> elements in the source order (due to how merge works – it moves the right element's content\n\t\t// to the first element and removes the right one. Since we may need to merge a couple of subsequent `<bQ>` elements\n\t\t// we want to keep the reference to the first (furthest left) one.\n\t\tquotesToMerge.reverse().reduce( ( currentQuote, nextQuote ) => {\n\t\t\tif ( currentQuote.nextSibling == nextQuote ) {\n\t\t\t\twriter.merge( writer.createPositionAfter( currentQuote ) );\n\n\t\t\t\treturn currentQuote;\n\t\t\t}\n\n\t\t\treturn nextQuote;\n\t\t} );\n\t}\n}\n\nfunction findQuote( elementOrPosition ) {\n\treturn elementOrPosition.parent.name == 'blockQuote' ? elementOrPosition.parent : null;\n}\n\n// Returns a minimal array of ranges containing groups of subsequent blocks.\n//\n// content: abcdefgh\n// blocks: [ a, b, d, f, g, h ]\n// output ranges: [ab]c[d]e[fgh]\n//\n// @param {Array.<module:engine/model/element~Element>} blocks\n// @returns {Array.<module:engine/model/range~Range>}\nfunction getRangesOfBlockGroups( writer, blocks ) {\n\tlet startPosition;\n\tlet i = 0;\n\tconst ranges = [];\n\n\twhile ( i < blocks.length ) {\n\t\tconst block = blocks[ i ];\n\t\tconst nextBlock = blocks[ i + 1 ];\n\n\t\tif ( !startPosition ) {\n\t\t\tstartPosition = writer.createPositionBefore( block );\n\t\t}\n\n\t\tif ( !nextBlock || block.nextSibling != nextBlock ) {\n\t\t\tranges.push( writer.createRange( startPosition, writer.createPositionAfter( block ) ) );\n\t\t\tstartPosition = null;\n\t\t}\n\n\t\ti++;\n\t}\n\n\treturn ranges;\n}\n\n// Checks whether <bQ> can wrap the block.\nfunction checkCanBeQuoted( schema, block ) {\n\t// TMP will be replaced with schema.checkWrap().\n\tconst isBQAllowed = schema.checkChild( block.parent, 'blockQuote' );\n\tconst isBlockAllowedInBQ = schema.checkChild( [ '$root', 'blockQuote' ], block );\n\n\treturn isBQAllowed && isBlockAllowedInBQ;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 block-quote/blockquoteediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport BlockQuoteCommand from './blockquotecommand';\n\n/**\n * The block quote editing.\n *\n * Introduces the `'blockQuote'` command and the `'blockQuote'` model element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BlockQuoteEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BlockQuoteEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\n\t\teditor.commands.add( 'blockQuote', new BlockQuoteCommand( editor ) );\n\n\t\tschema.register( 'blockQuote', {\n\t\t\tallowWhere: '$block',\n\t\t\tallowContentOf: '$root'\n\t\t} );\n\n\t\t// Disallow blockQuote in blockQuote.\n\t\tschema.addChildCheck( ( ctx, childDef ) => {\n\t\t\tif ( ctx.endsWith( 'blockQuote' ) && childDef.name == 'blockQuote' ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} );\n\n\t\teditor.conversion.elementToElement( { model: 'blockQuote', view: 'blockquote' } );\n\n\t\t// Postfixer which cleans incorrect model states connected with block quotes.\n\t\teditor.model.document.registerPostFixer( writer => {\n\t\t\tconst changes = editor.model.document.differ.getChanges();\n\n\t\t\tfor ( const entry of changes ) {\n\t\t\t\tif ( entry.type == 'insert' ) {\n\t\t\t\t\tconst element = entry.position.nodeAfter;\n\n\t\t\t\t\tif ( !element ) {\n\t\t\t\t\t\t// We are inside a text node.\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( element.is( 'blockQuote' ) && element.isEmpty ) {\n\t\t\t\t\t\t// Added an empty blockQuote - remove it.\n\t\t\t\t\t\twriter.remove( element );\n\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else if ( element.is( 'blockQuote' ) && !schema.checkChild( entry.position, element ) ) {\n\t\t\t\t\t\t// Added a blockQuote in incorrect place - most likely inside another blockQuote. Unwrap it\n\t\t\t\t\t\t// so the content inside is not lost.\n\t\t\t\t\t\twriter.unwrap( element );\n\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else if ( element.is( 'element' ) ) {\n\t\t\t\t\t\t// Just added an element. Check its children to see if there are no nested blockQuotes somewhere inside.\n\t\t\t\t\t\tconst range = writer.createRangeIn( element );\n\n\t\t\t\t\t\tfor ( const child of range.getItems() ) {\n\t\t\t\t\t\t\tif ( child.is( 'blockQuote' ) && !schema.checkChild( writer.createPositionBefore( child ), child ) ) {\n\t\t\t\t\t\t\t\twriter.unwrap( child );\n\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if ( entry.type == 'remove' ) {\n\t\t\t\t\tconst parent = entry.position.parent;\n\n\t\t\t\t\tif ( parent.is( 'blockQuote' ) && parent.isEmpty ) {\n\t\t\t\t\t\t// Something got removed and now blockQuote is empty. Remove the blockQuote as well.\n\t\t\t\t\t\twriter.remove( parent );\n\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst editor = this.editor;\n\t\tconst command = editor.commands.get( 'blockQuote' );\n\n\t\t// Overwrite default Enter key behavior.\n\t\t// If Enter key is pressed with selection collapsed in empty block inside a quote, break the quote.\n\t\t// This listener is added in afterInit in order to register it after list's feature listener.\n\t\t// We can't use a priority for this, because 'low' is already used by the enter feature, unless\n\t\t// we'd use numeric priority in this case.\n\t\tthis.listenTo( this.editor.editing.view.document, 'enter', ( evt, data ) => {\n\t\t\tconst doc = this.editor.model.document;\n\t\t\tconst positionParent = doc.selection.getLastPosition().parent;\n\n\t\t\tif ( doc.selection.isCollapsed && positionParent.isEmpty && command.value ) {\n\t\t\t\tthis.editor.execute( 'blockQuote' );\n\t\t\t\tthis.editor.editing.view.scrollToTheSelection();\n\n\t\t\t\tdata.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module block-quote/blockquoteui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport quoteIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/quote.svg';\nimport '../theme/blockquote.css';\n/**\n * The block quote UI plugin.\n *\n * It introduces the `'blockQuote'` button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BlockQuoteUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n editor.ui.componentFactory.add('blockQuote', locale => {\n const command = editor.commands.get('blockQuote');\n const buttonView = new ButtonView(locale);\n buttonView.set({\n label: t('k'),\n icon: quoteIcon,\n tooltip: true,\n isToggleable: true\n });\n // Bind button model to command.\n buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n // Execute command.\n this.listenTo(buttonView, 'execute', () => {\n editor.execute('blockQuote');\n editor.editing.view.focus();\n });\n return buttonView;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3 10.423a6.5 6.5 0 016.056-6.408l.038.67C6.448 5.423 5.354 7.663 5.22 10H9c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.574zm8 0a6.5 6.5 0 016.056-6.408l.038.67c-2.646.739-3.74 2.979-3.873 5.315H17c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.574z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module ckfinder/ckfinderui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport browseFilesIcon from '../theme/assets/icons/browse-files.svg';\n/**\n * The CKFinder UI plugin. It introduces the `'ckfinder'` toolbar button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CKFinderUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'CKFinderUI';\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const componentFactory = editor.ui.componentFactory;\n const t = editor.t;\n componentFactory.add('ckfinder', locale => {\n const command = editor.commands.get('ckfinder');\n const button = new ButtonView(locale);\n button.set({\n label: t('t'),\n icon: browseFilesIcon,\n tooltip: true\n });\n button.bind('isEnabled').to(command);\n button.on('execute', () => {\n editor.execute('ckfinder');\n editor.editing.view.focus();\n });\n return button;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.627 16.5zm5.873-.196zm0-7.001V8h-13v8.5h4.341c.191.54.457 1.044.785 1.5H2a1.5 1.5 0 01-1.5-1.5v-13A1.5 1.5 0 012 2h4.5a1.5 1.5 0 011.06.44L9.122 4H16a1.5 1.5 0 011.5 1.5v1A1.5 1.5 0 0119 8v2.531a6.027 6.027 0 00-1.5-1.228zM16 6.5v-1H8.5l-2-2H2v13h1V8a1.5 1.5 0 011.5-1.5H16z\\\"/><path d=\\\"M14.5 19.5a5 5 0 110-10 5 5 0 010 10zM15 14v-2h-1v2h-2v1h2v2h1v-2h2v-1h-2z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 image/image/imageloadobserver\n */\n\nimport Observer from '@ckeditor/ckeditor5-engine/src/view/observer/observer';\n\n/**\n * Observes all new images added to the {@link module:engine/view/document~Document},\n * fires {@link module:engine/view/document~Document#event:imageLoaded} and\n * {@link module:engine/view/document~Document#event:layoutChanged} event every time when the new image\n * has been loaded.\n *\n * **Note:** This event is not fired for images that has been added to the document and rendered as `complete` (already loaded).\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class ImageLoadObserver extends Observer {\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve( domRoot ) {\n\t\tthis.listenTo( domRoot, 'load', ( event, domEvent ) => {\n\t\t\tconst domElement = domEvent.target;\n\n\t\t\tif ( domElement.tagName == 'IMG' ) {\n\t\t\t\tthis._fireEvents( domEvent );\n\t\t\t}\n\t\t\t// Use capture phase for better performance (#4504).\n\t\t}, { useCapture: true } );\n\t}\n\n\t/**\n\t * Fires {@link module:engine/view/document~Document#event:layoutChanged} and\n\t * {@link module:engine/view/document~Document#event:imageLoaded}\n\t * if observer {@link #isEnabled is enabled}.\n\t *\n\t * @protected\n\t * @param {Event} domEvent The DOM event.\n\t */\n\t_fireEvents( domEvent ) {\n\t\tif ( this.isEnabled ) {\n\t\t\tthis.document.fire( 'layoutChanged' );\n\t\t\tthis.document.fire( 'imageLoaded', domEvent );\n\t\t}\n\t}\n}\n\n/**\n * Fired when an <img/> DOM element has been loaded in the DOM root.\n *\n * Introduced by {@link module:image/image/imageloadobserver~ImageLoadObserver}.\n *\n * @see module:image/image/imageloadobserver~ImageLoadObserver\n * @event module:engine/view/document~Document#event:imageLoaded\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 image/image/converters\n */\n\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * Returns a function that converts the image view representation:\n *\n *\t\t<figure class=\"image\"><img src=\"...\" alt=\"...\"></img></figure>\n *\n * to the model representation:\n *\n *\t\t<image src=\"...\" alt=\"...\"></image>\n *\n * The entire content of the `<figure>` element except the first `<img>` is being converted as children\n * of the `<image>` model element.\n *\n * @returns {Function}\n */\nexport function viewFigureToModel() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element:figure', converter );\n\t};\n\n\tfunction converter( evt, data, conversionApi ) {\n\t\t// Do not convert if this is not an \"image figure\".\n\t\tif ( !conversionApi.consumable.test( data.viewItem, { name: true, classes: 'image' } ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Find an image element inside the figure element.\n\t\tconst viewImage = Array.from( data.viewItem.getChildren() ).find( viewChild => viewChild.is( 'img' ) );\n\n\t\t// Do not convert if image element is absent, is missing src attribute or was already converted.\n\t\tif ( !viewImage || !viewImage.hasAttribute( 'src' ) || !conversionApi.consumable.test( viewImage, { name: true } ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Convert view image to model image.\n\t\tconst conversionResult = conversionApi.convertItem( viewImage, data.modelCursor );\n\n\t\t// Get image element from conversion result.\n\t\tconst modelImage = first( conversionResult.modelRange.getItems() );\n\n\t\t// When image wasn't successfully converted then finish conversion.\n\t\tif ( !modelImage ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Convert rest of the figure element's children as an image children.\n\t\tconversionApi.convertChildren( data.viewItem, conversionApi.writer.createPositionAt( modelImage, 0 ) );\n\n\t\t// Set image range as conversion result.\n\t\tdata.modelRange = conversionResult.modelRange;\n\n\t\t// Continue conversion where image conversion ends.\n\t\tdata.modelCursor = conversionResult.modelCursor;\n\t}\n}\n\n/**\n * Converter used to convert the `srcset` model image attribute to the `srcset`, `sizes` and `width` attributes in the view.\n *\n * @returns {Function}\n */\nexport function srcsetAttributeConverter() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'attribute:srcset:image', converter );\n\t};\n\n\tfunction converter( evt, data, conversionApi ) {\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst writer = conversionApi.writer;\n\t\tconst figure = conversionApi.mapper.toViewElement( data.item );\n\t\tconst img = figure.getChild( 0 );\n\n\t\tif ( data.attributeNewValue === null ) {\n\t\t\tconst srcset = data.attributeOldValue;\n\n\t\t\tif ( srcset.data ) {\n\t\t\t\twriter.removeAttribute( 'srcset', img );\n\t\t\t\twriter.removeAttribute( 'sizes', img );\n\n\t\t\t\tif ( srcset.width ) {\n\t\t\t\t\twriter.removeAttribute( 'width', img );\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst srcset = data.attributeNewValue;\n\n\t\t\tif ( srcset.data ) {\n\t\t\t\twriter.setAttribute( 'srcset', srcset.data, img );\n\t\t\t\t// Always outputting `100vw`. See https://github.com/ckeditor/ckeditor5-image/issues/2.\n\t\t\t\twriter.setAttribute( 'sizes', '100vw', img );\n\n\t\t\t\tif ( srcset.width ) {\n\t\t\t\t\twriter.setAttribute( 'width', srcset.width, img );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport function modelToViewAttributeConverter( attributeKey ) {\n\treturn dispatcher => {\n\t\tdispatcher.on( `attribute:${ attributeKey }:image`, converter );\n\t};\n\n\tfunction converter( evt, data, conversionApi ) {\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst figure = conversionApi.mapper.toViewElement( data.item );\n\t\tconst img = figure.getChild( 0 );\n\n\t\tif ( data.attributeNewValue !== null ) {\n\t\t\tviewWriter.setAttribute( data.attributeKey, data.attributeNewValue, img );\n\t\t} else {\n\t\t\tviewWriter.removeAttribute( data.attributeKey, img );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 widget/highlightstack\n */\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Class used to handle correct order of highlights on elements.\n *\n * When different highlights are applied to same element correct order should be preserved:\n *\n * * highlight with highest priority should be applied,\n * * if two highlights have same priority - sort by CSS class provided in\n * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor}.\n *\n * This way, highlight will be applied with the same rules it is applied on texts.\n */\nexport default class HighlightStack {\n\t/**\n\t * Creates class instance.\n\t */\n\tconstructor() {\n\t\tthis._stack = [];\n\t}\n\n\t/**\n\t * Adds highlight descriptor to the stack.\n\t *\n\t * @fires change:top\n\t * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\tadd( descriptor, writer ) {\n\t\tconst stack = this._stack;\n\n\t\t// Save top descriptor and insert new one. If top is changed - fire event.\n\t\tconst oldTop = stack[ 0 ];\n\t\tthis._insertDescriptor( descriptor );\n\t\tconst newTop = stack[ 0 ];\n\n\t\t// When new object is at the top and stores different information.\n\t\tif ( oldTop !== newTop && !compareDescriptors( oldTop, newTop ) ) {\n\t\t\tthis.fire( 'change:top', {\n\t\t\t\toldDescriptor: oldTop,\n\t\t\t\tnewDescriptor: newTop,\n\t\t\t\twriter\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Removes highlight descriptor from the stack.\n\t *\n\t * @fires change:top\n\t * @param {String} id Id of the descriptor to remove.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\tremove( id, writer ) {\n\t\tconst stack = this._stack;\n\n\t\tconst oldTop = stack[ 0 ];\n\t\tthis._removeDescriptor( id );\n\t\tconst newTop = stack[ 0 ];\n\n\t\t// When new object is at the top and stores different information.\n\t\tif ( oldTop !== newTop && !compareDescriptors( oldTop, newTop ) ) {\n\t\t\tthis.fire( 'change:top', {\n\t\t\t\toldDescriptor: oldTop,\n\t\t\t\tnewDescriptor: newTop,\n\t\t\t\twriter\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Inserts given descriptor in correct place in the stack. It also takes care about updating information when\n\t * descriptor with same id is already present.\n\t *\n\t * @private\n\t * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor\n\t */\n\t_insertDescriptor( descriptor ) {\n\t\tconst stack = this._stack;\n\t\tconst index = stack.findIndex( item => item.id === descriptor.id );\n\n\t\t// Inserting exact same descriptor - do nothing.\n\t\tif ( compareDescriptors( descriptor, stack[ index ] ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If descriptor with same id but with different information is on the stack - remove it.\n\t\tif ( index > -1 ) {\n\t\t\tstack.splice( index, 1 );\n\t\t}\n\n\t\t// Find correct place to insert descriptor in the stack.\n\t\t// It have different information (for example priority) so it must be re-inserted in correct place.\n\t\tlet i = 0;\n\n\t\twhile ( stack[ i ] && shouldABeBeforeB( stack[ i ], descriptor ) ) {\n\t\t\ti++;\n\t\t}\n\n\t\tstack.splice( i, 0, descriptor );\n\t}\n\n\t/**\n\t * Removes descriptor with given id from the stack.\n\t *\n\t * @private\n\t * @param {String} id Descriptor's id.\n\t */\n\t_removeDescriptor( id ) {\n\t\tconst stack = this._stack;\n\t\tconst index = stack.findIndex( item => item.id === id );\n\n\t\t// If descriptor with same id is on the list - remove it.\n\t\tif ( index > -1 ) {\n\t\t\tstack.splice( index, 1 );\n\t\t}\n\t}\n}\n\nmix( HighlightStack, EmitterMixin );\n\n// Compares two descriptors by checking their priority and class list.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} a\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} b\n// @returns {Boolean} Returns true if both descriptors are defined and have same priority and classes.\nfunction compareDescriptors( a, b ) {\n\treturn a && b && a.priority == b.priority && classesToString( a.classes ) == classesToString( b.classes );\n}\n\n// Checks whenever first descriptor should be placed in the stack before second one.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} a\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} b\n// @returns {Boolean}\nfunction shouldABeBeforeB( a, b ) {\n\tif ( a.priority > b.priority ) {\n\t\treturn true;\n\t} else if ( a.priority < b.priority ) {\n\t\treturn false;\n\t}\n\n\t// When priorities are equal and names are different - use classes to compare.\n\treturn classesToString( a.classes ) > classesToString( b.classes );\n}\n\n// Converts CSS classes passed with {@link module:engine/conversion/downcasthelpers~HighlightDescriptor} to\n// sorted string.\n//\n// @param {String|Array<String>} descriptor\n// @returns {String}\nfunction classesToString( classes ) {\n\treturn Array.isArray( classes ) ? classes.sort().join( ',' ) : classes;\n}\n\n/**\n * Fired when top element on {@link module:widget/highlightstack~HighlightStack} has been changed\n *\n * @event change:top\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} [data.newDescriptor] New highlight\n * descriptor. It will be `undefined` when last descriptor is removed from the stack.\n * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} [data.oldDescriptor] Old highlight\n * descriptor. It will be `undefined` when first descriptor is added to the stack.\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that can be used to modify element.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 widget/utils\n */\n\nimport HighlightStack from './highlightstack';\nimport IconView from '@ckeditor/ckeditor5-ui/src/icon/iconview';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\nimport dragHandleIcon from '../theme/assets/icons/drag-handle.svg';\n\n/**\n * CSS class added to each widget element.\n *\n * @const {String}\n */\nexport const WIDGET_CLASS_NAME = 'ck-widget';\n\n/**\n * CSS class added to currently selected widget element.\n *\n * @const {String}\n */\nexport const WIDGET_SELECTED_CLASS_NAME = 'ck-widget_selected';\n\n/**\n * Returns `true` if given {@link module:engine/view/node~Node} is an {@link module:engine/view/element~Element} and a widget.\n *\n * @param {module:engine/view/node~Node} node\n * @returns {Boolean}\n */\nexport function isWidget( node ) {\n\tif ( !node.is( 'element' ) ) {\n\t\treturn false;\n\t}\n\n\treturn !!node.getCustomProperty( 'widget' );\n}\n\n/* eslint-disable max-len */\n/**\n * Converts the given {@link module:engine/view/element~Element} to a widget in the following way:\n *\n * * sets the `contenteditable` attribute to `\"true\"`,\n * * adds the `ck-widget` CSS class,\n * * adds a custom {@link module:engine/view/element~Element#getFillerOffset `getFillerOffset()`} method returning `null`,\n * * adds a custom property allowing to recognize widget elements by using {@link ~isWidget `isWidget()`},\n * * implements the {@link ~setHighlightHandling view highlight on widgets}.\n *\n * This function needs to be used in conjunction with\n * {@link module:engine/conversion/downcasthelpers~DowncastHelpers downcast conversion helpers}\n * like {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`}.\n * Moreover, typically you will want to use `toWidget()` only for `editingDowncast`, while keeping the `dataDowncast` clean.\n *\n * For example, in order to convert a `<widget>` model element to `<div class=\"widget\">` in the view, you can define\n * such converters:\n *\n *\t\teditor.conversion.for( 'editingDowncast' )\n *\t\t\t.elementToElement( {\n *\t\t\t\tmodel: 'widget',\n *\t\t\t\tview: ( modelItem, writer ) => {\n *\t\t\t\t\tconst div = writer.createContainerElement( 'div', { class: 'widget' } );\n *\n *\t\t\t\t\treturn toWidget( div, writer, { label: 'some widget' } );\n *\t\t\t\t}\n *\t\t\t} );\n *\n *\t\teditor.conversion.for( 'dataDowncast' )\n *\t\t\t.elementToElement( {\n *\t\t\t\tmodel: 'widget',\n *\t\t\t\tview: ( modelItem, writer ) => {\n *\t\t\t\t\treturn writer.createContainerElement( 'div', { class: 'widget' } );\n *\t\t\t\t}\n *\t\t\t} );\n *\n * See the full source code of the widget (with a nested editable) schema definition and converters in\n * [this sample](https://github.com/ckeditor/ckeditor5-widget/blob/master/tests/manual/widget-with-nestededitable.js).\n *\n * @param {module:engine/view/element~Element} element\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {Object} [options={}]\n * @param {String|Function} [options.label] Element's label provided to the {@link ~setLabel} function. It can be passed as\n * a plain string or a function returning a string. It represents the widget for assistive technologies (like screen readers).\n * @param {Boolean} [options.hasSelectionHandle=false] If `true`, the widget will have a selection handle added.\n * @returns {module:engine/view/element~Element} Returns the same element.\n */\n/* eslint-enable max-len */\nexport function toWidget( element, writer, options = {} ) {\n\t// The selection on Edge behaves better when the whole editor contents is in a single contenteditable element.\n\t// https://github.com/ckeditor/ckeditor5/issues/1079\n\tif ( !env.isEdge ) {\n\t\twriter.setAttribute( 'contenteditable', 'false', element );\n\t}\n\n\twriter.addClass( WIDGET_CLASS_NAME, element );\n\twriter.setCustomProperty( 'widget', true, element );\n\telement.getFillerOffset = getFillerOffset;\n\n\tif ( options.label ) {\n\t\tsetLabel( element, options.label, writer );\n\t}\n\n\tif ( options.hasSelectionHandle ) {\n\t\taddSelectionHandle( element, writer );\n\t}\n\n\tsetHighlightHandling(\n\t\telement,\n\t\twriter,\n\t\t( element, descriptor, writer ) => writer.addClass( normalizeToArray( descriptor.classes ), element ),\n\t\t( element, descriptor, writer ) => writer.removeClass( normalizeToArray( descriptor.classes ), element )\n\t);\n\n\treturn element;\n\n\t// Normalizes CSS class in descriptor that can be provided in form of an array or a string.\n\tfunction normalizeToArray( classes ) {\n\t\treturn Array.isArray( classes ) ? classes : [ classes ];\n\t}\n}\n\n/**\n * Sets highlight handling methods. Uses {@link module:widget/highlightstack~HighlightStack} to\n * properly determine which highlight descriptor should be used at given time.\n *\n * @param {module:engine/view/element~Element} element\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {Function} add\n * @param {Function} remove\n */\nexport function setHighlightHandling( element, writer, add, remove ) {\n\tconst stack = new HighlightStack();\n\n\tstack.on( 'change:top', ( evt, data ) => {\n\t\tif ( data.oldDescriptor ) {\n\t\t\tremove( element, data.oldDescriptor, data.writer );\n\t\t}\n\n\t\tif ( data.newDescriptor ) {\n\t\t\tadd( element, data.newDescriptor, data.writer );\n\t\t}\n\t} );\n\n\twriter.setCustomProperty( 'addHighlight', ( element, descriptor, writer ) => stack.add( descriptor, writer ), element );\n\twriter.setCustomProperty( 'removeHighlight', ( element, id, writer ) => stack.remove( id, writer ), element );\n}\n\n/**\n * Sets label for given element.\n * It can be passed as a plain string or a function returning a string. Function will be called each time label is retrieved by\n * {@link ~getLabel `getLabel()`}.\n *\n * @param {module:engine/view/element~Element} element\n * @param {String|Function} labelOrCreator\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n */\nexport function setLabel( element, labelOrCreator, writer ) {\n\twriter.setCustomProperty( 'widgetLabel', labelOrCreator, element );\n}\n\n/**\n * Returns the label of the provided element.\n *\n * @param {module:engine/view/element~Element} element\n * @returns {String}\n */\nexport function getLabel( element ) {\n\tconst labelCreator = element.getCustomProperty( 'widgetLabel' );\n\n\tif ( !labelCreator ) {\n\t\treturn '';\n\t}\n\n\treturn typeof labelCreator == 'function' ? labelCreator() : labelCreator;\n}\n\n/**\n * Adds functionality to the provided {@link module:engine/view/editableelement~EditableElement} to act as a widget's editable:\n *\n * * sets the `contenteditable` attribute to `true` when {@link module:engine/view/editableelement~EditableElement#isReadOnly} is `false`,\n * otherwise sets it to `false`,\n * * adds the `ck-editor__editable` and `ck-editor__nested-editable` CSS classes,\n * * adds the `ck-editor__nested-editable_focused` CSS class when the editable is focused and removes it when it is blurred.\n *\n * Similarly to {@link ~toWidget `toWidget()`} this function should be used in `dataDowncast` only and it is usually\n * used together with {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`}.\n *\n * For example, in order to convert a `<nested>` model element to `<div class=\"nested\">` in the view, you can define\n * such converters:\n *\n *\t\teditor.conversion.for( 'editingDowncast' )\n *\t\t\t.elementToElement( {\n *\t\t\t\tmodel: 'nested',\n *\t\t\t\tview: ( modelItem, writer ) => {\n *\t\t\t\t\tconst div = writer.createEditableElement( 'div', { class: 'nested' } );\n *\n *\t\t\t\t\treturn toWidgetEditable( nested, writer );\n *\t\t\t\t}\n *\t\t\t} );\n *\n *\t\teditor.conversion.for( 'dataDowncast' )\n *\t\t\t.elementToElement( {\n *\t\t\t\tmodel: 'nested',\n *\t\t\t\tview: ( modelItem, writer ) => {\n *\t\t\t\t\treturn writer.createContainerElement( 'div', { class: 'nested' } );\n *\t\t\t\t}\n *\t\t\t} );\n *\n * See the full source code of the widget (with nested editable) schema definition and converters in\n * [this sample](https://github.com/ckeditor/ckeditor5-widget/blob/master/tests/manual/widget-with-nestededitable.js).\n *\n * @param {module:engine/view/editableelement~EditableElement} editable\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @returns {module:engine/view/editableelement~EditableElement} Returns the same element that was provided in the `editable` parameter\n */\nexport function toWidgetEditable( editable, writer ) {\n\twriter.addClass( [ 'ck-editor__editable', 'ck-editor__nested-editable' ], editable );\n\n\t// The selection on Edge behaves better when the whole editor contents is in a single contentedible element.\n\t// https://github.com/ckeditor/ckeditor5/issues/1079\n\tif ( !env.isEdge ) {\n\t\t// Set initial contenteditable value.\n\t\twriter.setAttribute( 'contenteditable', editable.isReadOnly ? 'false' : 'true', editable );\n\n\t\t// Bind the contenteditable property to element#isReadOnly.\n\t\teditable.on( 'change:isReadOnly', ( evt, property, is ) => {\n\t\t\twriter.setAttribute( 'contenteditable', is ? 'false' : 'true', editable );\n\t\t} );\n\t}\n\n\teditable.on( 'change:isFocused', ( evt, property, is ) => {\n\t\tif ( is ) {\n\t\t\twriter.addClass( 'ck-editor__nested-editable_focused', editable );\n\t\t} else {\n\t\t\twriter.removeClass( 'ck-editor__nested-editable_focused', editable );\n\t\t}\n\t} );\n\n\treturn editable;\n}\n\n/**\n * Returns a model position which is optimal (in terms of UX) for inserting a widget block.\n *\n * For instance, if a selection is in the middle of a paragraph, the position before this paragraph\n * will be returned so that it is not split. If the selection is at the end of a paragraph,\n * the position after this paragraph will be returned.\n *\n * Note: If the selection is placed in an empty block, that block will be returned. If that position\n * is then passed to {@link module:engine/model/model~Model#insertContent},\n * the block will be fully replaced by the image.\n *\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * The selection based on which the insertion position should be calculated.\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {module:engine/model/position~Position} The optimal position.\n */\nexport function findOptimalInsertionPosition( selection, model ) {\n\tconst selectedElement = selection.getSelectedElement();\n\n\tif ( selectedElement && model.schema.isBlock( selectedElement ) ) {\n\t\treturn model.createPositionAfter( selectedElement );\n\t}\n\n\tconst firstBlock = selection.getSelectedBlocks().next().value;\n\n\tif ( firstBlock ) {\n\t\t// If inserting into an empty block – return position in that block. It will get\n\t\t// replaced with the image by insertContent(). #42.\n\t\tif ( firstBlock.isEmpty ) {\n\t\t\treturn model.createPositionAt( firstBlock, 0 );\n\t\t}\n\n\t\tconst positionAfter = model.createPositionAfter( firstBlock );\n\n\t\t// If selection is at the end of the block - return position after the block.\n\t\tif ( selection.focus.isTouching( positionAfter ) ) {\n\t\t\treturn positionAfter;\n\t\t}\n\n\t\t// Otherwise return position before the block.\n\t\treturn model.createPositionBefore( firstBlock );\n\t}\n\n\treturn selection.focus;\n}\n\n/**\n * A util to be used in order to map view positions to correct model positions when implementing a widget\n * which renders non-empty view element for an empty model element.\n *\n * For example:\n *\n *\t\t// Model:\n *\t\t<placeholder type=\"name\"></placeholder>\n *\n *\t\t// View:\n *\t\t<span class=\"placeholder\">name</span>\n *\n * In such case, view positions inside `<span>` cannot be correct mapped to the model (because the model element is empty).\n * To handle mapping positions inside `<span class=\"placeholder\">` to the model use this util as follows:\n *\n *\t\teditor.editing.mapper.on(\n *\t\t\t'viewToModelPosition',\n *\t\t\tviewToModelPositionOutsideModelElement( model, viewElement => viewElement.hasClass( 'placeholder' ) )\n *\t\t);\n *\n * The callback will try to map the view offset of selection to an expected model position.\n *\n * 1. When the position is at the end (or in the middle) of the inline widget:\n *\n *\t\t// View:\n *\t\t<p>foo <span class=\"placeholder\">name|</span> bar</p>\n *\n *\t\t// Model:\n *\t\t<paragraph>foo <placeholder type=\"name\"></placeholder>| bar</paragraph>\n *\n * 2. When the position is at the beginning of the inline widget:\n *\n *\t\t// View:\n *\t\t<p>foo <span class=\"placeholder\">|name</span> bar</p>\n *\n *\t\t// Model:\n *\t\t<paragraph>foo |<placeholder type=\"name\"></placeholder> bar</paragraph>\n *\n * @param {module:engine/model/model~Model} model Model instance on which the callback operates.\n * @param {Function} viewElementMatcher Function that is passed a view element and should return `true` if the custom mapping\n * should be applied to the given view element.\n * @return {Function}\n */\nexport function viewToModelPositionOutsideModelElement( model, viewElementMatcher ) {\n\treturn ( evt, data ) => {\n\t\tconst { mapper, viewPosition } = data;\n\n\t\tconst viewParent = mapper.findMappedViewAncestor( viewPosition );\n\n\t\tif ( !viewElementMatcher( viewParent ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelParent = mapper.toModelElement( viewParent );\n\n\t\tdata.modelPosition = model.createPositionAt( modelParent, viewPosition.isAtStart ? 'before' : 'after' );\n\t};\n}\n\n// Default filler offset function applied to all widget elements.\n//\n// @returns {null}\nfunction getFillerOffset() {\n\treturn null;\n}\n\n// Adds a drag handle to the widget.\n//\n// @param {module:engine/view/containerelement~ContainerElement}\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction addSelectionHandle( widgetElement, writer ) {\n\tconst selectionHandle = writer.createUIElement( 'div', { class: 'ck ck-widget__selection-handle' }, function( domDocument ) {\n\t\tconst domElement = this.toDomElement( domDocument );\n\n\t\t// Use the IconView from the ui library.\n\t\tconst icon = new IconView();\n\t\ticon.set( 'content', dragHandleIcon );\n\n\t\t// Render the icon view right away to append its #element to the selectionHandle DOM element.\n\t\ticon.render();\n\n\t\tdomElement.appendChild( icon.element );\n\n\t\treturn domElement;\n\t} );\n\n\t// Append the selection handle into the widget wrapper.\n\twriter.insert( writer.createPositionAt( widgetElement, 0 ), selectionHandle );\n\twriter.addClass( [ 'ck-widget_with-selection-handle' ], widgetElement );\n}\n","export default \"<svg viewBox=\\\"0 0 16 16\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M4 0v1H1v3H0V.5A.5.5 0 01.5 0H4zm8 0h3.5a.5.5 0 01.5.5V4h-1V1h-3V0zM4 16H.5a.5.5 0 01-.5-.5V12h1v3h3v1zm8 0v-1h3v-3h1v3.5a.5.5 0 01-.5.5H12z\\\"/><path fill-opacity=\\\".256\\\" d=\\\"M1 1h14v14H1z\\\"/><g class=\\\"ck-icon__selected-indicator\\\"><path d=\\\"M7 0h2v1H7V0zM0 7h1v2H0V7zm15 0h1v2h-1V7zm-8 8h2v1H7v-1z\\\"/><path fill-opacity=\\\".254\\\" d=\\\"M1 1h14v14H1z\\\"/></g></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 image/image/utils\n */\n\nimport { findOptimalInsertionPosition, isWidget, toWidget } from '@ckeditor/ckeditor5-widget/src/utils';\n\n/**\n * Converts a given {@link module:engine/view/element~Element} to an image widget:\n * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the image widget element.\n * * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.\n * @param {String} label The element's label. It will be concatenated with the image `alt` attribute if one is present.\n * @returns {module:engine/view/element~Element}\n */\nexport function toImageWidget( viewElement, writer, label ) {\n\twriter.setCustomProperty( 'image', true, viewElement );\n\n\treturn toWidget( viewElement, writer, { label: labelCreator } );\n\n\tfunction labelCreator() {\n\t\tconst imgElement = viewElement.getChild( 0 );\n\t\tconst altText = imgElement.getAttribute( 'alt' );\n\n\t\treturn altText ? `${ altText } ${ label }` : label;\n\t}\n}\n\n/**\n * Checks if a given view element is an image widget.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @returns {Boolean}\n */\nexport function isImageWidget( viewElement ) {\n\treturn !!viewElement.getCustomProperty( 'image' ) && isWidget( viewElement );\n}\n\n/**\n * Returns an image widget editing view element if one is selected.\n *\n * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection\n * @returns {module:engine/view/element~Element|null}\n */\nexport function getSelectedImageWidget( selection ) {\n\tconst viewElement = selection.getSelectedElement();\n\n\tif ( viewElement && isImageWidget( viewElement ) ) {\n\t\treturn viewElement;\n\t}\n\n\treturn null;\n}\n\n/**\n * Checks if the provided model element is an `image`.\n *\n * @param {module:engine/model/element~Element} modelElement\n * @returns {Boolean}\n */\nexport function isImage( modelElement ) {\n\treturn !!modelElement && modelElement.is( 'image' );\n}\n\n/**\n * Handles inserting single file. This method unifies image insertion using {@link module:widget/utils~findOptimalInsertionPosition} method.\n *\n *\t\tmodel.change( writer => {\n *\t\t\tinsertImage( writer, model, { src: 'path/to/image.jpg' } );\n *\t\t} );\n *\n * @param {module:engine/model/writer~Writer} writer\n * @param {module:engine/model/model~Model} model\n * @param {Object} [attributes={}] Attributes of inserted image\n */\nexport function insertImage( writer, model, attributes = {} ) {\n\tconst imageElement = writer.createElement( 'image', attributes );\n\n\tconst insertAtSelection = findOptimalInsertionPosition( model.document.selection, model );\n\n\tmodel.insertContent( imageElement, insertAtSelection );\n\n\t// Inserting an image might've failed due to schema regulations.\n\tif ( imageElement.parent ) {\n\t\twriter.setSelection( imageElement, 'on' );\n\t}\n}\n\n/**\n * Checks if image can be inserted at current model selection.\n *\n * @param {module:engine/model/model~Model} model\n * @returns {Boolean}\n */\nexport function isImageAllowed( model ) {\n\tconst schema = model.schema;\n\tconst selection = model.document.selection;\n\n\treturn isImageAllowedInParent( selection, schema, model ) &&\n\t\t!checkSelectionOnObject( selection, schema ) &&\n\t\tisInOtherImage( selection );\n}\n\n// Checks if image is allowed by schema in optimal insertion parent.\n//\n// @returns {Boolean}\nfunction isImageAllowedInParent( selection, schema, model ) {\n\tconst parent = getInsertImageParent( selection, model );\n\n\treturn schema.checkChild( parent, 'image' );\n}\n\n// Check if selection is on object.\n//\n// @returns {Boolean}\nfunction checkSelectionOnObject( selection, schema ) {\n\tconst selectedElement = selection.getSelectedElement();\n\n\treturn selectedElement && schema.isObject( selectedElement );\n}\n\n// Checks if selection is placed in other image (ie. in caption).\nfunction isInOtherImage( selection ) {\n\treturn [ ...selection.focus.getAncestors() ].every( ancestor => !ancestor.is( 'image' ) );\n}\n\n// Returns a node that will be used to insert image with `model.insertContent` to check if image can be placed there.\nfunction getInsertImageParent( selection, model ) {\n\tconst insertAt = findOptimalInsertionPosition( selection, model );\n\n\tconst parent = insertAt.parent;\n\n\tif ( parent.isEmpty && !parent.is( '$root' ) ) {\n\t\treturn parent.parent;\n\t}\n\n\treturn parent;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { insertImage, isImageAllowed } from './utils';\n\n/**\n * @module image/image/imageinsertcommand\n */\n\n/**\n * Insert image command.\n *\n * The command is registered by the {@link module:image/image/imageediting~ImageEditing} plugin as `'imageInsert'`.\n *\n * In order to insert an image at the current selection position\n * (according to the {@link module:widget/utils~findOptimalInsertionPosition} algorithm),\n * execute the command and specify the image source:\n *\n *\t\teditor.execute( 'imageInsert', { source: 'http://url.to.the/image' } );\n *\n * It is also possible to insert multiple images at once:\n *\n *\t\teditor.execute( 'imageInsert', {\n *\t\t\tsource: [\n *\t\t\t\t'path/to/image.jpg',\n *\t\t\t\t'path/to/other-image.jpg'\n *\t\t\t]\n *\t\t} );\n *\n * @extends module:core/command~Command\n */\nexport default class ImageInsertCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = isImageAllowed( this.editor.model );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t * @param {Object} options Options for the executed command.\n\t * @param {String|Array.<String>} options.source The image source or an array of image sources to insert.\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\n\t\tmodel.change( writer => {\n\t\t\tconst sources = Array.isArray( options.source ) ? options.source : [ options.source ];\n\n\t\t\tfor ( const src of sources ) {\n\t\t\t\tinsertImage( writer, model, { src } );\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module image/image/imageediting\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageLoadObserver from './imageloadobserver';\nimport {\n viewFigureToModel,\n modelToViewAttributeConverter,\n srcsetAttributeConverter\n} from './converters';\nimport { toImageWidget } from './utils';\nimport ImageInsertCommand from './imageinsertcommand';\n/**\n * The image engine plugin.\n *\n * It registers:\n *\n * * `<image>` as a block element in the document schema, and allows `alt`, `src` and `srcset` attributes.\n * * converters for editing and data pipelines.\n * * `'imageInsert'` command.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageEditing extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'ImageEditing';\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const schema = editor.model.schema;\n const t = editor.t;\n const conversion = editor.conversion;\n // See https://github.com/ckeditor/ckeditor5-image/issues/142.\n editor.editing.view.addObserver(ImageLoadObserver);\n // Configure schema.\n schema.register('image', {\n isObject: true,\n isBlock: true,\n allowWhere: '$block',\n allowAttributes: [\n 'alt',\n 'src',\n 'srcset'\n ]\n });\n conversion.for('dataDowncast').elementToElement({\n model: 'image',\n view: (modelElement, viewWriter) => createImageViewElement(viewWriter)\n });\n conversion.for('editingDowncast').elementToElement({\n model: 'image',\n view: (modelElement, viewWriter) => toImageWidget(createImageViewElement(viewWriter), viewWriter, t('s'))\n });\n conversion.for('downcast').add(modelToViewAttributeConverter('src')).add(modelToViewAttributeConverter('alt')).add(srcsetAttributeConverter());\n conversion.for('upcast').elementToElement({\n view: {\n name: 'img',\n attributes: { src: true }\n },\n model: (viewImage, modelWriter) => modelWriter.createElement('image', { src: viewImage.getAttribute('src') })\n }).attributeToAttribute({\n view: {\n name: 'img',\n key: 'alt'\n },\n model: 'alt'\n }).attributeToAttribute({\n view: {\n name: 'img',\n key: 'srcset'\n },\n model: {\n key: 'srcset',\n value: viewImage => {\n const value = { data: viewImage.getAttribute('srcset') };\n if (viewImage.hasAttribute('width')) {\n value.width = viewImage.getAttribute('width');\n }\n return value;\n }\n }\n }).add(viewFigureToModel());\n // Register imageUpload command.\n editor.commands.add('imageInsert', new ImageInsertCommand(editor));\n }\n}\n// Creates a view element representing the image.\n//\n//\t\t<figure class=\"image\"><img></img></figure>\n//\n// Note that `alt` and `src` attributes are converted separately, so they are not included.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {module:engine/view/containerelement~ContainerElement}\nexport function createImageViewElement(writer) {\n const emptyElement = writer.createEmptyElement('img');\n const figure = writer.createContainerElement('figure', { class: 'image' });\n writer.insert(writer.createPositionAt(figure, 0), emptyElement);\n return figure;\n}","/**\n * @license Copyright (c) 2003-2020, 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 link/findlinkrange\n */\n\n/**\n * Returns a range containing the entire link in which the given `position` is placed.\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} value The `linkHref` attribute value.\n * @returns {module:engine/model/range~Range} The link range.\n */\nexport default function findLinkRange( position, value, model ) {\n\treturn model.createRange( _findBound( position, value, true, model ), _findBound( position, value, false, model ) );\n}\n\n// Walks forward or backward (depends on the `lookBack` flag), node by node, as long as they have the same `linkHref` 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} value The `linkHref` 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, 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( 'linkHref' ) == 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-2020, 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 link/linkcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport findLinkRange from './findlinkrange';\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\n\n/**\n * The link command. It is used by the {@link module:link/link~Link link feature}.\n *\n * @extends module:core/command~Command\n */\nexport default class LinkCommand extends Command {\n\t/**\n\t * The value of the `'linkHref'` attribute if the start of the selection is located in a node with this attribute.\n\t *\n\t * @observable\n\t * @readonly\n\t * @member {Object|undefined} #value\n\t */\n\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A collection of {@link module:link/utils~ManualDecorator manual decorators}\n\t\t * corresponding to the {@link module:link/link~LinkConfig#decorators decorator configuration}.\n\t\t *\n\t\t * You can consider it a model with states of manual decorators added to the currently selected link.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/collection~Collection}\n\t\t */\n\t\tthis.manualDecorators = new Collection();\n\t}\n\n\t/**\n\t * Synchronizes the state of {@link #manualDecorators} with the currently present elements in the model.\n\t */\n\trestoreManualDecoratorStates() {\n\t\tfor ( const manualDecorator of this.manualDecorators ) {\n\t\t\tmanualDecorator.value = this._getDecoratorStateFromModel( manualDecorator.id );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tthis.value = doc.selection.getAttribute( 'linkHref' );\n\n\t\tfor ( const manualDecorator of this.manualDecorators ) {\n\t\t\tmanualDecorator.value = this._getDecoratorStateFromModel( manualDecorator.id );\n\t\t}\n\n\t\tthis.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'linkHref' );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * When the selection is non-collapsed, the `linkHref` attribute will be applied to nodes inside the selection, but only to\n\t * those nodes where the `linkHref` attribute is allowed (disallowed nodes will be omitted).\n\t *\n\t * When the selection is collapsed and is not inside the text with the `linkHref` attribute, a\n\t * new {@link module:engine/model/text~Text text node} with the `linkHref` attribute will be inserted in place of the caret, but\n\t * only if such element is allowed in this place. The `_data` of the inserted text will equal the `href` parameter.\n\t * The selection will be updated to wrap the just inserted text node.\n\t *\n\t * When the selection is collapsed and inside the text with the `linkHref` attribute, the attribute value will be updated.\n\t *\n\t * # Decorators and model attribute management\n\t *\n\t * There is an optional argument to this command that applies or removes model\n\t * {@glink framework/guides/architecture/editing-engine#text-attributes text attributes} brought by\n\t * {@link module:link/utils~ManualDecorator manual link decorators}.\n\t *\n\t * Text attribute names in the model correspond to the entries in the {@link module:link/link~LinkConfig#decorators configuration}.\n\t * For every decorator configured, a model text attribute exists with the \"link\" prefix. For example, a `'linkMyDecorator'` attribute\n\t * corresponds to `'myDecorator'` in the configuration.\n\t *\n\t * To learn more about link decorators, check out the {@link module:link/link~LinkConfig#decorators `config.link.decorators`}\n\t * documentation.\n\t *\n\t * Here is how to manage decorator attributes with the link command:\n\t *\n\t *\t\tconst linkCommand = editor.commands.get( 'link' );\n\t *\n\t *\t\t// Adding a new decorator attribute.\n\t *\t\tlinkCommand.execute( 'http://example.com', {\n\t *\t\t\tlinkIsExternal: true\n\t *\t\t} );\n\t *\n\t *\t\t// Removing a decorator attribute from the selection.\n\t *\t\tlinkCommand.execute( 'http://example.com', {\n\t *\t\t\tlinkIsExternal: false\n\t *\t\t} );\n\t *\n\t *\t\t// Adding multiple decorator attributes at the same time.\n\t *\t\tlinkCommand.execute( 'http://example.com', {\n\t *\t\t\tlinkIsExternal: true,\n\t *\t\t\tlinkIsDownloadable: true,\n\t *\t\t} );\n\t *\n\t *\t\t// Removing and adding decorator attributes at the same time.\n\t *\t\tlinkCommand.execute( 'http://example.com', {\n\t *\t\t\tlinkIsExternal: false,\n\t *\t\t\tlinkFoo: true,\n\t *\t\t\tlinkIsDownloadable: false,\n\t *\t\t} );\n\t *\n\t * **Note**: If the decorator attribute name is not specified, its state remains untouched.\n\t *\n\t * **Note**: {@link module:link/unlinkcommand~UnlinkCommand#execute `UnlinkCommand#execute()`} removes all\n\t * decorator attributes.\n\t *\n\t * @fires execute\n\t * @param {String} href Link destination.\n\t * @param {Object} [manualDecoratorIds={}] The information about manual decorator attributes to be applied or removed upon execution.\n\t */\n\texecute( href, manualDecoratorIds = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\t// Stores information about manual decorators to turn them on/off when command is applied.\n\t\tconst truthyManualDecorators = [];\n\t\tconst falsyManualDecorators = [];\n\n\t\tfor ( const name in manualDecoratorIds ) {\n\t\t\tif ( manualDecoratorIds[ name ] ) {\n\t\t\t\ttruthyManualDecorators.push( name );\n\t\t\t} else {\n\t\t\t\tfalsyManualDecorators.push( name );\n\t\t\t}\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\t// If selection is collapsed then update selected link or insert new one at the place of caret.\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\tconst position = selection.getFirstPosition();\n\n\t\t\t\t// When selection is inside text with `linkHref` attribute.\n\t\t\t\tif ( selection.hasAttribute( 'linkHref' ) ) {\n\t\t\t\t\t// Then update `linkHref` value.\n\t\t\t\t\tconst linkRange = findLinkRange( position, selection.getAttribute( 'linkHref' ), model );\n\n\t\t\t\t\twriter.setAttribute( 'linkHref', href, linkRange );\n\n\t\t\t\t\ttruthyManualDecorators.forEach( item => {\n\t\t\t\t\t\twriter.setAttribute( item, true, linkRange );\n\t\t\t\t\t} );\n\n\t\t\t\t\tfalsyManualDecorators.forEach( item => {\n\t\t\t\t\t\twriter.removeAttribute( item, linkRange );\n\t\t\t\t\t} );\n\n\t\t\t\t\t// Create new range wrapping changed link.\n\t\t\t\t\twriter.setSelection( linkRange );\n\t\t\t\t}\n\t\t\t\t// If not then insert text node with `linkHref` attribute in place of caret.\n\t\t\t\t// However, since selection in collapsed, attribute value will be used as data for text node.\n\t\t\t\t// So, if `href` is empty, do not create text node.\n\t\t\t\telse if ( href !== '' ) {\n\t\t\t\t\tconst attributes = toMap( selection.getAttributes() );\n\n\t\t\t\t\tattributes.set( 'linkHref', href );\n\n\t\t\t\t\ttruthyManualDecorators.forEach( item => {\n\t\t\t\t\t\tattributes.set( item, true );\n\t\t\t\t\t} );\n\n\t\t\t\t\tconst node = writer.createText( href, attributes );\n\n\t\t\t\t\tmodel.insertContent( node, position );\n\n\t\t\t\t\t// Create new range wrapping created node.\n\t\t\t\t\twriter.setSelection( writer.createRangeOn( node ) );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// If selection has non-collapsed ranges, we change attribute on nodes inside those ranges\n\t\t\t\t// omitting nodes where `linkHref` attribute is disallowed.\n\t\t\t\tconst ranges = model.schema.getValidRanges( selection.getRanges(), 'linkHref' );\n\n\t\t\t\tfor ( const range of ranges ) {\n\t\t\t\t\twriter.setAttribute( 'linkHref', href, range );\n\n\t\t\t\t\ttruthyManualDecorators.forEach( item => {\n\t\t\t\t\t\twriter.setAttribute( item, true, range );\n\t\t\t\t\t} );\n\n\t\t\t\t\tfalsyManualDecorators.forEach( item => {\n\t\t\t\t\t\twriter.removeAttribute( item, range );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Provides information whether a decorator with a given name is present in the currently processed selection.\n\t *\n\t * @private\n\t * @param {String} decoratorName The name of the manual decorator used in the model\n\t * @returns {Boolean} The information whether a given decorator is currently present in the selection.\n\t */\n\t_getDecoratorStateFromModel( decoratorName ) {\n\t\tconst doc = this.editor.model.document;\n\t\treturn doc.selection.getAttribute( decoratorName ) || false;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 link/unlinkcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport findLinkRange from './findlinkrange';\n\n/**\n * The unlink command. It is used by the {@link module:link/link~Link link plugin}.\n *\n * @extends module:core/command~Command\n */\nexport default class UnlinkCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = this.editor.model.document.selection.hasAttribute( 'linkHref' );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * When the selection is collapsed, it removes the `linkHref` attribute from each node with the same `linkHref` attribute value.\n\t * When the selection is non-collapsed, it removes the `linkHref` attribute from each node in selected ranges.\n\t *\n\t * # Decorators\n\t *\n\t * If {@link module:link/link~LinkConfig#decorators `config.link.decorators`} is specified,\n\t * all configured decorators are removed together with the `linkHref` attribute.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst editor = this.editor;\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\n\t\tmodel.change( writer => {\n\t\t\t// Get ranges to unlink.\n\t\t\tconst rangesToUnlink = selection.isCollapsed ?\n\t\t\t\t[ findLinkRange( selection.getFirstPosition(), selection.getAttribute( 'linkHref' ), model ) ] : selection.getRanges();\n\n\t\t\t// Remove `linkHref` attribute from specified ranges.\n\t\t\tfor ( const range of rangesToUnlink ) {\n\t\t\t\twriter.removeAttribute( 'linkHref', range );\n\t\t\t\t// If there are registered custom attributes, then remove them during unlink.\n\t\t\t\tif ( linkCommand ) {\n\t\t\t\t\tfor ( const manualDecorator of linkCommand.manualDecorators ) {\n\t\t\t\t\t\twriter.removeAttribute( manualDecorator.id, range );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n","import baseSlice from './_baseSlice.js';\n\n/**\n * Casts `array` to a slice if it's needed.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {number} start The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the cast slice.\n */\nfunction castSlice(array, start, end) {\n var length = array.length;\n end = end === undefined ? length : end;\n return (!start && end >= length) ? array : baseSlice(array, start, end);\n}\n\nexport default castSlice;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\nexport default hasUnicode;\n","/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\nexport default asciiToArray;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\nexport default unicodeToArray;\n","import asciiToArray from './_asciiToArray.js';\nimport hasUnicode from './_hasUnicode.js';\nimport unicodeToArray from './_unicodeToArray.js';\n\n/**\n * Converts `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction stringToArray(string) {\n return hasUnicode(string)\n ? unicodeToArray(string)\n : asciiToArray(string);\n}\n\nexport default stringToArray;\n","import castSlice from './_castSlice.js';\nimport hasUnicode from './_hasUnicode.js';\nimport stringToArray from './_stringToArray.js';\nimport toString from './toString.js';\n\n/**\n * Creates a function like `_.lowerFirst`.\n *\n * @private\n * @param {string} methodName The name of the `String` case method to use.\n * @returns {Function} Returns the new case function.\n */\nfunction createCaseFirst(methodName) {\n return function(string) {\n string = toString(string);\n\n var strSymbols = hasUnicode(string)\n ? stringToArray(string)\n : undefined;\n\n var chr = strSymbols\n ? strSymbols[0]\n : string.charAt(0);\n\n var trailing = strSymbols\n ? castSlice(strSymbols, 1).join('')\n : string.slice(1);\n\n return chr[methodName]() + trailing;\n };\n}\n\nexport default createCaseFirst;\n","import createCaseFirst from './_createCaseFirst.js';\n\n/**\n * Converts the first character of `string` to upper case.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.upperFirst('fred');\n * // => 'Fred'\n *\n * _.upperFirst('FRED');\n * // => 'FRED'\n */\nvar upperFirst = createCaseFirst('toUpperCase');\n\nexport default upperFirst;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module link/utils\n */\nimport { upperFirst } from 'lodash-es';\nconst ATTRIBUTE_WHITESPACES = /[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205f\\u3000]/g;\n// eslint-disable-line no-control-regex\nconst SAFE_URL = /^(?:(?:https?|ftps?|mailto):|[^a-z]|[a-z+.-]+(?:[^a-z+.:-]|$))/i;\n/**\n * Returns `true` if a given view node is the link element.\n *\n * @param {module:engine/view/node~Node} node\n * @returns {Boolean}\n */\nexport function isLinkElement(node) {\n return node.is('attributeElement') && !!node.getCustomProperty('link');\n}\n/**\n * Creates link {@link module:engine/view/attributeelement~AttributeElement} with the provided `href` attribute.\n *\n * @param {String} href\n * @returns {module:engine/view/attributeelement~AttributeElement}\n */\nexport function createLinkElement(href, writer) {\n // Priority 5 - https://github.com/ckeditor/ckeditor5-link/issues/121.\n const linkElement = writer.createAttributeElement('a', { href }, { priority: 5 });\n writer.setCustomProperty('link', true, linkElement);\n return linkElement;\n}\n/**\n * Returns a safe URL based on a given value.\n *\n * A URL is considered safe if it is safe for the user (does not contain any malicious code).\n *\n * If a URL is considered unsafe, a simple `\"#\"` is returned.\n *\n * @protected\n * @param {*} url\n * @returns {String} Safe URL.\n */\nexport function ensureSafeUrl(url) {\n url = String(url);\n return isSafeUrl(url) ? url : '#';\n}\n// Checks whether the given URL is safe for the user (does not contain any malicious code).\n//\n// @param {String} url URL to check.\nfunction isSafeUrl(url) {\n const normalizedUrl = url.replace(ATTRIBUTE_WHITESPACES, '');\n return normalizedUrl.match(SAFE_URL);\n}\n/**\n * Returns the {@link module:link/link~LinkConfig#decorators `config.link.decorators`} configuration processed\n * to respect the locale of the editor, i.e. to display the {@link module:link/link~LinkDecoratorManualDefinition label}\n * in the correct language.\n *\n * **Note**: Only the few most commonly used labels are translated automatically. Other labels should be manually\n * translated in the {@link module:link/link~LinkConfig#decorators `config.link.decorators`} configuration.\n *\n * @param {module:utils/locale~Locale#t} t shorthand for {@link module:utils/locale~Locale#t Locale#t}\n * @param {Array.<module:link/link~LinkDecoratorDefinition>} The decorator reference\n * where the label values should be localized.\n * @returns {Array.<module:link/link~LinkDecoratorDefinition>}\n */\nexport function getLocalizedDecorators(t, decorators) {\n const localizedDecoratorsLabels = {\n 'Open in a new tab': t('dg'),\n 'Downloadable': t('dh')\n };\n decorators.forEach(decorator => {\n if (decorator.label && localizedDecoratorsLabels[decorator.label]) {\n decorator.label = localizedDecoratorsLabels[decorator.label];\n }\n return decorator;\n });\n return decorators;\n}\n/**\n * Converts an object with defined decorators to a normalized array of decorators. The `id` key is added for each decorator and\n * is used as the attribute's name in the model.\n *\n * @param {Object.<String, module:link/link~LinkDecoratorDefinition>} decorators\n * @returns {Array.<module:link/link~LinkDecoratorDefinition>}\n */\nexport function normalizeDecorators(decorators) {\n const retArray = [];\n if (decorators) {\n for (const [key, value] of Object.entries(decorators)) {\n const decorator = Object.assign({}, value, { id: `link${ upperFirst(key) }` });\n retArray.push(decorator);\n }\n }\n return retArray;\n}","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module link/utils\n */\n\n/**\n * Helper class that ties together all {@link module:link/link~LinkDecoratorAutomaticDefinition} and provides\n * a {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement downcast dispatcher} for them.\n */\nexport default class AutomaticDecorators {\n\tconstructor() {\n\t\t/**\n\t\t * Stores the definition of {@link module:link/link~LinkDecoratorAutomaticDefinition automatic decorators}.\n\t\t * This data is used as a source for a downcast dispatcher to create a proper conversion to output data.\n\t\t *\n\t\t * @private\n\t\t * @type {Set}\n\t\t */\n\t\tthis._definitions = new Set();\n\t}\n\n\t/**\n\t * Gives information about the number of decorators stored in the {@link module:link/utils~AutomaticDecorators} instance.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Number}\n\t */\n\tget length() {\n\t\treturn this._definitions.size;\n\t}\n\n\t/**\n\t * Adds automatic decorator objects or an array with them to be used during downcasting.\n\t *\n\t * @param {module:link/link~LinkDecoratorAutomaticDefinition|Array.<module:link/link~LinkDecoratorAutomaticDefinition>} item\n\t * A configuration object of automatic rules for decorating links. It might also be an array of such objects.\n\t */\n\tadd( item ) {\n\t\tif ( Array.isArray( item ) ) {\n\t\t\titem.forEach( item => this._definitions.add( item ) );\n\t\t} else {\n\t\t\tthis._definitions.add( item );\n\t\t}\n\t}\n\n\t/**\n\t * Provides the conversion helper used in the {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add} method.\n\t *\n\t * @returns {Function} A dispatcher function used as conversion helper\n\t * in {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add}.\n\t */\n\tgetDispatcher() {\n\t\treturn dispatcher => {\n\t\t\tdispatcher.on( 'attribute:linkHref', ( evt, data, conversionApi ) => {\n\t\t\t\t// There is only test as this behavior decorates links and\n\t\t\t\t// it is run before dispatcher which actually consumes this node.\n\t\t\t\t// This allows on writing own dispatcher with highest priority,\n\t\t\t\t// which blocks both native converter and this additional decoration.\n\t\t\t\tif ( !conversionApi.consumable.test( data.item, 'attribute:linkHref' ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst viewWriter = conversionApi.writer;\n\t\t\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\t\t\tfor ( const item of this._definitions ) {\n\t\t\t\t\tconst viewElement = viewWriter.createAttributeElement( 'a', item.attributes, {\n\t\t\t\t\t\tpriority: 5\n\t\t\t\t\t} );\n\t\t\t\t\tviewWriter.setCustomProperty( 'link', true, viewElement );\n\t\t\t\t\tif ( item.callback( data.attributeNewValue ) ) {\n\t\t\t\t\t\tif ( data.item.is( 'selection' ) ) {\n\t\t\t\t\t\t\tviewWriter.wrap( viewSelection.getFirstRange(), viewElement );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tviewWriter.wrap( conversionApi.mapper.toViewRange( data.range ), viewElement );\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tviewWriter.unwrap( conversionApi.mapper.toViewRange( data.range ), viewElement );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, { priority: 'high' } );\n\t\t};\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 link/utils\n */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Helper class that stores manual decorators with observable {@link module:link/utils~ManualDecorator#value}\n * to support integration with the UI state. An instance of this class is a model with the state of individual manual decorators.\n * These decorators are kept as collections in {@link module:link/linkcommand~LinkCommand#manualDecorators}.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class ManualDecorator {\n\t/**\n\t * Creates a new instance of {@link module:link/utils~ManualDecorator}.\n\t *\n\t * @param {Object} config\n\t * @param {String} config.id The name of the attribute used in the model that represents a given manual decorator.\n\t * For example: `'linkIsExternal'`.\n\t * @param {String} config.label The label used in the user interface to toggle the manual decorator.\n\t * @param {Object} config.attributes A set of attributes added to output data when the decorator is active for a specific link.\n\t * Attributes should keep the format of attributes defined in {@link module:engine/view/elementdefinition~ElementDefinition}.\n\t */\n\tconstructor( { id, label, attributes } ) {\n\t\t/**\n\t\t * An ID of a manual decorator which is the name of the attribute in the model, for example: 'linkManualDecorator0'.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.id = id;\n\n\t\t/**\n\t\t * The value of the current manual decorator. It reflects its state from the UI.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} module:link/utils~ManualDecorator#value\n\t\t */\n\t\tthis.set( 'value' );\n\n\t\t/**\n\t\t * The label used in the user interface to toggle the manual decorator.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.label = label;\n\n\t\t/**\n\t\t * A set of attributes added to downcasted data when the decorator is activated for a specific link.\n\t\t * Attributes should be added in a form of attributes defined in {@link module:engine/view/elementdefinition~ElementDefinition}.\n\t\t *\n\t\t * @type {Object}\n\t\t */\n\t\tthis.attributes = attributes;\n\t}\n}\n\nmix( ManualDecorator, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/utils/bindtwostepcarettoattribute\n */\n\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport priorities from '@ckeditor/ckeditor5-utils/src/priorities';\n\n/**\n * This helper enables the two-step caret (phantom) movement behavior for the given {@link module:engine/model/model~Model}\n * attribute on arrow right (<kbd>→</kbd>) and left (<kbd>←</kbd>) 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 helper 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 behavior is enabled 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</$text>\n *\n * <kbd>→</kbd>\n *\n * \t\tfoo<$text a=\"true\">{}bar</$text>\n *\n * * When disabled:\n *\n * \t\tfoo{}<$text a=\"true\">bar</$text>\n *\n * <kbd>→</kbd>\n *\n * \t\tfoo<$text a=\"true\">b{}ar</$text>\n *\n *\n * ## \"Leaving\" an attribute:\n *\n * * When enabled:\n *\n * \t\t<$text a=\"true\">bar{}</$text>baz\n *\n * <kbd>→</kbd>\n *\n * \t\t<$text a=\"true\">bar</$text>{}baz\n *\n * * When disabled:\n *\n * \t\t<$text a=\"true\">bar{}</$text>baz\n *\n * <kbd>→</kbd>\n *\n * \t\t<$text a=\"true\">bar</$text>b{}az\n *\n * # Backward movement\n *\n * * When enabled:\n *\n * \t\t<$text a=\"true\">bar</$text>{}baz\n *\n * <kbd>←</kbd>\n *\n * \t\t<$text a=\"true\">bar{}</$text>baz\n *\n * * When disabled:\n *\n * \t\t<$text a=\"true\">bar</$text>{}baz\n *\n * <kbd>←</kbd>\n *\n * \t\t<$text a=\"true\">ba{}r</$text>b{}az\n *\n * @param {Object} options Helper options.\n * @param {module:engine/view/view~View} options.view View controller instance.\n * @param {module:engine/model/model~Model} options.model Data model instance.\n * @param {module:utils/dom/emittermixin~Emitter} options.emitter The emitter to which this behavior should be added\n * (e.g. a plugin instance).\n * @param {String} options.attribute Attribute for which this behavior will be added.\n * @param {module:utils/locale~Locale} options.locale The {@link module:core/editor/editor~Editor#locale} instance.\n */\nexport default function bindTwoStepCaretToAttribute( { view, model, emitter, attribute, locale } ) {\n\tconst twoStepCaretHandler = new TwoStepCaretHandler( model, emitter, attribute );\n\tconst modelSelection = model.document.selection;\n\n\t// Listen to keyboard events and handle the caret movement according to the 2-step caret logic.\n\t//\n\t// Note: This listener has the \"high+1\" priority:\n\t// * \"high\" because of the filler logic implemented in the renderer which also engages on #keydown.\n\t// When the gravity is overridden the attributes of the (model) selection attributes are reset.\n\t// It may end up with the filler kicking in and breaking the selection.\n\t// * \"+1\" because we would like to avoid collisions with other features (like Widgets), which\n\t// take over the keydown events with the \"high\" priority. Two-step caret movement takes precedence\n\t// over Widgets in that matter.\n\t//\n\t// Find out more in https://github.com/ckeditor/ckeditor5-engine/issues/1301.\n\temitter.listenTo( view.document, 'keydown', ( evt, data ) => {\n\t\t// This implementation works only for collapsed selection.\n\t\tif ( !modelSelection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// When user tries to expand the selection or jump over the whole word or to the beginning/end then\n\t\t// two-steps movement is not necessary.\n\t\tif ( data.shiftKey || data.altKey || data.ctrlKey ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst arrowRightPressed = data.keyCode == keyCodes.arrowright;\n\t\tconst arrowLeftPressed = data.keyCode == keyCodes.arrowleft;\n\n\t\t// When neither left or right arrow has been pressed then do noting.\n\t\tif ( !arrowRightPressed && !arrowLeftPressed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst position = modelSelection.getFirstPosition();\n\t\tconst contentDirection = locale.contentLanguageDirection;\n\t\tlet isMovementHandled;\n\n\t\tif ( ( contentDirection === 'ltr' && arrowRightPressed ) || ( contentDirection === 'rtl' && arrowLeftPressed ) ) {\n\t\t\tisMovementHandled = twoStepCaretHandler.handleForwardMovement( position, data );\n\t\t} else {\n\t\t\tisMovementHandled = twoStepCaretHandler.handleBackwardMovement( position, data );\n\t\t}\n\n\t\t// Stop the keydown event if the two-step caret movement handled it. Avoid collisions\n\t\t// with other features which may also take over the caret movement (e.g. Widget).\n\t\tif ( isMovementHandled ) {\n\t\t\tevt.stop();\n\t\t}\n\t}, { priority: priorities.get( 'high' ) + 1 } );\n}\n\n/**\n * This is a protected helper–class for {@link module:engine/utils/bindtwostepcarettoattribute}.\n * It handles the state of the 2-step caret movement for a single {@link module:engine/model/model~Model}\n * attribute upon the `keypress` in the {@link module:engine/view/view~View}.\n *\n * @protected\n */\nexport class TwoStepCaretHandler {\n\t/*\n\t * Creates two step handler instance.\n\t *\n\t * @param {module:engine/model/model~Model} model Data model instance.\n\t * @param {module:utils/dom/emittermixin~Emitter} emitter The emitter to which this behavior should be added\n\t * (e.g. a plugin instance).\n\t * @param {String} attribute Attribute for which the behavior will be added.\n\t */\n\tconstructor( model, emitter, attribute ) {\n\t\t/**\n\t\t * The model instance this class instance operates on.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model#schema}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * The Attribute this class instance operates on.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.attribute = attribute;\n\n\t\t/**\n\t\t * A reference to the document selection.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/selection~Selection}\n\t\t */\n\t\tthis._modelSelection = model.document.selection;\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\n\t\t/**\n\t\t * A flag indicating that the automatic gravity restoration for this attribute\n\t\t * should not happen upon the next\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\temitter.listenTo( this._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 && isAtBoundary( this._modelSelection.getFirstPosition(), attribute ) ) {\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 * 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 * @param {module:engine/model/position~Position} position The model position at the moment of the key press.\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\thandleForwardMovement( position, data ) {\n\t\tconst attribute = this.attribute;\n\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\t<paragraph>foo<$text attribute>{}bar</$text>baz</paragraph>\n\t\t//\n\t\t// or left the attribute\n\t\t//\n\t\t// \t\t<paragraph>foo<$text attribute>bar</$text>{}baz</paragraph>\n\t\t//\n\t\t// and the gravity will be restored automatically.\n\t\tif ( this._isGravityOverridden ) {\n\t\t\treturn;\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<paragraph><$text attribute>{}bar</$text>baz</paragraph>\n\t\t//\n\t\tif ( position.isAtStart && this._hasSelectionAttribute ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// ENGAGE 2-SCM when about to leave one attribute value and enter another:\n\t\t//\n\t\t// \t\t<paragraph><$text attribute=\"1\">foo{}</$text><$text attribute=\"2\">bar</$text></paragraph>\n\t\t//\n\t\t// but DON'T when already in between of them (no attribute selection):\n\t\t//\n\t\t// \t\t<paragraph><$text attribute=\"1\">foo</$text>{}<$text attribute=\"2\">bar</$text></paragraph>\n\t\t//\n\t\tif ( isBetweenDifferentValues( position, attribute ) && this._hasSelectionAttribute ) {\n\t\t\tthis._preventCaretMovement( data );\n\t\t\tthis._removeSelectionAttribute();\n\n\t\t\treturn true;\n\t\t}\n\n\t\t// ENGAGE 2-SCM when entering an attribute:\n\t\t//\n\t\t// \t\t<paragraph>foo{}<$text attribute>bar</$text>baz</paragraph>\n\t\t//\n\t\tif ( isAtStartBoundary( position, attribute ) ) {\n\t\t\tthis._preventCaretMovement( data );\n\t\t\tthis._overrideGravity();\n\n\t\t\treturn true;\n\t\t}\n\n\t\t// ENGAGE 2-SCM when leaving an attribute:\n\t\t//\n\t\t//\t\t<paragraph>foo<$text attribute>bar{}</$text>baz</paragraph>\n\t\t//\n\t\tif ( isAtEndBoundary( position, attribute ) && this._hasSelectionAttribute ) {\n\t\t\tthis._preventCaretMovement( data );\n\t\t\tthis._overrideGravity();\n\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 * @param {module:engine/model/position~Position} position The model position at the moment of the key press.\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\thandleBackwardMovement( position, data ) {\n\t\tconst attribute = this.attribute;\n\n\t\t// When the gravity is already overridden...\n\t\tif ( this._isGravityOverridden ) {\n\t\t\t// ENGAGE 2-SCM & REMOVE SELECTION ATTRIBUTE\n\t\t\t// when about to leave one attribute value and enter another:\n\t\t\t//\n\t\t\t// \t\t<paragraph><$text attribute=\"1\">foo</$text><$text attribute=\"2\">{}bar</$text></paragraph>\n\t\t\t//\n\t\t\t// but DON'T when already in between of them (no attribute selection):\n\t\t\t//\n\t\t\t// \t\t<paragraph><$text attribute=\"1\">foo</$text>{}<$text attribute=\"2\">bar</$text></paragraph>\n\t\t\t//\n\t\t\tif ( isBetweenDifferentValues( position, attribute ) && this._hasSelectionAttribute ) {\n\t\t\t\tthis._preventCaretMovement( data );\n\t\t\t\tthis._restoreGravity();\n\t\t\t\tthis._removeSelectionAttribute();\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// ENGAGE 2-SCM when at any boundary of the attribute:\n\t\t\t//\n\t\t\t// \t\t<paragraph>foo<$text attribute>bar</$text>{}baz</paragraph>\n\t\t\t// \t\t<paragraph>foo<$text attribute>{}bar</$text>baz</paragraph>\n\t\t\t//\n\t\t\telse {\n\t\t\t\tthis._preventCaretMovement( data );\n\t\t\t\tthis._restoreGravity();\n\n\t\t\t\t// REMOVE SELECTION ATRIBUTE at the beginning of the block.\n\t\t\t\t// It's like restoring gravity but towards a non-existent content when\n\t\t\t\t// the gravity is overridden:\n\t\t\t\t//\n\t\t\t\t// \t\t<paragraph><$text attribute>{}bar</$text></paragraph>\n\t\t\t\t//\n\t\t\t\t// becomes:\n\t\t\t\t//\n\t\t\t\t// \t\t<paragraph>{}<$text attribute>bar</$text></paragraph>\n\t\t\t\t//\n\t\t\t\tif ( position.isAtStart ) {\n\t\t\t\t\tthis._removeSelectionAttribute();\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else {\n\t\t\t// ENGAGE 2-SCM when between two different attribute values but selection has no attribute:\n\t\t\t//\n\t\t\t// \t\t<paragraph><$text attribute=\"1\">foo</$text>{}<$text attribute=\"2\">bar</$text></paragraph>\n\t\t\t//\n\t\t\tif ( isBetweenDifferentValues( position, attribute ) && !this._hasSelectionAttribute ) {\n\t\t\t\tthis._preventCaretMovement( data );\n\t\t\t\tthis._setSelectionAttributeFromTheNodeBefore( position );\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// End of block boundary cases:\n\t\t\t//\n\t\t\t// \t\t<paragraph><$text attribute>bar{}</$text></paragraph>\n\t\t\t// \t\t<paragraph><$text attribute>bar</$text>{}</paragraph>\n\t\t\t//\n\t\t\tif ( position.isAtEnd && isAtEndBoundary( position, attribute ) ) {\n\t\t\t\t// DON'T ENGAGE 2-SCM if the selection has the attribute already.\n\t\t\t\t// This is a common selection if set using the mouse.\n\t\t\t\t//\n\t\t\t\t// \t\t<paragraph><$text attribute>bar{}</$text></paragraph>\n\t\t\t\t//\n\t\t\t\tif ( this._hasSelectionAttribute ) {\n\t\t\t\t\t// DON'T ENGAGE 2-SCM if the attribute at the end of the block which has length == 1.\n\t\t\t\t\t// Make sure the selection will not the attribute after it moves backwards.\n\t\t\t\t\t//\n\t\t\t\t\t// \t\t<paragraph>foo<$text attribute>b{}</$text></paragraph>\n\t\t\t\t\t//\n\t\t\t\t\tif ( isStepAfterTheAttributeBoundary( position, attribute ) ) {\n\t\t\t\t\t\t// Skip the automatic gravity restore upon the next selection#change:range event.\n\t\t\t\t\t\t// If not skipped, it would automatically restore the gravity, which should remain\n\t\t\t\t\t\t// overridden.\n\t\t\t\t\t\tthis._skipNextAutomaticGravityRestoration();\n\t\t\t\t\t\tthis._overrideGravity();\n\n\t\t\t\t\t\t// Don't return \"true\" here because we didn't call _preventCaretMovement.\n\t\t\t\t\t\t// Returning here will destabilize the filler logic, which also listens to\n\t\t\t\t\t\t// keydown (and the event would be stopped).\n\t\t\t\t\t}\n\n\t\t\t\t\treturn;\n\t\t\t\t}\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<paragraph><$text attribute>bar</$text>{}</paragraph>\n\t\t\t\t//\n\t\t\t\telse {\n\t\t\t\t\tthis._preventCaretMovement( data );\n\t\t\t\t\tthis._setSelectionAttributeFromTheNodeBefore( position );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// REMOVE SELECTION ATRIBUTE 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<paragraph>{}<$text attribute>bar</$text></paragraph>\n\t\t\t//\n\t\t\tif ( position.isAtStart ) {\n\t\t\t\tif ( this._hasSelectionAttribute ) {\n\t\t\t\t\tthis._removeSelectionAttribute();\n\t\t\t\t\tthis._preventCaretMovement( data );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// DON'T ENGAGE 2-SCM when about to enter of leave an 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\t<paragraph>foo<$text attribute>b{}ar</$text>baz</paragraph>\n\t\t\t// \t\t<paragraph>foo<$text attribute>bar</$text>b{}az</paragraph>\n\t\t\t//\n\t\t\tif ( isStepAfterTheAttributeBoundary( position, attribute ) ) {\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._skipNextAutomaticGravityRestoration();\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}\n\t\t}\n\t}\n\n\t/**\n\t * `true` when the gravity is overridden for the {@link #attribute}.\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 * `true` when the {@link module:engine/model/selection~Selection} has the {@link #attribute}.\n\t *\n\t * @readonly\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _hasSelectionAttribute() {\n\t\treturn this._modelSelection.hasAttribute( this.attribute );\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.model.change( writer => writer.overrideSelectionGravity() );\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.model.change( writer => {\n\t\t\twriter.restoreSelectionGravity( this._overrideUid );\n\t\t\tthis._overrideUid = null;\n\t\t} );\n\t}\n\n\t/**\n\t * Prevents the caret movement in the view by calling `preventDefault` on the event data.\n\t *\n\t * @private\n\t */\n\t_preventCaretMovement( data ) {\n\t\tdata.preventDefault();\n\t}\n\n\t/**\n\t * Removes the {@link #attribute} from the selection using using the\n\t * {@link module:engine/model/writer~Writer model writer}.\n\t *\n\t * @private\n\t */\n\t_removeSelectionAttribute() {\n\t\tthis.model.change( writer => {\n\t\t\twriter.removeSelectionAttribute( this.attribute );\n\t\t} );\n\t}\n\n\t/**\n\t * Applies the {@link #attribute} to the current selection using using the\n\t * value from the node before the current position. Uses\n\t * the {@link module:engine/model/writer~Writer model writer}.\n\t *\n\t * @private\n\t * @param {module:engine/model/position~Position} position\n\t */\n\t_setSelectionAttributeFromTheNodeBefore( position ) {\n\t\tconst attribute = this.attribute;\n\n\t\tthis.model.change( writer => {\n\t\t\twriter.setSelectionAttribute( this.attribute, position.nodeBefore.getAttribute( attribute ) );\n\t\t} );\n\t}\n\n\t/**\n\t * Skips the next automatic selection gravity restoration upon the\n\t * {@link module:engine/model/selection~Selection#event:change:range} event.\n\t *\n\t * See {@link #_isNextGravityRestorationSkipped}.\n\t *\n\t * @private\n\t */\n\t_skipNextAutomaticGravityRestoration() {\n\t\tthis._isNextGravityRestorationSkipped = true;\n\t}\n}\n\n// @param {module:engine/model/position~Position} position\n// @param {String} attribute\n// @returns {Boolean} `true` when position between the nodes sticks to the bound of text with given attribute.\nfunction isAtBoundary( position, attribute ) {\n\treturn isAtStartBoundary( position, attribute ) || isAtEndBoundary( position, attribute );\n}\n\n// @param {module:engine/model/position~Position} position\n// @param {String} attribute\nfunction isAtStartBoundary( position, attribute ) {\n\tconst { nodeBefore, nodeAfter } = position;\n\tconst isAttrBefore = nodeBefore ? nodeBefore.hasAttribute( attribute ) : false;\n\tconst isAttrAfter = nodeAfter ? nodeAfter.hasAttribute( attribute ) : false;\n\n\treturn isAttrAfter && ( !isAttrBefore || nodeBefore.getAttribute( attribute ) !== nodeAfter.getAttribute( attribute ) );\n}\n\n// @param {module:engine/model/position~Position} position\n// @param {String} attribute\nfunction isAtEndBoundary( position, attribute ) {\n\tconst { nodeBefore, nodeAfter } = position;\n\tconst isAttrBefore = nodeBefore ? nodeBefore.hasAttribute( attribute ) : false;\n\tconst isAttrAfter = nodeAfter ? nodeAfter.hasAttribute( attribute ) : false;\n\n\treturn isAttrBefore && ( !isAttrAfter || nodeBefore.getAttribute( attribute ) !== nodeAfter.getAttribute( attribute ) );\n}\n\n// @param {module:engine/model/position~Position} position\n// @param {String} attribute\nfunction isBetweenDifferentValues( position, attribute ) {\n\tconst { nodeBefore, nodeAfter } = position;\n\tconst isAttrBefore = nodeBefore ? nodeBefore.hasAttribute( attribute ) : false;\n\tconst isAttrAfter = nodeAfter ? nodeAfter.hasAttribute( attribute ) : false;\n\n\tif ( !isAttrAfter || !isAttrBefore ) {\n\t\treturn;\n\t}\n\n\treturn nodeAfter.getAttribute( attribute ) !== nodeBefore.getAttribute( attribute );\n}\n\n// @param {module:engine/model/position~Position} position\n// @param {String} attribute\nfunction isStepAfterTheAttributeBoundary( position, attribute ) {\n\treturn isAtBoundary( position.getShiftedBy( -1 ), attribute );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 link/linkediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport LinkCommand from './linkcommand';\nimport UnlinkCommand from './unlinkcommand';\nimport { createLinkElement, ensureSafeUrl, getLocalizedDecorators, normalizeDecorators } from './utils';\nimport AutomaticDecorators from './utils/automaticdecorators';\nimport ManualDecorator from './utils/manualdecorator';\nimport bindTwoStepCaretToAttribute from '@ckeditor/ckeditor5-engine/src/utils/bindtwostepcarettoattribute';\nimport findLinkRange from './findlinkrange';\nimport '../theme/link.css';\n\nconst HIGHLIGHT_CLASS = 'ck-link_selected';\nconst DECORATOR_AUTOMATIC = 'automatic';\nconst DECORATOR_MANUAL = 'manual';\nconst EXTERNAL_LINKS_REGEXP = /^(https?:)?\\/\\//;\n\n/**\n * The link engine feature.\n *\n * It introduces the `linkHref=\"url\"` attribute in the model which renders to the view as a `<a href=\"url\">` element\n * as well as `'link'` and `'unlink'` commands.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class LinkEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'LinkEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'link', {\n\t\t\taddTargetToExternalLinks: false\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst locale = editor.locale;\n\n\t\t// Allow link attribute on all inline nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: 'linkHref' } );\n\n\t\teditor.conversion.for( 'dataDowncast' )\n\t\t\t.attributeToElement( { model: 'linkHref', view: createLinkElement } );\n\n\t\teditor.conversion.for( 'editingDowncast' )\n\t\t\t.attributeToElement( { model: 'linkHref', view: ( href, writer ) => {\n\t\t\t\treturn createLinkElement( ensureSafeUrl( href ), writer );\n\t\t\t} } );\n\n\t\teditor.conversion.for( 'upcast' )\n\t\t\t.elementToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'a',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\thref: true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tmodel: {\n\t\t\t\t\tkey: 'linkHref',\n\t\t\t\t\tvalue: viewElement => viewElement.getAttribute( 'href' )\n\t\t\t\t}\n\t\t\t} );\n\n\t\t// Create linking commands.\n\t\teditor.commands.add( 'link', new LinkCommand( editor ) );\n\t\teditor.commands.add( 'unlink', new UnlinkCommand( editor ) );\n\n\t\tconst linkDecorators = getLocalizedDecorators( editor.t, normalizeDecorators( editor.config.get( 'link.decorators' ) ) );\n\n\t\tthis._enableAutomaticDecorators( linkDecorators.filter( item => item.mode === DECORATOR_AUTOMATIC ) );\n\t\tthis._enableManualDecorators( linkDecorators.filter( item => item.mode === DECORATOR_MANUAL ) );\n\n\t\t// Enable two-step caret movement for `linkHref` attribute.\n\t\tbindTwoStepCaretToAttribute( {\n\t\t\tview: editor.editing.view,\n\t\t\tmodel: editor.model,\n\t\t\temitter: this,\n\t\t\tattribute: 'linkHref',\n\t\t\tlocale\n\t\t} );\n\n\t\t// Setup highlight over selected link.\n\t\tthis._setupLinkHighlight();\n\t}\n\n\t/**\n\t * Processes an array of configured {@link module:link/link~LinkDecoratorAutomaticDefinition automatic decorators}\n\t * and registers a {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher downcast dispatcher}\n\t * for each one of them. Downcast dispatchers are obtained using the\n\t * {@link module:link/utils~AutomaticDecorators#getDispatcher} method.\n\t *\n\t * **Note**: This method also activates the automatic external link decorator if enabled with\n\t * {@link module:link/link~LinkConfig#addTargetToExternalLinks `config.link.addTargetToExternalLinks`}.\n\t *\n\t * @private\n\t * @param {Array.<module:link/link~LinkDecoratorAutomaticDefinition>} automaticDecoratorDefinitions\n\t */\n\t_enableAutomaticDecorators( automaticDecoratorDefinitions ) {\n\t\tconst editor = this.editor;\n\t\tconst automaticDecorators = new AutomaticDecorators();\n\n\t\t// Adds a default decorator for external links.\n\t\tif ( editor.config.get( 'link.addTargetToExternalLinks' ) ) {\n\t\t\tautomaticDecorators.add( {\n\t\t\t\tid: 'linkIsExternal',\n\t\t\t\tmode: DECORATOR_AUTOMATIC,\n\t\t\t\tcallback: url => EXTERNAL_LINKS_REGEXP.test( url ),\n\t\t\t\tattributes: {\n\t\t\t\t\ttarget: '_blank',\n\t\t\t\t\trel: 'noopener noreferrer'\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\tautomaticDecorators.add( automaticDecoratorDefinitions );\n\n\t\tif ( automaticDecorators.length ) {\n\t\t\teditor.conversion.for( 'downcast' ).add( automaticDecorators.getDispatcher() );\n\t\t}\n\t}\n\n\t/**\n\t * Processes an array of configured {@link module:link/link~LinkDecoratorManualDefinition manual decorators},\n\t * transforms them into {@link module:link/utils~ManualDecorator} instances and stores them in the\n\t * {@link module:link/linkcommand~LinkCommand#manualDecorators} collection (a model for manual decorators state).\n\t *\n\t * Also registers an {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement attribute-to-element}\n\t * converter for each manual decorator and extends the {@link module:engine/model/schema~Schema model's schema}\n\t * with adequate model attributes.\n\t *\n\t * @private\n\t * @param {Array.<module:link/link~LinkDecoratorManualDefinition>} manualDecoratorDefinitions\n\t */\n\t_enableManualDecorators( manualDecoratorDefinitions ) {\n\t\tif ( !manualDecoratorDefinitions.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\t\tconst command = editor.commands.get( 'link' );\n\t\tconst manualDecorators = command.manualDecorators;\n\n\t\tmanualDecoratorDefinitions.forEach( decorator => {\n\t\t\teditor.model.schema.extend( '$text', { allowAttributes: decorator.id } );\n\n\t\t\t// Keeps reference to manual decorator to decode its name to attributes during downcast.\n\t\t\tmanualDecorators.add( new ManualDecorator( decorator ) );\n\n\t\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\t\tmodel: decorator.id,\n\t\t\t\tview: ( manualDecoratorName, writer ) => {\n\t\t\t\t\tif ( manualDecoratorName ) {\n\t\t\t\t\t\tconst attributes = manualDecorators.get( decorator.id ).attributes;\n\t\t\t\t\t\tconst element = writer.createAttributeElement( 'a', attributes, { priority: 5 } );\n\t\t\t\t\t\twriter.setCustomProperty( 'link', true, element );\n\n\t\t\t\t\t\treturn element;\n\t\t\t\t\t}\n\t\t\t\t} } );\n\n\t\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'a',\n\t\t\t\t\tattributes: manualDecorators.get( decorator.id ).attributes\n\t\t\t\t},\n\t\t\t\tmodel: {\n\t\t\t\t\tkey: decorator.id\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t/**\n\t * Adds a visual highlight style to a link in which the selection is anchored.\n\t * Together with two-step caret movement, they indicate that the user is typing inside the link.\n\t *\n\t * Highlight is turned on by adding the `.ck-link_selected` class to the link in the view:\n\t *\n\t * * The class is removed before the conversion has started, as callbacks added with the `'highest'` priority\n\t * to {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} events.\n\t * * The class is added in the view post fixer, after other changes in the model tree were converted to the view.\n\t *\n\t * This way, adding and removing the highlight does not interfere with conversion.\n\t *\n\t * @private\n\t */\n\t_setupLinkHighlight() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst highlightedLinks = new Set();\n\n\t\t// Adding the class.\n\t\tview.document.registerPostFixer( writer => {\n\t\t\tconst selection = editor.model.document.selection;\n\t\t\tlet changed = false;\n\n\t\t\tif ( selection.hasAttribute( 'linkHref' ) ) {\n\t\t\t\tconst modelRange = findLinkRange( selection.getFirstPosition(), selection.getAttribute( 'linkHref' ), editor.model );\n\t\t\t\tconst viewRange = editor.editing.mapper.toViewRange( modelRange );\n\n\t\t\t\t// There might be multiple `a` elements in the `viewRange`, for example, when the `a` element is\n\t\t\t\t// broken by a UIElement.\n\t\t\t\tfor ( const item of viewRange.getItems() ) {\n\t\t\t\t\tif ( item.is( 'a' ) && !item.hasClass( HIGHLIGHT_CLASS ) ) {\n\t\t\t\t\t\twriter.addClass( HIGHLIGHT_CLASS, item );\n\t\t\t\t\t\thighlightedLinks.add( item );\n\t\t\t\t\t\tchanged = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn changed;\n\t\t} );\n\n\t\t// Removing the class.\n\t\teditor.conversion.for( 'editingDowncast' ).add( dispatcher => {\n\t\t\t// Make sure the highlight is removed on every possible event, before conversion is started.\n\t\t\tdispatcher.on( 'insert', removeHighlight, { priority: 'highest' } );\n\t\t\tdispatcher.on( 'remove', removeHighlight, { priority: 'highest' } );\n\t\t\tdispatcher.on( 'attribute', removeHighlight, { priority: 'highest' } );\n\t\t\tdispatcher.on( 'selection', removeHighlight, { priority: 'highest' } );\n\n\t\t\tfunction removeHighlight() {\n\t\t\t\tview.change( writer => {\n\t\t\t\t\tfor ( const item of highlightedLinks.values() ) {\n\t\t\t\t\t\twriter.removeClass( HIGHLIGHT_CLASS, item );\n\t\t\t\t\t\thighlightedLinks.delete( item );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/notification/notification\n */\n\n/* globals window */\n\nimport ContextPlugin from '@ckeditor/ckeditor5-core/src/contextplugin';\n\n/**\n * The Notification plugin.\n *\n * This plugin sends a few types of notifications: `success`, `info` and `warning`. The notifications need to be\n * handled and displayed by a plugin responsible for showing the UI of the notifications. Using this plugin for dispatching\n * notifications makes it possible to switch the notifications UI.\n *\n * Note that every unhandled and not stopped `warning` notification will be displayed as a system alert.\n * See {@link module:ui/notification/notification~Notification#showWarning}.\n *\n * @extends module:core/contextplugin~ContextPlugin\n */\nexport default class Notification extends ContextPlugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Notification';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\t// Each unhandled and not stopped `show:warning` event is displayed as a system alert.\n\t\tthis.on( 'show:warning', ( evt, data ) => {\n\t\t\twindow.alert( data.message ); // eslint-disable-line no-alert\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Shows a success notification.\n\t *\n\t * By default, it fires the {@link #event:show:success `show:success` event} with the given `data`. The event namespace can be extended\n\t * using the `data.namespace` option. For example:\n\t *\n\t * \t\tshowSuccess( 'Image is uploaded.', {\n\t * \t\t\tnamespace: 'upload:image'\n\t * \t\t} );\n\t *\n\t * will fire the `show:success:upload:image` event.\n\t *\n\t * You can provide the title of the notification:\n\t *\n\t *\t\tshowSuccess( 'Image is uploaded.', {\n\t *\t\t\ttitle: 'Image upload success'\n\t *\t\t} );\n\t *\n\t * @param {String} message The content of the notification.\n\t * @param {Object} [data={}] Additional data.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title] The title of the notification.\n\t */\n\tshowSuccess( message, data = {} ) {\n\t\tthis._showNotification( {\n\t\t\tmessage,\n\t\t\ttype: 'success',\n\t\t\tnamespace: data.namespace,\n\t\t\ttitle: data.title\n\t\t} );\n\t}\n\n\t/**\n\t * Shows an information notification.\n\t *\n\t * By default, it fires the {@link #event:show:info `show:info` event} with the given `data`. The event namespace can be extended\n\t * using the `data.namespace` option. For example:\n\t *\n\t * \t\tshowInfo( 'Editor is offline.', {\n\t * \t\t\tnamespace: 'editor:status'\n\t * \t\t} );\n\t *\n\t * will fire the `show:info:editor:status` event.\n\t *\n\t * You can provide the title of the notification:\n\t *\n\t *\t\tshowInfo( 'Editor is offline.', {\n\t *\t\t\ttitle: 'Network information'\n\t *\t\t} );\n\t *\n\t * @param {String} message The content of the notification.\n\t * @param {Object} [data={}] Additional data.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title] The title of the notification.\n\t */\n\tshowInfo( message, data = {} ) {\n\t\tthis._showNotification( {\n\t\t\tmessage,\n\t\t\ttype: 'info',\n\t\t\tnamespace: data.namespace,\n\t\t\ttitle: data.title\n\t\t} );\n\t}\n\n\t/**\n\t * Shows a warning notification.\n\t *\n\t * By default, it fires the {@link #event:show:warning `show:warning` event}\n\t * with the given `data`. The event namespace can be extended using the `data.namespace` option. For example:\n\t *\n\t * \t\tshowWarning( 'Image upload error.', {\n\t * \t\t\tnamespace: 'upload:image'\n\t * \t\t} );\n\t *\n\t * will fire the `show:warning:upload:image` event.\n\t *\n\t * You can provide the title of the notification:\n\t *\n\t *\t\tshowWarning( 'Image upload error.', {\n\t *\t\t\ttitle: 'Upload failed'\n\t *\t\t} );\n\t *\n\t * Note that each unhandled and not stopped `warning` notification will be displayed as a system alert.\n\t * The plugin responsible for displaying warnings should `stop()` the event to prevent displaying it as an alert:\n\t *\n\t * \t\tnotifications.on( 'show:warning', ( evt, data ) => {\n\t * \t\t\t// Do something with the data.\n\t *\n\t * \t\t\t// Stop this event to prevent displaying it as an alert.\n\t * \t\t\tevt.stop();\n\t * \t\t} );\n\t *\n\t * You can attach many listeners to the same event and `stop()` this event in a listener with a low priority:\n\t *\n\t * \t\tnotifications.on( 'show:warning', ( evt, data ) => {\n\t * \t\t\t// Show the warning in the UI, but do not stop it.\n\t * \t\t} );\n\t *\n\t * \t\tnotifications.on( 'show:warning', ( evt, data ) => {\n\t * \t\t\t// Log the warning to some error tracker.\n\t *\n\t * \t\t\t// Stop this event to prevent displaying it as an alert.\n\t * \t\t\tevt.stop();\n\t * \t\t}, { priority: 'low' } );\n\t *\n\t * @param {String} message The content of the notification.\n\t * @param {Object} [data={}] Additional data.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title] The title of the notification.\n\t */\n\tshowWarning( message, data = {} ) {\n\t\tthis._showNotification( {\n\t\t\tmessage,\n\t\t\ttype: 'warning',\n\t\t\tnamespace: data.namespace,\n\t\t\ttitle: data.title\n\t\t} );\n\t}\n\n\t/**\n\t * Fires the `show` event with the specified type, namespace and message.\n\t *\n\t * @private\n\t * @param {Object} data The message data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {'success'|'info'|'warning'} data.type The type of the message.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title=''] The title of the notification.\n\t */\n\t_showNotification( data ) {\n\t\tconst event = `show:${ data.type }` + ( data.namespace ? `:${ data.namespace }` : '' );\n\n\t\tthis.fire( event, {\n\t\t\tmessage: data.message,\n\t\t\ttype: data.type,\n\t\t\ttitle: data.title || ''\n\t\t} );\n\t}\n\n\t/**\n\t * Fired when one of the `showSuccess()`, `showInfo()`, `showWarning()` methods is called.\n\t *\n\t * @event show\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'success'|'info'|'warning'} data.type The type of the notification.\n\t */\n\n\t/**\n\t * Fired when the `showSuccess()` method is called.\n\t *\n\t * @event show:success\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'success'} data.type The type of the notification.\n\t */\n\n\t/**\n\t * Fired when the `showInfo()` method is called.\n\t *\n\t * @event show:info\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'info'} data.type The type of the notification.\n\t */\n\n\t/**\n\t * Fired when the `showWarning()` method is called.\n\t *\n\t * When this event is not handled or stopped by `event.stop()`, the `data.message` of this event will\n\t * be automatically displayed as a system alert.\n\t *\n\t * @event show:warning\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'warning'} data.type The type of the notification.\n\t */\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/* global window */\n/**\n * @module ckfinder/ckfindercommand\n */\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n/**\n * The CKFinder command. It is used by the {@link module:ckfinder/ckfinderediting~CKFinderEditing CKFinder editing feature}\n * to open the CKFinder file manager to insert an image or a link to a file into the editor content.\n *\n *\t\teditor.execute( 'ckfinder' );\n *\n * **Note:** This command uses other features to perform tasks:\n * - To insert images the {@link module:image/image/imageinsertcommand~ImageInsertCommand 'imageInsert'} command\n * from the {@link module:image/image~Image Image feature}.\n * - To insert links to files the {@link module:link/linkcommand~LinkCommand 'link'} command\n * from the {@link module:link/link~Link Link feature}.\n *\n * @extends module:core/command~Command\n */\nexport default class CKFinderCommand extends Command {\n /**\n\t * @inheritDoc\n\t */\n constructor(editor) {\n super(editor);\n // Remove default document listener to lower its priority.\n this.stopListening(this.editor.model.document, 'change');\n // Lower this command listener priority to be sure that refresh() will be called after link & image refresh.\n this.listenTo(this.editor.model.document, 'change', () => this.refresh(), { priority: 'low' });\n }\n /**\n\t * @inheritDoc\n\t */\n refresh() {\n const imageCommand = this.editor.commands.get('imageInsert');\n const linkCommand = this.editor.commands.get('link');\n // The CKFinder command is enabled when one of image or link command is enabled.\n this.isEnabled = imageCommand.isEnabled || linkCommand.isEnabled;\n }\n /**\n\t * @inheritDoc\n\t */\n execute() {\n const editor = this.editor;\n const openerMethod = this.editor.config.get('ckfinder.openerMethod') || 'modal';\n if (openerMethod != 'popup' && openerMethod != 'modal') {\n throw new CKEditorError('ckfinder-unknown-openerMethod: The openerMethod config option must by \"popup\" or \"modal\".', editor);\n }\n const options = this.editor.config.get('ckfinder.options') || {};\n options.chooseFiles = true;\n // Cache the user-defined onInit method\n const originalOnInit = options.onInit;\n // Pass the lang code to the CKFinder if not defined by user.\n if (!options.language) {\n options.language = editor.locale.uiLanguage;\n }\n // The onInit method allows to extend CKFinder's behavior. It is used to attach event listeners to file choosing related events.\n options.onInit = finder => {\n // Call original options.onInit if it was defined by user.\n if (originalOnInit) {\n originalOnInit(finder);\n }\n finder.on('files:choose', evt => {\n const files = evt.data.files.toArray();\n // Insert links\n const links = files.filter(file => !file.isImage());\n const images = files.filter(file => file.isImage());\n for (const linkFile of links) {\n editor.execute('link', linkFile.getUrl());\n }\n const imagesUrls = [];\n for (const image of images) {\n const url = image.getUrl();\n imagesUrls.push(url ? url : finder.request('file:getProxyUrl', { file: image }));\n }\n if (imagesUrls.length) {\n insertImages(editor, imagesUrls);\n }\n });\n finder.on('file:choose:resizedImage', evt => {\n const resizedUrl = evt.data.resizedUrl;\n if (!resizedUrl) {\n const notification = editor.plugins.get('Notification');\n const t = editor.locale.t;\n notification.showWarning(t('bj'), {\n title: t('bk'),\n namespace: 'ckfinder'\n });\n return;\n }\n insertImages(editor, [resizedUrl]);\n });\n };\n window.CKFinder[openerMethod](options);\n }\n}\nfunction insertImages(editor, urls) {\n const imageCommand = editor.commands.get('imageInsert');\n // Check if inserting an image is actually possible - it might be possible to only insert a link.\n if (!imageCommand.isEnabled) {\n const notification = editor.plugins.get('Notification');\n const t = editor.locale.t;\n notification.showWarning(t('bl'), {\n title: t('bm'),\n namespace: 'ckfinder'\n });\n return;\n }\n editor.execute('imageInsert', { source: urls });\n}","/**\n * @license Copyright (c) 2003-2020, 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 ckfinder/ckfinderediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageEditing from '@ckeditor/ckeditor5-image/src/image/imageediting';\nimport LinkEditing from '@ckeditor/ckeditor5-link/src/linkediting';\nimport Notification from '@ckeditor/ckeditor5-ui/src/notification/notification';\n\nimport CKFinderCommand from './ckfindercommand';\n\n/**\n * The CKFinder editing feature. It introduces the {@link module:ckfinder/ckfindercommand~CKFinderCommand CKFinder command}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CKFinderEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CKFinderEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Notification, ImageEditing, LinkEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.commands.add( 'ckfinder', new CKFinderCommand( editor ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 cloud-services-core/uploadgateway/fileuploader\n */\n\n/* globals XMLHttpRequest, FormData, Blob, atob */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nconst BASE64_HEADER_REG_EXP = /^data:(\\S*?);base64,/;\n\n/**\n * FileUploader class used to upload single file.\n */\nexport default class FileUploader {\n\t/**\n\t * Creates `FileUploader` instance.\n\t *\n\t * @param {Blob|String} fileOrData A blob object or a data string encoded with Base64.\n\t * @param {module:cloud-services-core/token~Token} token Token used for authentication.\n\t * @param {String} apiAddress API address.\n\t */\n\tconstructor( fileOrData, token, apiAddress ) {\n\t\tif ( !fileOrData ) {\n\t\t\t/**\n\t\t\t * File must be provided as the first argument.\n\t\t\t *\n\t\t\t * @error fileuploader-missing-file\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'fileuploader-missing-file: File must be provided as the first argument', null );\n\t\t}\n\n\t\tif ( !token ) {\n\t\t\t/**\n\t\t\t * Token must be provided as the second argument.\n\t\t\t *\n\t\t\t * @error fileuploader-missing-token\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'fileuploader-missing-token: Token must be provided as the second argument.', null );\n\t\t}\n\n\t\tif ( !apiAddress ) {\n\t\t\t/**\n\t\t\t * Api address must be provided as the third argument.\n\t\t\t *\n\t\t\t * @error fileuploader-missing-api-address\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'fileuploader-missing-api-address: Api address must be provided as the third argument.', null );\n\t\t}\n\n\t\t/**\n\t\t * A file that is being uploaded.\n\t\t *\n\t\t * @type {Blob}\n\t\t */\n\t\tthis.file = _isBase64( fileOrData ) ? _base64ToBlob( fileOrData ) : fileOrData;\n\n\t\t/**\n\t\t * CKEditor Cloud Services access token.\n\t\t *\n\t\t * @type {module:cloud-services-core/token~Token}\n\t\t * @private\n\t\t */\n\t\tthis._token = token;\n\n\t\t/**\n\t\t * CKEditor Cloud Services API address.\n\t\t *\n\t\t * @type {String}\n\t\t * @private\n\t\t */\n\t\tthis._apiAddress = apiAddress;\n\t}\n\n\t/**\n\t * Registers callback on `progress` event.\n\t *\n\t * @chainable\n\t * @param {Function} callback\n\t * @returns {module:cloud-services-core/uploadgateway/fileuploader~FileUploader}\n\t */\n\tonProgress( callback ) {\n\t\tthis.on( 'progress', ( event, data ) => callback( data ) );\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Registers callback on `error` event. Event is called once when error occurs.\n\t *\n\t * @chainable\n\t * @param {Function} callback\n\t * @returns {module:cloud-services-core/uploadgateway/fileuploader~FileUploader}\n\t */\n\tonError( callback ) {\n\t\tthis.once( 'error', ( event, data ) => callback( data ) );\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Aborts upload process.\n\t */\n\tabort() {\n\t\tthis.xhr.abort();\n\t}\n\n\t/**\n\t * Sends XHR request to API.\n\t *\n\t * @chainable\n\t * @returns {Promise.<Object>}\n\t */\n\tsend() {\n\t\tthis._prepareRequest();\n\t\tthis._attachXHRListeners();\n\n\t\treturn this._sendRequest();\n\t}\n\n\t/**\n\t * Prepares XHR request.\n\t *\n\t * @private\n\t */\n\t_prepareRequest() {\n\t\tconst xhr = new XMLHttpRequest();\n\n\t\txhr.open( 'POST', this._apiAddress );\n\t\txhr.setRequestHeader( 'Authorization', this._token.value );\n\t\txhr.responseType = 'json';\n\n\t\tthis.xhr = xhr;\n\t}\n\n\t/**\n\t * Attaches listeners to the XHR.\n\t *\n\t * @private\n\t */\n\t_attachXHRListeners() {\n\t\tconst that = this;\n\t\tconst xhr = this.xhr;\n\n\t\txhr.addEventListener( 'error', onError( 'Network Error' ) );\n\t\txhr.addEventListener( 'abort', onError( 'Abort' ) );\n\n\t\t/* istanbul ignore else */\n\t\tif ( xhr.upload ) {\n\t\t\txhr.upload.addEventListener( 'progress', event => {\n\t\t\t\tif ( event.lengthComputable ) {\n\t\t\t\t\tthis.fire( 'progress', {\n\t\t\t\t\t\ttotal: event.total,\n\t\t\t\t\t\tuploaded: event.loaded\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\txhr.addEventListener( 'load', () => {\n\t\t\tconst statusCode = xhr.status;\n\t\t\tconst xhrResponse = xhr.response;\n\n\t\t\tif ( statusCode < 200 || statusCode > 299 ) {\n\t\t\t\treturn this.fire( 'error', xhrResponse.message || xhrResponse.error );\n\t\t\t}\n\t\t} );\n\n\t\tfunction onError( message ) {\n\t\t\treturn () => that.fire( 'error', message );\n\t\t}\n\t}\n\n\t/**\n\t * Sends XHR request.\n\t *\n\t * @private\n\t */\n\t_sendRequest() {\n\t\tconst formData = new FormData();\n\t\tconst xhr = this.xhr;\n\n\t\tformData.append( 'file', this.file );\n\n\t\treturn new Promise( ( resolve, reject ) => {\n\t\t\txhr.addEventListener( 'load', () => {\n\t\t\t\tconst statusCode = xhr.status;\n\t\t\t\tconst xhrResponse = xhr.response;\n\n\t\t\t\tif ( statusCode < 200 || statusCode > 299 ) {\n\t\t\t\t\tif ( xhrResponse.message ) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Uploading file failed.\n\t\t\t\t\t\t *\n\t\t\t\t\t\t * @error fileuploader-uploading-data-failed\n\t\t\t\t\t\t */\n\t\t\t\t\t\treturn reject( new CKEditorError(\n\t\t\t\t\t\t\t'fileuploader-uploading-data-failed: Uploading file failed.',\n\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t{ message: xhrResponse.message }\n\t\t\t\t\t\t) );\n\t\t\t\t\t}\n\n\t\t\t\t\treturn reject( xhrResponse.error );\n\t\t\t\t}\n\n\t\t\t\treturn resolve( xhrResponse );\n\t\t\t} );\n\n\t\t\txhr.addEventListener( 'error', () => reject( new Error( 'Network Error' ) ) );\n\t\t\txhr.addEventListener( 'abort', () => reject( new Error( 'Abort' ) ) );\n\n\t\t\txhr.send( formData );\n\t\t} );\n\t}\n\n\t/**\n\t * Fired when error occurs.\n\t *\n\t * @event error\n\t * @param {String} error Error message\n\t */\n\n\t/**\n\t * Fired on upload progress.\n\t *\n\t * @event progress\n\t * @param {Object} status Total and uploaded status\n\t */\n}\n\nmix( FileUploader, EmitterMixin );\n\n/**\n * Transforms Base64 string data into file.\n *\n * @param {String} base64 String data.\n * @param {Number} [sliceSize=512]\n * @returns {Blob}\n * @private\n */\nfunction _base64ToBlob( base64, sliceSize = 512 ) {\n\ttry {\n\t\tconst contentType = base64.match( BASE64_HEADER_REG_EXP )[ 1 ];\n\t\tconst base64Data = atob( base64.replace( BASE64_HEADER_REG_EXP, '' ) );\n\n\t\tconst byteArrays = [];\n\n\t\tfor ( let offset = 0; offset < base64Data.length; offset += sliceSize ) {\n\t\t\tconst slice = base64Data.slice( offset, offset + sliceSize );\n\t\t\tconst byteNumbers = new Array( slice.length );\n\n\t\t\tfor ( let i = 0; i < slice.length; i++ ) {\n\t\t\t\tbyteNumbers[ i ] = slice.charCodeAt( i );\n\t\t\t}\n\n\t\t\tbyteArrays.push( new Uint8Array( byteNumbers ) );\n\t\t}\n\n\t\treturn new Blob( byteArrays, { type: contentType } );\n\t} catch ( error ) {\n\t\t/**\n\t\t * Problem with decoding Base64 image data.\n\t\t *\n\t\t * @error fileuploader-decoding-image-data-error\n\t\t */\n\t\tthrow new CKEditorError( 'fileuploader-decoding-image-data-error: Problem with decoding Base64 image data.', null );\n\t}\n}\n\n/**\n * Checks that string is Base64.\n *\n * @param {String} string\n * @returns {Boolean}\n * @private\n */\nfunction _isBase64( string ) {\n\tif ( typeof string !== 'string' ) {\n\t\treturn false;\n\t}\n\n\tconst match = string.match( BASE64_HEADER_REG_EXP );\n\treturn !!( match && match.length );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 cloud-services-core/token\n */\n\n/* globals XMLHttpRequest, setInterval, clearInterval */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nconst DEFAULT_OPTIONS = { refreshInterval: 3600000, autoRefresh: true };\n\n/**\n * Class representing the token used for communication with CKEditor Cloud Services.\n * Value of the token is retrieving from the specified URL and is refreshed every 1 hour by default.\n *\n * @mixes ObservableMixin\n */\nclass Token {\n\t/**\n\t * Creates `Token` instance.\n\t * Method `init` should be called after using the constructor or use `create` method instead.\n\t *\n\t * @param {String|Function} tokenUrlOrRefreshToken Endpoint address to download the token or a callback that provides the token. If the\n\t * value is a function it has to match the {@link module:cloud-services-core/token~refreshToken} interface.\n\t * @param {Object} options\n\t * @param {String} [options.initValue] Initial value of the token.\n\t * @param {Number} [options.refreshInterval=3600000] Delay between refreshes. Default 1 hour.\n\t * @param {Boolean} [options.autoRefresh=true] Specifies whether to start the refresh automatically.\n\t */\n\tconstructor( tokenUrlOrRefreshToken, options = DEFAULT_OPTIONS ) {\n\t\tif ( !tokenUrlOrRefreshToken ) {\n\t\t\t/**\n\t\t\t * A `tokenUrl` must be provided as the first constructor argument.\n\t\t\t *\n\t\t\t * @error token-missing-token-url\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'token-missing-token-url: A `tokenUrl` must be provided as the first constructor argument.',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\t/**\n\t\t * Value of the token.\n\t\t * The value of the token is null if `initValue` is not provided or `init` method was not called.\n\t\t * `create` method creates token with initialized value from url.\n\t\t *\n\t\t * @name value\n\t\t * @member {String} #value\n\t\t * @observable\n\t\t * @readonly\n\t\t */\n\t\tthis.set( 'value', options.initValue );\n\n\t\t/**\n\t\t * Base refreshing function.\n\t\t *\n\t\t * @private\n\t\t * @member {String|Function} #_refresh\n\t\t */\n\t\tif ( typeof tokenUrlOrRefreshToken === 'function' ) {\n\t\t\tthis._refresh = tokenUrlOrRefreshToken;\n\t\t} else {\n\t\t\tthis._refresh = () => defaultRefreshToken( tokenUrlOrRefreshToken );\n\t\t}\n\n\t\t/**\n\t\t * @type {Object}\n\t\t * @private\n\t\t */\n\t\tthis._options = Object.assign( {}, DEFAULT_OPTIONS, options );\n\t}\n\n\t/**\n\t * Initializes the token.\n\t *\n\t * @returns {Promise.<module:cloud-services-core/token~Token>}\n\t */\n\tinit() {\n\t\treturn new Promise( ( resolve, reject ) => {\n\t\t\tif ( this._options.autoRefresh ) {\n\t\t\t\tthis._startRefreshing();\n\t\t\t}\n\n\t\t\tif ( !this.value ) {\n\t\t\t\tthis._refreshToken()\n\t\t\t\t\t.then( resolve )\n\t\t\t\t\t.catch( reject );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tresolve( this );\n\t\t} );\n\t}\n\n\t/**\n\t * Refresh token method. Useful in a method form as it can be override in tests.\n\t *\n\t * @protected\n\t */\n\t_refreshToken() {\n\t\treturn this._refresh()\n\t\t\t.then( value => this.set( 'value', value ) )\n\t\t\t.then( () => this );\n\t}\n\n\t/**\n\t * Destroys token instance. Stops refreshing.\n\t */\n\tdestroy() {\n\t\tthis._stopRefreshing();\n\t}\n\n\t/**\n\t * Starts value refreshing every `refreshInterval` time.\n\t *\n\t * @protected\n\t */\n\t_startRefreshing() {\n\t\tthis._refreshInterval = setInterval( () => this._refreshToken(), this._options.refreshInterval );\n\t}\n\n\t/**\n\t * Stops value refreshing.\n\t *\n\t * @protected\n\t */\n\t_stopRefreshing() {\n\t\tclearInterval( this._refreshInterval );\n\t}\n\n\t/**\n\t * Creates a initialized {@link module:cloud-services-core/token~Token} instance.\n\t *\n\t * @param {String|Function} tokenUrlOrRefreshToken Endpoint address to download the token or a callback that provides the token. If the\n\t * value is a function it has to match the {@link module:cloud-services-core/token~refreshToken} interface.\n\t * @param {Object} options\n\t * @param {String} [options.initValue] Initial value of the token.\n\t * @param {Number} [options.refreshInterval=3600000] Delay between refreshes. Default 1 hour.\n\t * @param {Boolean} [options.autoRefresh=true] Specifies whether to start the refresh automatically.\n\t * @returns {Promise.<module:cloud-services-core/token~Token>}\n\t */\n\tstatic create( tokenUrlOrRefreshToken, options = DEFAULT_OPTIONS ) {\n\t\tconst token = new Token( tokenUrlOrRefreshToken, options );\n\n\t\treturn token.init();\n\t}\n}\n\nmix( Token, ObservableMixin );\n\n/**\n * This function is called in a defined interval by the {@link ~Token} class.\n * It should return a promise, which resolves with the new token value.\n * If any error occurs it should return a rejected promise with an error message.\n *\n * @function refreshToken\n * @returns {Promise.<String>}\n */\n\n/**\n * @private\n * @param {String} tokenUrl\n */\nfunction defaultRefreshToken( tokenUrl ) {\n\treturn new Promise( ( resolve, reject ) => {\n\t\tconst xhr = new XMLHttpRequest();\n\n\t\txhr.open( 'GET', tokenUrl );\n\n\t\txhr.addEventListener( 'load', () => {\n\t\t\tconst statusCode = xhr.status;\n\t\t\tconst xhrResponse = xhr.response;\n\n\t\t\tif ( statusCode < 200 || statusCode > 299 ) {\n\t\t\t\t/**\n\t\t\t\t * Cannot download new token from the provided url.\n\t\t\t\t *\n\t\t\t\t * @error token-cannot-download-new-token\n\t\t\t\t */\n\t\t\t\treturn reject(\n\t\t\t\t\tnew CKEditorError( 'token-cannot-download-new-token: Cannot download new token from the provided url.', null )\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn resolve( xhrResponse );\n\t\t} );\n\n\t\txhr.addEventListener( 'error', () => reject( new Error( 'Network Error' ) ) );\n\t\txhr.addEventListener( 'abort', () => reject( new Error( 'Abort' ) ) );\n\n\t\txhr.send();\n\t} );\n}\n\nexport default Token;\n","/**\n * @license Copyright (c) 2003-2020, 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 cloud-services/cloudservices\n */\n\nimport ContextPlugin from '@ckeditor/ckeditor5-core/src/contextplugin';\nimport Token from '@ckeditor/ckeditor-cloud-services-core/src/token/token';\n\n/**\n * Plugin introducing integration between CKEditor 5 and CKEditor Cloud Services .\n *\n * It initializes the token provider based on\n * the {@link module:cloud-services/cloudservices~CloudServicesConfig `config.cloudService`}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CloudServices extends ContextPlugin {\n\t/**\n\t * @inheritdoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CloudServices';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst config = this.context.config;\n\n\t\tconst options = config.get( 'cloudServices' ) || {};\n\n\t\tfor ( const optionName in options ) {\n\t\t\tthis[ optionName ] = options[ optionName ];\n\t\t}\n\n\t\t/**\n\t\t * The authentication token URL for CKEditor Cloud Services or a callback to the token value promise. See the\n\t\t * {@link module:cloud-services/cloudservices~CloudServicesConfig#tokenUrl} for more details.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String|Function|undefined} #tokenUrl\n\t\t */\n\n\t\t/**\n\t\t * The URL to which the files should be uploaded.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} #uploadUrl\n\t\t */\n\n\t\t/**\n\t\t * Other plugins use this token for the authorization process. It handles token requesting and refreshing.\n\t\t * Its value is `null` when {@link module:cloud-services/cloudservices~CloudServicesConfig#tokenUrl} is not provided.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Object|null} #token\n\t\t */\n\n\t\tif ( !this.tokenUrl ) {\n\t\t\tthis.token = null;\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis.token = new CloudServices.Token( this.tokenUrl );\n\n\t\treturn this.token.init();\n\t}\n}\n\nCloudServices.Token = Token;\n\n/**\n * The configuration of CKEditor Cloud Services. Introduced by the {@link module:cloud-services/cloudservices~CloudServices} plugin.\n *\n * Read more in {@link module:cloud-services/cloudservices~CloudServicesConfig}.\n *\n * @member {module:cloud-services/cloudservices~CloudServicesConfig} module:core/editor/editorconfig~EditorConfig#cloudServices\n */\n\n/**\n * The configuration for all plugins using CKEditor Cloud Services.\n *\n *\t\tClassicEditor\n *\t\t\t.create( document.querySelector( '#editor' ), {\n *\t\t\t\tcloudServices: {\n *\t\t\t\t\ttokenUrl: 'https://example.com/cs-token-endpoint',\n *\t\t\t\t\tuploadUrl: 'https://your-organization-id.cke-cs.com/easyimage/upload/'\n *\t\t\t\t}\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 CloudServicesConfig\n */\n\n/**\n * A token URL or a token request function.\n *\n * As a string, it should be a URL to the security token endpoint in your application. The role of this endpoint is to securely authorize\n * the end users of your application to use [CKEditor Cloud Services](https://ckeditor.com/ckeditor-cloud-services) only\n * if they should have access e.g. to upload files with {@glink @cs guides/easy-image/quick-start Easy Image} or to use the\n * {@glink @cs guides/collaboration/quick-start Collaboration} service.\n *\n *\t\tClassicEditor\n *\t\t\t.create( document.querySelector( '#editor' ), {\n *\t\t\t\tcloudServices: {\n *\t\t\t\t\ttokenUrl: 'https://example.com/cs-token-endpoint',\n *\t\t\t\t\t...\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * As a function, it should provide a promise to the token value, so you can highly customize the token and provide your token URL endpoint.\n * By using this approach you can set your own headers for the request.\n *\n * \t\tClassicEditor\n *\t\t\t.create( document.querySelector( '#editor' ), {\n *\t\t\t\tcloudServices: {\n *\t\t\t\t\ttokenUrl: () => new Promise( ( resolve, reject ) => {\n *\t\t\t\t\t\tconst xhr = new XMLHttpRequest();\n *\n *\t\t\t\t\t\txhr.open( 'GET', 'https://example.com/cs-token-endpoint' );\n *\n *\t\t\t\t\t\txhr.addEventListener( 'load', () => {\n *\t\t\t\t\t\t\tconst statusCode = xhr.status;\n *\t\t\t\t\t\t\tconst xhrResponse = xhr.response;\n *\n *\t\t\t\t\t\t\tif ( statusCode < 200 || statusCode > 299 ) {\n *\t\t\t\t\t\t\t\treturn reject( new Error( 'Cannot download new token!' ) );\n *\t\t\t\t\t\t\t}\n *\n *\t\t\t\t\t\t\treturn resolve( xhrResponse );\n *\t\t\t\t\t\t} );\n *\n *\t\t\t\t\t\txhr.addEventListener( 'error', () => reject( new Error( 'Network Error' ) ) );\n *\t\t\t\t\t\txhr.addEventListener( 'abort', () => reject( new Error( 'Abort' ) ) );\n *\n *\t\t\t\t\t\txhr.setRequestHeader( customHeader, customValue );\n *\n *\t\t\t\t\t\txhr.send();\n *\t\t\t\t\t} ),\n *\t\t\t\t\t...\n *\t\t\t\t}\n *\t\t\t} )\n *\n * You can find more information about token endpoints in the\n * {@glink @cs guides/easy-image/quick-start#create-token-endpoint Cloud Services - Quick start}\n * and {@glink @cs guides/security/token-endpoint Cloud Services - Token endpoint} documentation.\n *\n * Without a properly working token endpoint (token URL) CKEditor plugins will not be able to connect to CKEditor Cloud Services.\n *\n * @member {String|Function} module:cloud-services/cloudservices~CloudServicesConfig#tokenUrl\n */\n\n/**\n * The endpoint URL for [CKEditor Cloud Services](https://ckeditor.com/ckeditor-cloud-services) uploads.\n * This option must be set for Easy Image to work correctly.\n *\n * The upload URL is unique for each customer and can be found in the\n * [CKEditor Ecosystem customer dashboard](https://dashboard.ckeditor.com) after subscribing to the Easy Image service.\n * To learn how to start using Easy Image, check the {@glink @cs guides/easy-image/quick-start Easy Image - Quick start} documentation.\n *\n * Note: Make sure to also set the {@link module:cloud-services/cloudservices~CloudServicesConfig#tokenUrl} configuration option.\n *\n * @member {String} module:cloud-services/cloudservices~CloudServicesConfig#uploadUrl\n */\n\n/**\n * The URL for web socket communication, used by the `RealTimeCollaborativeEditing` plugin. Every customer (organization in the CKEditor\n * Ecosystem dashboard) has their own, unique URLs to communicate with CKEditor Cloud Services. The URL can be found in the\n * CKEditor Ecosystem customer dashboard.\n *\n * Note: Unlike most plugins, `RealTimeCollaborativeEditing` is not included in any CKEditor 5 build and needs to be installed manually.\n * Check [Collaboration overview](https://ckeditor.com/docs/ckeditor5/latest/features/collaboration/overview.html) for more details.\n *\n * @member {String} module:cloud-services/cloudservices~CloudServicesConfig#webSocketUrl\n */\n\n/**\n * An optional parameter used for integration with CKEditor Cloud Services when uploading the editor build to cloud services.\n *\n * Whenever the editor build or the configuration changes, this parameter should be set to a new, unique value to differentiate\n * the new bundle (build + configuration) from the old ones.\n *\n * @member {String} module:cloud-services/cloudservices~CloudServicesConfig#bundleVersion\n */\n\n/**\n * The document ID used by the `RealTimeCollaborativeEditing` plugin. All editor instances created with the same document ID will\n * collaborate. It means that each document needs a different document ID if you do not want to start collaboration between these\n * documents. The ID is usually a primary key of the document in the database but you are free to provide whatever identifier fits your\n * scenario.\n *\n * Note: Unlike most plugins, `RealTimeCollaborativeEditing` is not included in any CKEditor 5 build and needs to be installed manually.\n * Check [Collaboration overview](https://ckeditor.com/docs/ckeditor5/latest/features/collaboration/overview.html) for more details.\n *\n * @member {String} module:cloud-services/cloudservices~CloudServicesConfig#documentId\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 easy-image/cloudservicesuploadadapter\n*/\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';\nimport UploadGateway from '@ckeditor/ckeditor-cloud-services-core/src/uploadgateway/uploadgateway';\nimport CloudServices from '@ckeditor/ckeditor5-cloud-services/src/cloudservices';\n\n/**\n * A plugin that enables upload to [CKEditor Cloud Services](https://ckeditor.com/ckeditor-cloud-services/).\n *\n * It is mainly used by the {@link module:easy-image/easyimage~EasyImage} feature.\n *\n * After enabling this adapter you need to configure the CKEditor Cloud Services integration through\n * {@link module:cloud-services/cloudservices~CloudServicesConfig `config.cloudServices`}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CloudServicesUploadAdapter extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FileRepository, CloudServices ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\tconst cloudServices = editor.plugins.get( CloudServices );\n\n\t\tconst token = cloudServices.token;\n\t\tconst uploadUrl = cloudServices.uploadUrl;\n\n\t\tif ( !token ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._uploadGateway = new CloudServicesUploadAdapter._UploadGateway( token, uploadUrl );\n\n\t\teditor.plugins.get( FileRepository ).createUploadAdapter = loader => {\n\t\t\treturn new Adapter( this._uploadGateway, loader );\n\t\t};\n\t}\n}\n\n/**\n * @private\n */\nclass Adapter {\n\tconstructor( uploadGateway, loader ) {\n\t\tthis.uploadGateway = uploadGateway;\n\n\t\tthis.loader = loader;\n\t}\n\n\tupload() {\n\t\treturn this.loader.file.then( file => {\n\t\t\tthis.fileUploader = this.uploadGateway.upload( file );\n\n\t\t\tthis.fileUploader.on( 'progress', ( evt, data ) => {\n\t\t\t\tthis.loader.uploadTotal = data.total;\n\t\t\t\tthis.loader.uploaded = data.uploaded;\n\t\t\t} );\n\n\t\t\treturn this.fileUploader.send();\n\t\t} );\n\t}\n\n\tabort() {\n\t\tthis.fileUploader.abort();\n\t}\n}\n\n// Store the API in static property to easily overwrite it in tests.\n// Too bad dependency injection does not work in Webpack + ES 6 (const) + Babel.\nCloudServicesUploadAdapter._UploadGateway = UploadGateway;\n","/**\n * @license Copyright (c) 2003-2020, 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 cloud-services-core/uploadgateway/uploadgateway\n */\n\nimport FileUploader from './fileuploader';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * UploadGateway abstracts file uploads to CKEditor Cloud Services.\n */\nexport default class UploadGateway {\n\t/**\n\t * Creates `UploadGateway` instance.\n\t *\n\t * @param {module:cloud-services-core/token~Token} token Token used for authentication.\n\t * @param {String} apiAddress API address.\n\t */\n\tconstructor( token, apiAddress ) {\n\t\tif ( !token ) {\n\t\t\t/**\n\t\t\t * Token must be provided.\n\t\t\t *\n\t\t\t * @error uploadgateway-missing-token\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'uploadgateway-missing-token: Token must be provided.', null );\n\t\t}\n\n\t\tif ( !apiAddress ) {\n\t\t\t/**\n\t\t\t * Api address must be provided.\n\t\t\t *\n\t\t\t * @error uploadgateway-missing-api-address\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'uploadgateway-missing-api-address: Api address must be provided.', null );\n\t\t}\n\n\t\t/**\n\t\t * CKEditor Cloud Services access token.\n\t\t *\n\t\t * @type {module:cloud-services-core/token~Token}\n\t\t * @private\n\t\t */\n\t\tthis._token = token;\n\n\t\t/**\n\t\t * CKEditor Cloud Services API address.\n\t\t *\n\t\t * @type {String}\n\t\t * @private\n\t\t */\n\t\tthis._apiAddress = apiAddress;\n\t}\n\n\t/**\n\t * Creates a {@link module:cloud-services-core/uploadgateway/fileuploader~FileUploader} instance that wraps\n\t * file upload process. The file is being sent at a time when the\n\t * {@link module:cloud-services-core/uploadgateway/fileuploader~FileUploader#send} method is called.\n\t *\n\t * const token = await Token.create( 'https://token-endpoint' );\n\t * new UploadGateway( token, 'https://example.org' )\n\t * .upload( 'FILE' )\n\t * .onProgress( ( data ) => console.log( data ) )\n\t * .send()\n\t * .then( ( response ) => console.log( response ) );\n\t *\n\t * @param {Blob|String} fileOrData A blob object or a data string encoded with Base64.\n\t * @returns {module:cloud-services-core/uploadgateway/fileuploader~FileUploader} Returns `FileUploader` instance.\n\t */\n\tupload( fileOrData ) {\n\t\treturn new FileUploader( fileOrData, this._token, this._apiAddress );\n\t}\n}\n\n","/**\n * @license Copyright (c) 2003-2020, 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 engine/view/observer/mouseobserver\n */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * Mouse events observer.\n *\n * Note that this observer is not available by default. To make it available it needs to be added to\n * {@link module:engine/view/view~View} by {@link module:engine/view/view~View#addObserver} method.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class MouseObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = 'mousedown';\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired when mouse button is pressed down on one of the editables.\n *\n * Introduced by {@link module:engine/view/observer/mouseobserver~MouseObserver}.\n *\n * Note that this event is not available by default. To make it available {@link module:engine/view/observer/mouseobserver~MouseObserver}\n * needs to be added to {@link module:engine/view/view~View} by a {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:engine/view/observer/mouseobserver~MouseObserver\n * @event module:engine/view/document~Document#event:mousedown\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 widget/widget\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport MouseObserver from '@ckeditor/ckeditor5-engine/src/view/observer/mouseobserver';\nimport { getLabel, isWidget, WIDGET_SELECTED_CLASS_NAME } from './utils';\nimport { getCode, keyCodes, parseKeystroke } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\nimport '../theme/widget.css';\n\nconst selectAllKeystrokeCode = parseKeystroke( 'Ctrl+A' );\n\n/**\n * The widget plugin. It enables base support for widgets.\n *\n * See {@glink api/widget package page} for more details and documentation.\n *\n * This plugin enables multiple behaviors required by widgets:\n *\n * * The model to view selection converter for the editing pipeline (it handles widget custom selection rendering).\n * If a converted selection wraps around a widget element, that selection is marked as\n * {@link module:engine/view/selection~Selection#isFake fake}. Additionally, the `ck-widget_selected` CSS class\n * is added to indicate that widget has been selected.\n * * The mouse and keyboard events handling on and around widget elements.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Widget extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Widget';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst view = this.editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t/**\n\t\t * Holds previously selected widgets.\n\t\t *\n\t\t * @private\n\t\t * @type {Set.<module:engine/view/element~Element>}\n\t\t */\n\t\tthis._previouslySelected = new Set();\n\n\t\t// Model to view selection converter.\n\t\t// Converts selection placed over widget element to fake selection\n\t\tthis.editor.editing.downcastDispatcher.on( 'selection', ( evt, data, conversionApi ) => {\n\t\t\t// Remove selected class from previously selected widgets.\n\t\t\tthis._clearPreviouslySelectedWidgets( conversionApi.writer );\n\n\t\t\tconst viewWriter = conversionApi.writer;\n\t\t\tconst viewSelection = viewWriter.document.selection;\n\t\t\tconst selectedElement = viewSelection.getSelectedElement();\n\t\t\tlet lastMarked = null;\n\n\t\t\tfor ( const range of viewSelection.getRanges() ) {\n\t\t\t\tfor ( const value of range ) {\n\t\t\t\t\tconst node = value.item;\n\n\t\t\t\t\t// Do not mark nested widgets in selected one. See: #57.\n\t\t\t\t\tif ( isWidget( node ) && !isChild( node, lastMarked ) ) {\n\t\t\t\t\t\tviewWriter.addClass( WIDGET_SELECTED_CLASS_NAME, node );\n\n\t\t\t\t\t\tthis._previouslySelected.add( node );\n\t\t\t\t\t\tlastMarked = node;\n\n\t\t\t\t\t\t// Check if widget is a single element selected.\n\t\t\t\t\t\tif ( node == selectedElement ) {\n\t\t\t\t\t\t\tviewWriter.setSelection( viewSelection.getRanges(), { fake: true, label: getLabel( selectedElement ) } );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\t// If mouse down is pressed on widget - create selection over whole widget.\n\t\tview.addObserver( MouseObserver );\n\t\tthis.listenTo( viewDocument, 'mousedown', ( ...args ) => this._onMousedown( ...args ) );\n\n\t\t// Handle custom keydown behaviour.\n\t\tthis.listenTo( viewDocument, 'keydown', ( ...args ) => this._onKeydown( ...args ), { priority: 'high' } );\n\n\t\t// Handle custom delete behaviour.\n\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\tif ( this._handleDelete( data.direction == 'forward' ) ) {\n\t\t\t\tdata.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:mousedown mousedown} events on widget elements.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} eventInfo\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t */\n\t_onMousedown( eventInfo, domEventData ) {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\t\tlet element = domEventData.target;\n\n\t\t// Do nothing for single or double click inside nested editable.\n\t\tif ( isInsideNestedEditable( element ) ) {\n\t\t\t// But at least triple click inside nested editable causes broken selection in Safari.\n\t\t\t// For such event, we select the entire nested editable element.\n\t\t\t// See: https://github.com/ckeditor/ckeditor5/issues/1463.\n\t\t\tif ( env.isSafari && domEventData.domEvent.detail >= 3 ) {\n\t\t\t\tconst mapper = editor.editing.mapper;\n\t\t\t\tconst modelElement = mapper.toModelElement( element );\n\n\t\t\t\tthis.editor.model.change( writer => {\n\t\t\t\t\tdomEventData.preventDefault();\n\t\t\t\t\twriter.setSelection( modelElement, 'in' );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t// If target is not a widget element - check if one of the ancestors is.\n\t\tif ( !isWidget( element ) ) {\n\t\t\telement = element.findAncestor( isWidget );\n\n\t\t\tif ( !element ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tdomEventData.preventDefault();\n\n\t\t// Focus editor if is not focused already.\n\t\tif ( !viewDocument.isFocused ) {\n\t\t\tview.focus();\n\t\t}\n\n\t\t// Create model selection over widget.\n\t\tconst modelElement = editor.editing.mapper.toModelElement( element );\n\n\t\tthis._setSelectionOverElement( modelElement );\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:keydown keydown} events.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} eventInfo\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t */\n\t_onKeydown( eventInfo, domEventData ) {\n\t\tconst keyCode = domEventData.keyCode;\n\t\tconst isLtrContent = this.editor.locale.contentLanguageDirection === 'ltr';\n\t\tconst isForward = keyCode == keyCodes.arrowdown || keyCode == keyCodes[ isLtrContent ? 'arrowright' : 'arrowleft' ];\n\t\tlet wasHandled = false;\n\n\t\t// Checks if the keys were handled and then prevents the default event behaviour and stops\n\t\t// the propagation.\n\t\tif ( isArrowKeyCode( keyCode ) ) {\n\t\t\twasHandled = this._handleArrowKeys( isForward );\n\t\t} else if ( isSelectAllKeyCode( domEventData ) ) {\n\t\t\twasHandled = this._selectAllNestedEditableContent() || this._selectAllContent();\n\t\t} else if ( keyCode === keyCodes.enter ) {\n\t\t\twasHandled = this._handleEnterKey( domEventData.shiftKey );\n\t\t}\n\n\t\tif ( wasHandled ) {\n\t\t\tdomEventData.preventDefault();\n\t\t\teventInfo.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Handles delete keys: backspace and delete.\n\t *\n\t * @private\n\t * @param {Boolean} isForward Set to true if delete was performed in forward direction.\n\t * @returns {Boolean|undefined} Returns `true` if keys were handled correctly.\n\t */\n\t_handleDelete( isForward ) {\n\t\t// Do nothing when the read only mode is enabled.\n\t\tif ( this.editor.isReadOnly ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelDocument = this.editor.model.document;\n\t\tconst modelSelection = modelDocument.selection;\n\n\t\t// Do nothing on non-collapsed selection.\n\t\tif ( !modelSelection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst objectElement = this._getObjectElementNextToSelection( isForward );\n\n\t\tif ( objectElement ) {\n\t\t\tthis.editor.model.change( writer => {\n\t\t\t\tlet previousNode = modelSelection.anchor.parent;\n\n\t\t\t\t// Remove previous element if empty.\n\t\t\t\twhile ( previousNode.isEmpty ) {\n\t\t\t\t\tconst nodeToRemove = previousNode;\n\t\t\t\t\tpreviousNode = nodeToRemove.parent;\n\n\t\t\t\t\twriter.remove( nodeToRemove );\n\t\t\t\t}\n\n\t\t\t\tthis._setSelectionOverElement( objectElement );\n\t\t\t} );\n\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Handles arrow keys.\n\t *\n\t * @private\n\t * @param {Boolean} isForward Set to true if arrow key should be handled in forward direction.\n\t * @returns {Boolean|undefined} Returns `true` if keys were handled correctly.\n\t */\n\t_handleArrowKeys( isForward ) {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst modelDocument = model.document;\n\t\tconst modelSelection = modelDocument.selection;\n\t\tconst objectElement = modelSelection.getSelectedElement();\n\n\t\t// If object element is selected.\n\t\tif ( objectElement && schema.isObject( objectElement ) ) {\n\t\t\tconst position = isForward ? modelSelection.getLastPosition() : modelSelection.getFirstPosition();\n\t\t\tconst newRange = schema.getNearestSelectionRange( position, isForward ? 'forward' : 'backward' );\n\n\t\t\tif ( newRange ) {\n\t\t\t\tmodel.change( writer => {\n\t\t\t\t\twriter.setSelection( newRange );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\t// If selection is next to object element.\n\t\t// Return if not collapsed.\n\t\tif ( !modelSelection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst objectElement2 = this._getObjectElementNextToSelection( isForward );\n\n\t\tif ( !!objectElement2 && schema.isObject( objectElement2 ) ) {\n\t\t\tthis._setSelectionOverElement( objectElement2 );\n\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Handles the enter key, giving users and access to positions in the editable directly before\n\t * (<kbd>Shift</kbd>+<kbd>Enter</kbd>) or after (<kbd>Enter</kbd>) the selected widget.\n\t * It improves the UX, mainly when the widget is the first or last child of the root editable\n\t * and there's no other way to type after or before it.\n\t *\n\t * @private\n\t * @param {Boolean} isBackwards Set to true if the new paragraph is to be inserted before\n\t * the selected widget (<kbd>Shift</kbd>+<kbd>Enter</kbd>).\n\t * @returns {Boolean|undefined} Returns `true` if keys were handled correctly.\n\t */\n\t_handleEnterKey( isBackwards ) {\n\t\tconst model = this.editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst selectedElement = modelSelection.getSelectedElement();\n\n\t\tif ( shouldInsertParagraph( selectedElement, model.schema ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\tlet position = writer.createPositionAt( selectedElement, isBackwards ? 'before' : 'after' );\n\t\t\t\tconst paragraph = writer.createElement( 'paragraph' );\n\n\t\t\t\t// Split the parent when inside a block element.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5/issues/1529\n\t\t\t\tif ( model.schema.isBlock( selectedElement.parent ) ) {\n\t\t\t\t\tconst paragraphLimit = model.schema.findAllowedParent( position, paragraph );\n\n\t\t\t\t\tposition = writer.split( position, paragraphLimit ).position;\n\t\t\t\t}\n\n\t\t\t\twriter.insert( paragraph, position );\n\t\t\t\twriter.setSelection( paragraph, 'in' );\n\t\t\t} );\n\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Extends the {@link module:engine/model/selection~Selection document's selection} to span the entire\n\t * content of the nested editable if already anchored in one.\n\t *\n\t * See: {@link module:engine/model/schema~Schema#getLimitElement}.\n\t *\n\t * @private\n\t */\n\t_selectAllNestedEditableContent() {\n\t\tconst model = this.editor.model;\n\t\tconst documentSelection = model.document.selection;\n\t\tconst limitElement = model.schema.getLimitElement( documentSelection );\n\n\t\tif ( documentSelection.getFirstRange().root == limitElement ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\twriter.setSelection( writer.createRangeIn( limitElement ) );\n\t\t} );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Handles <kbd>CTRL + A</kbd> when widget is selected.\n\t *\n\t * @private\n\t * @returns {Boolean} Returns true if widget was selected and selecting all was handled by this method.\n\t */\n\t_selectAllContent() {\n\t\tconst model = this.editor.model;\n\t\tconst editing = this.editor.editing;\n\t\tconst view = editing.view;\n\t\tconst viewDocument = view.document;\n\t\tconst viewSelection = viewDocument.selection;\n\n\t\tconst selectedElement = viewSelection.getSelectedElement();\n\n\t\t// Only widget is selected.\n\t\t// https://github.com/ckeditor/ckeditor5-widget/issues/23\n\t\tif ( selectedElement && isWidget( selectedElement ) ) {\n\t\t\tconst widgetParent = editing.mapper.toModelElement( selectedElement.parent );\n\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( writer.createRangeIn( widgetParent ) );\n\t\t\t} );\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Sets {@link module:engine/model/selection~Selection document's selection} over given element.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} element\n\t */\n\t_setSelectionOverElement( element ) {\n\t\tthis.editor.model.change( writer => {\n\t\t\twriter.setSelection( writer.createRangeOn( element ) );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks if {@link module:engine/model/element~Element element} placed next to the current\n\t * {@link module:engine/model/selection~Selection model selection} exists and is marked in\n\t * {@link module:engine/model/schema~Schema schema} as `object`.\n\t *\n\t * @private\n\t * @param {Boolean} forward Direction of checking.\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\t_getObjectElementNextToSelection( forward ) {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst modelSelection = model.document.selection;\n\n\t\t// Clone current selection to use it as a probe. We must leave default selection as it is so it can return\n\t\t// to its current state after undo.\n\t\tconst probe = model.createSelection( modelSelection );\n\t\tmodel.modifySelection( probe, { direction: forward ? 'forward' : 'backward' } );\n\t\tconst objectElement = forward ? probe.focus.nodeBefore : probe.focus.nodeAfter;\n\n\t\tif ( !!objectElement && schema.isObject( objectElement ) ) {\n\t\t\treturn objectElement;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Removes CSS class from previously selected widgets.\n\t *\n\t * @private\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\t_clearPreviouslySelectedWidgets( writer ) {\n\t\tfor ( const widget of this._previouslySelected ) {\n\t\t\twriter.removeClass( WIDGET_SELECTED_CLASS_NAME, widget );\n\t\t}\n\n\t\tthis._previouslySelected.clear();\n\t}\n}\n\n// Returns 'true' if provided key code represents one of the arrow keys.\n//\n// @param {Number} keyCode\n// @returns {Boolean}\nfunction isArrowKeyCode( keyCode ) {\n\treturn keyCode == keyCodes.arrowright ||\n\t\tkeyCode == keyCodes.arrowleft ||\n\t\tkeyCode == keyCodes.arrowup ||\n\t\tkeyCode == keyCodes.arrowdown;\n}\n\n// Returns 'true' if provided (DOM) key event data corresponds with the Ctrl+A keystroke.\n//\n// @param {module:engine/view/observer/keyobserver~KeyEventData} domEventData\n// @returns {Boolean}\nfunction isSelectAllKeyCode( domEventData ) {\n\treturn getCode( domEventData ) == selectAllKeystrokeCode;\n}\n\n// Returns `true` when element is a nested editable or is placed inside one.\n//\n// @param {module:engine/view/element~Element}\n// @returns {Boolean}\nfunction isInsideNestedEditable( element ) {\n\twhile ( element ) {\n\t\tif ( element.is( 'editableElement' ) && !element.is( 'rootElement' ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Click on nested widget should select it.\n\t\tif ( isWidget( element ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\telement = element.parent;\n\t}\n\n\treturn false;\n}\n\n// Checks whether the specified `element` is a child of the `parent` element.\n//\n// @param {module:engine/view/element~Element} element An element to check.\n// @param {module:engine/view/element~Element|null} parent A parent for the element.\n// @returns {Boolean}\nfunction isChild( element, parent ) {\n\tif ( !parent ) {\n\t\treturn false;\n\t}\n\n\treturn Array.from( element.getAncestors() ).includes( parent );\n}\n\n// Checks if enter key should insert paragraph. This should be done only on elements of type object (excluding inline objects).\n//\n// @param {module:engine/model/element~Element} element And element to check.\n// @param {module:engine/model/schema~Schema} schema\nfunction shouldInsertParagraph( element, schema ) {\n\treturn element && schema.isObject( element ) && !schema.isInline( element );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 image/imagetextalternative/imagetextalternativecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { isImage } from '../image/utils';\n\n/**\n * The image text alternative command. It is used to change the `alt` attribute of `<image>` elements.\n *\n * @extends module:core/command~Command\n */\nexport default class ImageTextAlternativeCommand extends Command {\n\t/**\n\t * The command value: `false` if there is no `alt` attribute, otherwise the value of the `alt` attribute.\n\t *\n\t * @readonly\n\t * @observable\n\t * @member {String|Boolean} #value\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst element = this.editor.model.document.selection.getSelectedElement();\n\n\t\tthis.isEnabled = isImage( element );\n\n\t\tif ( isImage( element ) && element.hasAttribute( 'alt' ) ) {\n\t\t\tthis.value = element.getAttribute( 'alt' );\n\t\t} else {\n\t\t\tthis.value = false;\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t * @param {Object} options\n\t * @param {String} options.newValue The new value of the `alt` attribute to set.\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\t\tconst imageElement = model.document.selection.getSelectedElement();\n\n\t\tmodel.change( writer => {\n\t\t\twriter.setAttribute( 'alt', options.newValue, imageElement );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 image/imagetextalternative/imagetextalternativeediting\n */\n\nimport ImageTextAlternativeCommand from './imagetextalternativecommand';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * The image text alternative editing plugin.\n *\n * Registers the `'imageTextAlternative'` command.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageTextAlternativeEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageTextAlternativeEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tthis.editor.commands.add( 'imageTextAlternative', new ImageTextAlternativeCommand( this.editor ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/labeledinput/labeledinputview\n */\n\nimport View from '../view';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\nimport LabelView from '../label/labelview';\nimport '../../theme/components/labeledinput/labeledinput.css';\n\n/**\n * The labeled input view class.\n *\n * @extends module:ui/view~View\n */\nexport default class LabeledInputView extends View {\n\t/**\n\t * Creates an instance of the labeled input view class.\n\t *\n\t * @param {module:utils/locale~Locale} locale The locale instance.\n\t * @param {Function} InputView Constructor of the input view.\n\t */\n\tconstructor( locale, InputView ) {\n\t\tsuper( locale );\n\n\t\tconst inputUid = `ck-input-${ uid() }`;\n\t\tconst statusUid = `ck-status-${ uid() }`;\n\n\t\t/**\n\t\t * The text of the label.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #label\n\t\t */\n\t\tthis.set( 'label' );\n\n\t\t/**\n\t\t * The value of the input.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #value\n\t\t */\n\t\tthis.set( 'value' );\n\n\t\t/**\n\t\t * Controls whether the component is in read-only mode.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * The validation error text. When set, it will be displayed\n\t\t * next to the {@link #inputView} as a typical validation error message.\n\t\t * Set it to `null` to hide the message.\n\t\t *\n\t\t * **Note:** Setting this property to anything but `null` will automatically\n\t\t * make the {@link module:ui/inputtext/inputtextview~InputTextView#hasError `hasError`}\n\t\t * of the {@link #inputView} `true`.\n\t\t *\n\t\t * **Note:** Typing in the {@link #inputView} which fires the\n\t\t * {@link module:ui/inputtext/inputtextview~InputTextView#event:input `input` event}\n\t\t * resets this property back to `null`, indicating that the input field can be re–validated.\n\t\t *\n\t\t * @observable\n\t\t * @member {String|null} #errorText\n\t\t */\n\t\tthis.set( 'errorText', null );\n\n\t\t/**\n\t\t * The additional information text displayed next to the {@link #inputView} which can\n\t\t * be used to inform the user about the purpose of the input, provide help or hints.\n\t\t *\n\t\t * Set it to `null` to hide the message.\n\t\t *\n\t\t * **Note:** This text will be displayed in the same place as {@link #errorText} but the\n\t\t * latter always takes precedence: if the {@link #errorText} is set, it replaces\n\t\t * {@link #errorText} for as long as the value of the input is invalid.\n\t\t *\n\t\t * @observable\n\t\t * @member {String|null} #infoText\n\t\t */\n\t\tthis.set( 'infoText', null );\n\n\t\t/**\n\t\t * The label view.\n\t\t *\n\t\t * @member {module:ui/label/labelview~LabelView} #labelView\n\t\t */\n\t\tthis.labelView = this._createLabelView( inputUid );\n\n\t\t/**\n\t\t * The input view.\n\t\t *\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView} #inputView\n\t\t */\n\t\tthis.inputView = this._createInputView( InputView, inputUid, statusUid );\n\n\t\t/**\n\t\t * The status view for the {@link #inputView}. It displays {@link #errorText} and\n\t\t * {@link #infoText}.\n\t\t *\n\t\t * @member {module:ui/view~View} #statusView\n\t\t */\n\t\tthis.statusView = this._createStatusView( statusUid );\n\n\t\t/**\n\t\t * The combined status text made of {@link #errorText} and {@link #infoText}.\n\t\t * Note that when present, {@link #errorText} always takes precedence in the\n\t\t * status.\n\t\t *\n\t\t * @see #errorText\n\t\t * @see #infoText\n\t\t * @see #statusView\n\t\t * @private\n\t\t * @observable\n\t\t * @member {String|null} #_statusText\n\t\t */\n\t\tthis.bind( '_statusText' ).to(\n\t\t\tthis, 'errorText',\n\t\t\tthis, 'infoText',\n\t\t\t( errorText, infoText ) => errorText || infoText\n\t\t);\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-labeled-input',\n\t\t\t\t\tbind.if( 'isReadOnly', 'ck-disabled' )\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\tthis.labelView,\n\t\t\t\tthis.inputView,\n\t\t\t\tthis.statusView\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * Creates label view class instance and bind with view.\n\t *\n\t * @private\n\t * @param {String} id Unique id to set as labelView#for attribute.\n\t * @returns {module:ui/label/labelview~LabelView}\n\t */\n\t_createLabelView( id ) {\n\t\tconst labelView = new LabelView( this.locale );\n\n\t\tlabelView.for = id;\n\t\tlabelView.bind( 'text' ).to( this, 'label' );\n\n\t\treturn labelView;\n\t}\n\n\t/**\n\t * Creates input view class instance and bind with view.\n\t *\n\t * @private\n\t * @param {Function} InputView Input view constructor.\n\t * @param {String} inputUid Unique id to set as inputView#id attribute.\n\t * @param {String} statusUid Unique id of the status for the input's `aria-describedby` attribute.\n\t * @returns {module:ui/inputtext/inputtextview~InputTextView}\n\t */\n\t_createInputView( InputView, inputUid, statusUid ) {\n\t\tconst inputView = new InputView( this.locale, statusUid );\n\n\t\tinputView.id = inputUid;\n\t\tinputView.ariaDescribedById = statusUid;\n\t\tinputView.bind( 'value' ).to( this );\n\t\tinputView.bind( 'isReadOnly' ).to( this );\n\t\tinputView.bind( 'hasError' ).to( this, 'errorText', value => !!value );\n\n\t\tinputView.on( 'input', () => {\n\t\t\t// UX: Make the error text disappear and disable the error indicator as the user\n\t\t\t// starts fixing the errors.\n\t\t\tthis.errorText = null;\n\t\t} );\n\n\t\treturn inputView;\n\t}\n\n\t/**\n\t * Creates the status view instance. It displays {@link #errorText} and {@link #infoText}\n\t * next to the {@link #inputView}. See {@link #_statusText}.\n\t *\n\t * @private\n\t * @param {String} statusUid Unique id of the status, shared with the input's `aria-describedby` attribute.\n\t * @returns {module:ui/view~View}\n\t */\n\t_createStatusView( statusUid ) {\n\t\tconst statusView = new View( this.locale );\n\t\tconst bind = this.bindTemplate;\n\n\t\tstatusView.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-labeled-input__status',\n\t\t\t\t\tbind.if( 'errorText', 'ck-labeled-input__status_error' ),\n\t\t\t\t\tbind.if( '_statusText', 'ck-hidden', value => !value )\n\t\t\t\t],\n\t\t\t\tid: statusUid,\n\t\t\t\trole: bind.if( 'errorText', 'alert' )\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: bind.to( '_statusText' )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn statusView;\n\t}\n\n\t/**\n\t * Moves the focus to the input and selects the value.\n\t */\n\tselect() {\n\t\tthis.inputView.select();\n\t}\n\n\t/**\n\t * Focuses the input.\n\t */\n\tfocus() {\n\t\tthis.inputView.focus();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/inputtext/inputtextview\n */\n\nimport View from '../view';\nimport '../../theme/components/inputtext/inputtext.css';\n\n/**\n * The text input view class.\n *\n * @extends module:ui/view~View\n */\nexport default class InputTextView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The value of the input.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #value\n\t\t */\n\t\tthis.set( 'value' );\n\n\t\t/**\n\t\t * The `id` attribute of the input (i.e. to pair with a `<label>` element).\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #id\n\t\t */\n\t\tthis.set( 'id' );\n\n\t\t/**\n\t\t * The `placeholder` attribute of the input.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #placeholder\n\t\t */\n\t\tthis.set( 'placeholder' );\n\n\t\t/**\n\t\t * Controls whether the input view is in read-only mode.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * Set to `true` when the field has some error. Usually controlled via\n\t\t * {@link module:ui/labeledinput/labeledinputview~LabeledInputView#errorText}.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #hasError\n\t\t */\n\t\tthis.set( 'hasError', false );\n\n\t\t/**\n\t\t * The `id` of the element describing this field, e.g. when it has\n\t\t * some error, it helps screen readers read the error text.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #ariaDescribedById\n\t\t */\n\t\tthis.set( 'ariaDescribedById' );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'input',\n\t\t\tattributes: {\n\t\t\t\ttype: 'text',\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-input',\n\t\t\t\t\t'ck-input-text',\n\t\t\t\t\tbind.if( 'hasError', 'ck-error' )\n\t\t\t\t],\n\t\t\t\tid: bind.to( 'id' ),\n\t\t\t\tplaceholder: bind.to( 'placeholder' ),\n\t\t\t\treadonly: bind.to( 'isReadOnly' ),\n\t\t\t\t'aria-invalid': bind.if( 'hasError', true ),\n\t\t\t\t'aria-describedby': bind.to( 'ariaDescribedById' )\n\t\t\t},\n\t\t\ton: {\n\t\t\t\tinput: bind.to( 'input' )\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * Fired when the user types in the input. Corresponds to the native\n\t\t * DOM `input` event.\n\t\t *\n\t\t * @event input\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tconst setValue = value => {\n\t\t\tthis.element.value = ( !value && value !== 0 ) ? '' : value;\n\t\t};\n\n\t\tsetValue( this.value );\n\n\t\t// Bind `this.value` to the DOM element's value.\n\t\t// We cannot use `value` DOM attribute because removing it on Edge does not clear the DOM element's value property.\n\t\tthis.on( 'change:value', ( evt, name, value ) => {\n\t\t\tsetValue( value );\n\t\t} );\n\t}\n\n\t/**\n\t * Moves the focus to the input and selects the value.\n\t */\n\tselect() {\n\t\tthis.element.select();\n\t}\n\n\t/**\n\t * Focuses the input.\n\t */\n\tfocus() {\n\t\tthis.element.focus();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/bindings/submithandler\n */\n\n/**\n * A handler useful for {@link module:ui/view~View views} working as HTML forms. It intercepts a native DOM\n * `submit` event, prevents the default web browser behavior (navigation and page reload) and\n * fires the `submit` event on a view instead. Such a custom event can be then used by any\n * {@link module:utils/dom/emittermixin~Emitter emitter}, e.g. to serialize the form data.\n *\n *\t\timport submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';\n *\n *\t\t// ...\n *\n *\t\tclass AnyFormView extends View {\n *\t\t\tconstructor() {\n *\t\t\t\tsuper();\n *\n *\t\t\t\t// ...\n *\n *\t\t\t\tsubmitHandler( {\n *\t\t\t\t\tview: this\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n *\n *\t\t// ...\n *\n *\t\tconst view = new AnyFormView();\n *\n *\t\t// A sample listener attached by an emitter working with the view.\n *\t\tthis.listenTo( view, 'submit', () => {\n *\t\t\tsaveTheFormData();\n *\t\t\thideTheForm();\n *\t\t} );\n *\n * @param {Object} [options] Configuration options.\n * @param {module:ui/view~View} options.view The view which DOM `submit` events should be handled.\n */\nexport default function submitHandler( { view } ) {\n\tview.listenTo( view.element, 'submit', ( evt, domEvt ) => {\n\t\tdomEvt.preventDefault();\n\t\tview.fire( 'submit' );\n\t}, { useCapture: true } );\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M6.972 16.615a.997.997 0 01-.744-.292l-4.596-4.596a1 1 0 111.414-1.414l3.926 3.926 9.937-9.937a1 1 0 011.414 1.415L7.717 16.323a.997.997 0 01-.745.292z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.591 10.177l4.243 4.242a1 1 0 01-1.415 1.415l-4.242-4.243-4.243 4.243a1 1 0 01-1.414-1.415l4.243-4.242L4.52 5.934A1 1 0 015.934 4.52l4.243 4.243 4.242-4.243a1 1 0 111.415 1.414l-4.243 4.243z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module image/imagetextalternative/ui/textalternativeformview\n */\nimport View from '@ckeditor/ckeditor5-ui/src/view';\nimport ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport LabeledInputView from '@ckeditor/ckeditor5-ui/src/labeledinput/labeledinputview';\nimport InputTextView from '@ckeditor/ckeditor5-ui/src/inputtext/inputtextview';\nimport submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';\nimport checkIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/check.svg';\nimport cancelIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/cancel.svg';\nimport '../../../theme/textalternativeform.css';\n/**\n * The TextAlternativeFormView class.\n *\n * @extends module:ui/view~View\n */\nexport default class TextAlternativeFormView extends View {\n /**\n\t * @inheritDoc\n\t */\n constructor(locale) {\n super(locale);\n const t = this.locale.t;\n /**\n\t\t * Tracks information about the DOM focus in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n this.focusTracker = new FocusTracker();\n /**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n this.keystrokes = new KeystrokeHandler();\n /**\n\t\t * A textarea with a label.\n\t\t *\n\t\t * @member {module:ui/labeledinput/labeledinputview~LabeledInputView} #labeledTextarea\n\t\t */\n this.labeledInput = this._createLabeledInputView();\n /**\n\t\t * A button used to submit the form.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView} #saveButtonView\n\t\t */\n this.saveButtonView = this._createButton(t('cf'), checkIcon, 'ck-button-save');\n this.saveButtonView.type = 'submit';\n /**\n\t\t * A button used to cancel the form.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView} #cancelButtonView\n\t\t */\n this.cancelButtonView = this._createButton(t('cg'), cancelIcon, 'ck-button-cancel', 'cancel');\n /**\n\t\t * A collection of views which can be focused in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this._focusables = new ViewCollection();\n /**\n\t\t * Helps cycling over {@link #_focusables} in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n this._focusCycler = new FocusCycler({\n focusables: this._focusables,\n focusTracker: this.focusTracker,\n keystrokeHandler: this.keystrokes,\n actions: {\n // Navigate form fields backwards using the Shift + Tab keystroke.\n focusPrevious: 'shift + tab',\n // Navigate form fields forwards using the Tab key.\n focusNext: 'tab'\n }\n });\n this.setTemplate({\n tag: 'form',\n attributes: {\n class: [\n 'ck',\n 'ck-text-alternative-form'\n ],\n // https://github.com/ckeditor/ckeditor5-image/issues/40\n tabindex: '-1'\n },\n children: [\n this.labeledInput,\n this.saveButtonView,\n this.cancelButtonView\n ]\n });\n }\n /**\n\t * @inheritDoc\n\t */\n render() {\n super.render();\n this.keystrokes.listenTo(this.element);\n submitHandler({ view: this });\n [\n this.labeledInput,\n this.saveButtonView,\n this.cancelButtonView\n ].forEach(v => {\n // Register the view as focusable.\n this._focusables.add(v);\n // Register the view in the focus tracker.\n this.focusTracker.add(v.element);\n });\n }\n /**\n\t * Creates the button view.\n\t *\n\t * @private\n\t * @param {String} label The button label\n\t * @param {String} icon The button's icon.\n\t * @param {String} className The additional button CSS class name.\n\t * @param {String} [eventName] The event name that the ButtonView#execute event will be delegated to.\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n _createButton(label, icon, className, eventName) {\n const button = new ButtonView(this.locale);\n button.set({\n label,\n icon,\n tooltip: true\n });\n button.extendTemplate({ attributes: { class: className } });\n if (eventName) {\n button.delegate('execute').to(this, eventName);\n }\n return button;\n }\n /**\n\t * Creates an input with a label.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledinput/labeledinputview~LabeledInputView}\n\t */\n _createLabeledInputView() {\n const t = this.locale.t;\n const labeledInput = new LabeledInputView(this.locale, InputTextView);\n labeledInput.label = t('cl');\n labeledInput.inputView.placeholder = t('cl');\n return labeledInput;\n }\n}","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/panel/balloon/balloonpanelview\n */\n\nimport View from '../../view';\nimport { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';\nimport isRange from '@ckeditor/ckeditor5-utils/src/dom/isrange';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport { isElement } from 'lodash-es';\n\nimport '../../../theme/components/panel/balloonpanel.css';\n\nconst toPx = toUnit( 'px' );\nconst defaultLimiterElement = global.document.body;\n\n/**\n * The balloon panel view class.\n *\n * A floating container which can\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#pin pin} to any\n * {@link module:utils/dom/position~Options#target target} in the DOM and remain in that position\n * e.g. when the web page is scrolled.\n *\n * The balloon panel can be used to display contextual, non-blocking UI like forms, toolbars and\n * the like in its {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#content} view\n * collection.\n *\n * There is a number of {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}\n * that the balloon can use, automatically switching from one to another when the viewport space becomes\n * scarce to keep the balloon visible to the user as long as it is possible. The balloon will also\n * accept any custom position set provided by the user compatible with the\n * {@link module:utils/dom/position~Options options}.\n *\n *\t\tconst panel = new BalloonPanelView( locale );\n *\t\tconst childView = new ChildView();\n *\t\tconst positions = BalloonPanelView.defaultPositions;\n *\n *\t\tpanel.render();\n *\n *\t\t// Add a child view to the panel's content collection.\n *\t\tpanel.content.add( childView );\n *\n *\t\t// Start pinning the panel to an element with the \"target\" id DOM.\n *\t\t// The balloon will remain pinned until unpin() is called.\n *\t\tpanel.pin( {\n *\t\t\ttarget: document.querySelector( '#target' ),\n *\t\t\tpositions: [\n *\t\t\t\tpositions.northArrowSouth,\n *\t\t\t\tpositions.southArrowNorth\n *\t\t\t]\n *\t\t} );\n *\n * @extends module:ui/view~View\n */\nexport default class BalloonPanelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * The absolute top position of the balloon panel in pixels.\n\t\t *\n\t\t * @observable\n\t\t * @default 0\n\t\t * @member {Number} #top\n\t\t */\n\t\tthis.set( 'top', 0 );\n\n\t\t/**\n\t\t * The absolute left position of the balloon panel in pixels.\n\t\t *\n\t\t * @observable\n\t\t * @default 0\n\t\t * @member {Number} #left\n\t\t */\n\t\tthis.set( 'left', 0 );\n\n\t\t/**\n\t\t * The balloon panel's current position. The position name is reflected in the CSS class set\n\t\t * to the balloon, i.e. `.ck-balloon-panel_arrow_nw` for the \"arrow_nw\" position. The class\n\t\t * controls the minor aspects of the balloon's visual appearance like the placement\n\t\t * of an {@link #withArrow arrow}. To support a new position, an additional CSS must be created.\n\t\t *\n\t\t * Default position names correspond with\n\t\t * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\n\t\t *\n\t\t * See the {@link #attachTo} and {@link #pin} methods to learn about custom balloon positions.\n\t\t *\n\t\t * @observable\n\t\t * @default 'arrow_nw'\n\t\t * @member {'arrow_nw'|'arrow_ne'|'arrow_sw'|'arrow_se'} #position\n\t\t */\n\t\tthis.set( 'position', 'arrow_nw' );\n\n\t\t/**\n\t\t * Controls whether the balloon panel is visible or not.\n\t\t *\n\t\t * @observable\n\t\t * @default false\n\t\t * @member {Boolean} #isVisible\n\t\t */\n\t\tthis.set( 'isVisible', false );\n\n\t\t/**\n\t\t * Controls whether the balloon panel has an arrow. The presence of the arrow\n\t\t * is reflected in the `ck-balloon-panel_with-arrow` CSS class.\n\t\t *\n\t\t * @observable\n\t\t * @default true\n\t\t * @member {Boolean} #withArrow\n\t\t */\n\t\tthis.set( 'withArrow', true );\n\n\t\t/**\n\t\t * An additional CSS class added to the {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class' );\n\n\t\t/**\n\t\t * A callback that starts pinning the panel when {@link #isVisible} gets\n\t\t * `true`. Used by {@link #pin}.\n\t\t *\n\t\t * @private\n\t\t * @member {Function} #_pinWhenIsVisibleCallback\n\t\t */\n\n\t\t/**\n\t\t * A collection of the child views that creates the balloon panel contents.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.content = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-balloon-panel',\n\t\t\t\t\tbind.to( 'position', value => `ck-balloon-panel_${ value }` ),\n\t\t\t\t\tbind.if( 'isVisible', 'ck-balloon-panel_visible' ),\n\t\t\t\t\tbind.if( 'withArrow', 'ck-balloon-panel_with-arrow' ),\n\t\t\t\t\tbind.to( 'class' )\n\t\t\t\t],\n\n\t\t\t\tstyle: {\n\t\t\t\t\ttop: bind.to( 'top', toPx ),\n\t\t\t\t\tleft: bind.to( 'left', toPx )\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tchildren: this.content\n\t\t} );\n\t}\n\n\t/**\n\t * Shows the panel.\n\t *\n\t * See {@link #isVisible}.\n\t */\n\tshow() {\n\t\tthis.isVisible = true;\n\t}\n\n\t/**\n\t * Hides the panel.\n\t *\n\t * See {@link #isVisible}.\n\t */\n\thide() {\n\t\tthis.isVisible = false;\n\t}\n\n\t/**\n\t * Attaches the panel to a specified {@link module:utils/dom/position~Options#target} with a\n\t * smart positioning heuristics that chooses from available positions to make sure the panel\n\t * is visible to the user i.e. within the limits of the viewport.\n\t *\n\t * This method accepts configuration {@link module:utils/dom/position~Options options}\n\t * to set the `target`, optional `limiter` and `positions` the balloon should choose from.\n\t *\n\t *\t\tconst panel = new BalloonPanelView( locale );\n\t *\t\tconst positions = BalloonPanelView.defaultPositions;\n\t *\n\t *\t\tpanel.render();\n\t *\n\t *\t\t// Attach the panel to an element with the \"target\" id DOM.\n\t *\t\tpanel.attachTo( {\n\t *\t\t\ttarget: document.querySelector( '#target' ),\n\t *\t\t\tpositions: [\n\t *\t\t\t\tpositions.northArrowSouth,\n\t *\t\t\t\tpositions.southArrowNorth\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t * **Note**: Attaching the panel will also automatically {@link #show} it.\n\t *\n\t * **Note**: An attached panel will not follow its target when the window is scrolled or resized.\n\t * See the {@link #pin} method for a more permanent positioning strategy.\n\t *\n\t * @param {module:utils/dom/position~Options} options Positioning options compatible with\n\t * {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is\n\t * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\n\t */\n\tattachTo( options ) {\n\t\tthis.show();\n\n\t\tconst defaultPositions = BalloonPanelView.defaultPositions;\n\t\tconst positionOptions = Object.assign( {}, {\n\t\t\telement: this.element,\n\t\t\tpositions: [\n\t\t\t\tdefaultPositions.southArrowNorth,\n\t\t\t\tdefaultPositions.southArrowNorthWest,\n\t\t\t\tdefaultPositions.southArrowNorthEast,\n\t\t\t\tdefaultPositions.northArrowSouth,\n\t\t\t\tdefaultPositions.northArrowSouthWest,\n\t\t\t\tdefaultPositions.northArrowSouthEast\n\t\t\t],\n\t\t\tlimiter: defaultLimiterElement,\n\t\t\tfitInViewport: true\n\t\t}, options );\n\n\t\tconst optimalPosition = BalloonPanelView._getOptimalPosition( positionOptions );\n\n\t\t// Usually browsers make some problems with super accurate values like 104.345px\n\t\t// so it is better to use int values.\n\t\tconst left = parseInt( optimalPosition.left );\n\t\tconst top = parseInt( optimalPosition.top );\n\t\tconst position = optimalPosition.name;\n\n\t\tObject.assign( this, { top, left, position } );\n\t}\n\n\t/**\n\t * Works the same way as the {@link #attachTo} method except that the position of the panel is\n\t * continuously updated when:\n\t *\n\t * * any ancestor of the {@link module:utils/dom/position~Options#target}\n\t * or {@link module:utils/dom/position~Options#limiter} is scrolled,\n\t * * the browser window gets resized or scrolled.\n\t *\n\t * Thanks to that, the panel always sticks to the {@link module:utils/dom/position~Options#target}\n\t * and is immune to the changing environment.\n\t *\n\t *\t\tconst panel = new BalloonPanelView( locale );\n\t *\t\tconst positions = BalloonPanelView.defaultPositions;\n\t *\n\t *\t\tpanel.render();\n\t *\n\t *\t\t// Pin the panel to an element with the \"target\" id DOM.\n\t *\t\tpanel.pin( {\n\t *\t\t\ttarget: document.querySelector( '#target' ),\n\t *\t\t\tpositions: [\n\t *\t\t\t\tpositions.northArrowSouth,\n\t *\t\t\t\tpositions.southArrowNorth\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t * To leave the pinned state, use the {@link #unpin} method.\n\t *\n\t * **Note**: Pinning the panel will also automatically {@link #show} it.\n\t *\n\t * @param {module:utils/dom/position~Options} options Positioning options compatible with\n\t * {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is\n\t * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\n\t */\n\tpin( options ) {\n\t\tthis.unpin();\n\n\t\tthis._pinWhenIsVisibleCallback = () => {\n\t\t\tif ( this.isVisible ) {\n\t\t\t\tthis._startPinning( options );\n\t\t\t} else {\n\t\t\t\tthis._stopPinning();\n\t\t\t}\n\t\t};\n\n\t\tthis._startPinning( options );\n\n\t\t// Control the state of the listeners depending on whether the panel is visible\n\t\t// or not.\n\t\t// TODO: Use on() (https://github.com/ckeditor/ckeditor5-utils/issues/144).\n\t\tthis.listenTo( this, 'change:isVisible', this._pinWhenIsVisibleCallback );\n\t}\n\n\t/**\n\t * Stops pinning the panel, as set up by {@link #pin}.\n\t */\n\tunpin() {\n\t\tif ( this._pinWhenIsVisibleCallback ) {\n\t\t\t// Deactivate listeners attached by pin().\n\t\t\tthis._stopPinning();\n\n\t\t\t// Deactivate the panel pin() control logic.\n\t\t\t// TODO: Use off() (https://github.com/ckeditor/ckeditor5-utils/issues/144).\n\t\t\tthis.stopListening( this, 'change:isVisible', this._pinWhenIsVisibleCallback );\n\n\t\t\tthis._pinWhenIsVisibleCallback = null;\n\n\t\t\tthis.hide();\n\t\t}\n\t}\n\n\t/**\n\t * Starts managing the pinned state of the panel. See {@link #pin}.\n\t *\n\t * @private\n\t * @param {module:utils/dom/position~Options} options Positioning options compatible with\n\t * {@link module:utils/dom/position~getOptimalPosition}.\n\t */\n\t_startPinning( options ) {\n\t\tthis.attachTo( options );\n\n\t\tconst targetElement = getDomElement( options.target );\n\t\tconst limiterElement = options.limiter ? getDomElement( options.limiter ) : defaultLimiterElement;\n\n\t\t// Then we need to listen on scroll event of eny element in the document.\n\t\tthis.listenTo( global.document, 'scroll', ( evt, domEvt ) => {\n\t\t\tconst scrollTarget = domEvt.target;\n\n\t\t\t// The position needs to be updated if the positioning target is within the scrolled element.\n\t\t\tconst isWithinScrollTarget = targetElement && scrollTarget.contains( targetElement );\n\n\t\t\t// The position needs to be updated if the positioning limiter is within the scrolled element.\n\t\t\tconst isLimiterWithinScrollTarget = limiterElement && scrollTarget.contains( limiterElement );\n\n\t\t\t// The positioning target and/or limiter can be a Rect, object etc..\n\t\t\t// There's no way to optimize the listener then.\n\t\t\tif ( isWithinScrollTarget || isLimiterWithinScrollTarget || !targetElement || !limiterElement ) {\n\t\t\t\tthis.attachTo( options );\n\t\t\t}\n\t\t}, { useCapture: true } );\n\n\t\t// We need to listen on window resize event and update position.\n\t\tthis.listenTo( global.window, 'resize', () => {\n\t\t\tthis.attachTo( options );\n\t\t} );\n\t}\n\n\t/**\n\t * Stops managing the pinned state of the panel. See {@link #pin}.\n\t *\n\t * @private\n\t */\n\t_stopPinning() {\n\t\tthis.stopListening( global.document, 'scroll' );\n\t\tthis.stopListening( global.window, 'resize' );\n\t}\n}\n\n// Returns the DOM element for given object or null, if there is none,\n// e.g. when the passed object is a Rect instance or so.\n//\n// @private\n// @param {*} object\n// @returns {HTMLElement|null}\nfunction getDomElement( object ) {\n\tif ( isElement( object ) ) {\n\t\treturn object;\n\t}\n\n\tif ( isRange( object ) ) {\n\t\treturn object.commonAncestorContainer;\n\t}\n\n\tif ( typeof object == 'function' ) {\n\t\treturn getDomElement( object() );\n\t}\n\n\treturn null;\n}\n\n/**\n * A horizontal offset of the arrow tip from the edge of the balloon. Controlled by CSS.\n *\n *\t\t +-----|---------...\n *\t\t | |\n *\t\t | |\n *\t\t | |\n *\t\t | |\n *\t\t +--+ | +------...\n *\t\t \\ | /\n *\t\t \\|/\n *\t >|-----|<---------------- horizontal offset\n *\n * @default 30\n * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowHorizontalOffset\n */\nBalloonPanelView.arrowHorizontalOffset = 25;\n\n/**\n * A vertical offset of the arrow from the edge of the balloon. Controlled by CSS.\n *\n *\t\t +-------------...\n *\t\t |\n *\t\t |\n *\t\t | /-- vertical offset\n *\t\t | V\n *\t\t +--+ +-----... ---------\n *\t\t \\ / |\n *\t\t \\/ |\n *\t\t-------------------------------\n *\t\t ^\n *\n * @default 15\n * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowVerticalOffset\n */\nBalloonPanelView.arrowVerticalOffset = 10;\n\n/**\n * Function used to calculate the optimal position for the balloon.\n *\n * @protected\n * @member {Function} module:ui/panel/balloon/balloonpanelview~BalloonPanelView._getOptimalPosition\n */\nBalloonPanelView._getOptimalPosition = getOptimalPosition;\n\n/**\n * A default set of positioning functions used by the balloon panel view\n * when attaching using the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo} method.\n *\n * The available positioning functions are as follows:\n *\n * **North**\n *\n * * `northArrowSouth`\n *\n * \t\t+-----------------+\n * \t\t| Balloon |\n * \t\t+-----------------+\n * \t\t V\n * \t\t [ Target ]\n *\n * * `northArrowSouthEast`\n *\n * \t\t+-----------------+\n * \t\t| Balloon |\n * \t\t+-----------------+\n * \t\t V\n * \t\t [ Target ]\n *\n * * `northArrowSouthWest`\n *\n * \t\t +-----------------+\n * \t\t | Balloon |\n * \t\t +-----------------+\n * \t\t V\n * \t\t[ Target ]\n *\n * **North west**\n *\n * * `northWestArrowSouth`\n *\n * \t\t+-----------------+\n * \t\t| Balloon |\n * \t\t+-----------------+\n * \t\t V\n * \t\t [ Target ]\n *\n * * `northWestArrowSouthWest`\n *\n * \t\t+-----------------+\n * \t\t| Balloon |\n * \t\t+-----------------+\n * \t\t V\n * \t\t [ Target ]\n *\n * * `northWestArrowSouthEast`\n *\n * \t\t+-----------------+\n * \t\t| Balloon |\n * \t\t+-----------------+\n * \t\t V\n * \t\t [ Target ]\n *\n * **North east**\n *\n * * `northEastArrowSouth`\n *\n * \t\t+-----------------+\n * \t\t| Balloon |\n * \t\t+-----------------+\n * \t\t V\n * \t\t[ Target ]\n *\n * * `northEastArrowSouthEast`\n *\n * \t\t+-----------------+\n * \t\t| Balloon |\n * \t\t+-----------------+\n * \t\t V\n * \t\t [ Target ]\n *\n * * `northEastArrowSouthWest`\n *\n * \t\t +-----------------+\n * \t\t | Balloon |\n * \t\t +-----------------+\n * \t\t V\n * \t\t[ Target ]\n *\n * **South**\n *\n * * `southArrowNorth`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southArrowNorthEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southArrowNorthWest`\n *\n *\t\t[ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * **South west**\n *\n * * `southWestArrowNorth`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southWestArrowNorthWest`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southWestArrowNorthEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * **South east**\n *\n * * `southEastArrowNorth`\n *\n *\t\t[ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southEastArrowNorthEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southEastArrowNorthWest`\n *\n *\t\t[ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * See {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo}.\n *\n * Positioning functions must be compatible with {@link module:utils/dom/position~Position}.\n *\n * The name that the position function returns will be reflected in the balloon panel's class that\n * controls the placement of the \"arrow\". See {@link #position} to learn more.\n *\n * @member {Object} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions\n */\nBalloonPanelView.defaultPositions = {\n\t// ------- North\n\n\tnorthArrowSouth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,\n\t\tname: 'arrow_s'\n\t} ),\n\n\tnorthArrowSouthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_se'\n\t} ),\n\n\tnorthArrowSouthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sw'\n\t} ),\n\n\t// ------- North west\n\n\tnorthWestArrowSouth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width / 2,\n\t\tname: 'arrow_s'\n\t} ),\n\n\tnorthWestArrowSouthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sw'\n\t} ),\n\n\tnorthWestArrowSouthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_se'\n\t} ),\n\n\t// ------- North east\n\n\tnorthEastArrowSouth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width / 2,\n\t\tname: 'arrow_s'\n\t} ),\n\n\tnorthEastArrowSouthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_se'\n\t} ),\n\n\tnorthEastArrowSouthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sw'\n\t} ),\n\n\t// ------- South\n\n\tsouthArrowNorth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,\n\t\tname: 'arrow_n'\n\t} ),\n\n\tsouthArrowNorthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_ne'\n\t} ),\n\n\tsouthArrowNorthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nw'\n\t} ),\n\n\t// ------- South west\n\n\tsouthWestArrowNorth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width / 2,\n\t\tname: 'arrow_n'\n\t} ),\n\n\tsouthWestArrowNorthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nw'\n\t} ),\n\n\tsouthWestArrowNorthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_ne'\n\t} ),\n\n\t// ------- South east\n\n\tsouthEastArrowNorth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width / 2,\n\t\tname: 'arrow_n'\n\t} ),\n\n\tsouthEastArrowNorthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_ne'\n\t} ),\n\n\tsouthEastArrowNorthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nw'\n\t} ),\n};\n\n// Returns the top coordinate for positions starting with `north*`.\n//\n// @private\n// @param {utils/dom/rect~Rect} targetRect A rect of the target.\n// @param {utils/dom/rect~Rect} elementRect A rect of the balloon.\n// @returns {Number}\nfunction getNorthTop( targetRect, balloonRect ) {\n\treturn targetRect.top - balloonRect.height - BalloonPanelView.arrowVerticalOffset;\n}\n\n// Returns the top coordinate for positions starting with `south*`.\n//\n// @private\n// @param {utils/dom/rect~Rect} targetRect A rect of the target.\n// @param {utils/dom/rect~Rect} elementRect A rect of the balloon.\n// @returns {Number}\nfunction getSouthTop( targetRect ) {\n\treturn targetRect.bottom + BalloonPanelView.arrowVerticalOffset;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module ui/panel/balloon/contextualballoon\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport BalloonPanelView from './balloonpanelview';\nimport View from '../../view';\nimport ButtonView from '../../button/buttonview';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\nimport prevIcon from '../../../theme/assets/icons/previous-arrow.svg';\nimport nextIcon from '../../../theme/assets/icons/next-arrow.svg';\nimport '../../../theme/components/panel/balloonrotator.css';\nimport '../../../theme/components/panel/fakepanel.css';\nconst toPx = toUnit('px');\n/**\n * Provides the common contextual balloon for the editor.\n *\n * The role of this plugin is to unify the contextual balloons logic, simplify views management and help\n * avoid the unnecessary complexity of handling multiple {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n * instances in the editor.\n *\n * This plugin allows for creating single or multiple panel stacks.\n *\n * Each stack may have multiple views, with the one on the top being visible. When the visible view is removed from the stack,\n * the previous view becomes visible.\n *\n * It might be useful to implement nested navigation in a balloon. For instance, a toolbar view may contain a link button.\n * When you click it, a link view (which lets you set the URL) is created and put on top of the toolbar view, so the link panel\n * is displayed. When you finish editing the link and close (remove) the link view, the toolbar view is visible again.\n *\n * However, there are cases when there are multiple independent balloons to be displayed, for instance, if the selection\n * is inside two inline comments at the same time. For such cases, you can create two independent panel stacks.\n * The contextual balloon plugin will create a navigation bar to let the users switch between these panel stacks using the \"Next\"\n * and \"Previous\" buttons.\n *\n * If there are no views in the current stack, the balloon panel will try to switch to the next stack. If there are no\n * panels in any stack, the balloon panel will be hidden.\n *\n * **Note**: To force the balloon panel to show only one view, even if there are other stacks, use the `singleViewMode=true` option\n * when {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon#add adding} a view to a panel.\n *\n * From the implementation point of view, the contextual ballon plugin is reusing a single\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView} instance to display multiple contextual balloon\n * panels in the editor. It also creates a special {@link module:ui/panel/balloon/contextualballoon~RotatorView rotator view},\n * used to manage multiple panel stacks. Rotator view is a child of the balloon panel view and the parent of the specific\n * view you want to display. If there is more than one panel stack to be displayed, the rotator view will add a\n * navigation bar. If there is only one stack, the rotator view is transparent (it does not add any UI elements).\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ContextualBalloon extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'ContextualBalloon';\n }\n /**\n\t * @inheritDoc\n\t */\n constructor(editor) {\n super(editor);\n /**\n\t\t * The {@link module:utils/dom/position~Options#limiter position limiter}\n\t\t * for the {@link #view balloon}, used when no `limiter` has been passed into {@link #add}\n\t\t * or {@link #updatePosition}.\n\t\t *\n\t\t * By default, a function that obtains the farthest DOM\n\t\t * {@link module:engine/view/rooteditableelement~RootEditableElement}\n\t\t * of the {@link module:engine/view/document~Document#selection}.\n\t\t *\n\t\t * @member {module:utils/dom/position~Options#limiter} #positionLimiter\n\t\t */\n this.positionLimiter = () => {\n const view = this.editor.editing.view;\n const viewDocument = view.document;\n const editableElement = viewDocument.selection.editableElement;\n if (editableElement) {\n return view.domConverter.mapViewToDom(editableElement.root);\n }\n return null;\n };\n /**\n\t\t * The currently visible view or `null` when there are no views in any stack.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {module:ui/view~View|null} #visibleView\n\t\t */\n this.set('visibleView', null);\n /**\n\t\t * The common balloon panel view.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/panel/balloon/balloonpanelview~BalloonPanelView} #view\n\t\t */\n this.view = new BalloonPanelView(editor.locale);\n editor.ui.view.body.add(this.view);\n editor.ui.focusTracker.add(this.view.element);\n /**\n\t\t * The map of views and their stacks.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<module:ui/view~View,Set>}\n\t\t */\n this._viewToStack = new Map();\n /**\n\t\t * The map of IDs and stacks.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<String,Set>}\n\t\t */\n this._idToStack = new Map();\n /**\n\t\t * A total number of all stacks in the balloon.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #_numberOfStacks\n\t\t */\n this.set('_numberOfStacks', 0);\n /**\n\t\t * A flag that controls the single view mode.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #_singleViewMode\n\t\t */\n this.set('_singleViewMode', false);\n /**\n\t\t * Rotator view embedded in the contextual balloon.\n\t\t * Displays the currently visible view in the balloon and provides navigation for switching stacks.\n\t\t *\n\t\t * @private\n\t\t * @type {module:ui/panel/balloon/contextualballoon~RotatorView}\n\t\t */\n this._rotatorView = this._createRotatorView();\n /**\n\t\t * Displays fake panels under the balloon panel view when multiple stacks are added to the balloon.\n\t\t *\n\t\t * @private\n\t\t * @type {module:ui/view~View}\n\t\t */\n this._fakePanelsView = this._createFakePanelsView();\n }\n /**\n\t * Returns `true` when the given view is in one of the stacks. Otherwise returns `false`.\n\t *\n\t * @param {module:ui/view~View} view\n\t * @returns {Boolean}\n\t */\n hasView(view) {\n return Array.from(this._viewToStack.keys()).includes(view);\n }\n /**\n\t * Adds a new view to the stack and makes it visible if the current stack is visible\n\t * or it is the first view in the balloon.\n\t *\n\t * @param {Object} data The configuration of the view.\n\t * @param {String} [data.stackId='main'] The ID of the stack that the view is added to.\n\t * @param {module:ui/view~View} [data.view] The content of the balloon.\n\t * @param {module:utils/dom/position~Options} [data.position] Positioning options.\n\t * @param {String} [data.balloonClassName] An additional CSS class added to the {@link #view balloon} when visible.\n\t * @param {Boolean} [data.withArrow=true] Whether the {@link #view balloon} should be rendered with an arrow.\n\t * @param {Boolean} [data.singleViewMode=false] Whether the view should be the only visible view even if other stacks were added.\n\t */\n add(data) {\n if (this.hasView(data.view)) {\n /**\n\t\t\t * Trying to add configuration of the same view more than once.\n\t\t\t *\n\t\t\t * @error contextualballoon-add-view-exist\n\t\t\t */\n throw new CKEditorError('contextualballoon-add-view-exist: Cannot add configuration of the same view twice.', [\n this,\n data\n ]);\n }\n const stackId = data.stackId || 'main';\n // If new stack is added, creates it and show view from this stack.\n if (!this._idToStack.has(stackId)) {\n this._idToStack.set(stackId, new Map([[\n data.view,\n data\n ]]));\n this._viewToStack.set(data.view, this._idToStack.get(stackId));\n this._numberOfStacks = this._idToStack.size;\n if (!this._visibleStack || data.singleViewMode) {\n this.showStack(stackId);\n }\n return;\n }\n const stack = this._idToStack.get(stackId);\n if (data.singleViewMode) {\n this.showStack(stackId);\n }\n // Add new view to the stack.\n stack.set(data.view, data);\n this._viewToStack.set(data.view, stack);\n // And display it if is added to the currently visible stack.\n if (stack === this._visibleStack) {\n this._showView(data);\n }\n }\n /**\n\t * Removes the given view from the stack. If the removed view was visible,\n\t * the view preceding it in the stack will become visible instead.\n\t * When there is no view in the stack, the next stack will be displayed.\n\t * When there are no more stacks, the balloon will hide.\n\t *\n\t * @param {module:ui/view~View} view A view to be removed from the balloon.\n\t */\n remove(view) {\n if (!this.hasView(view)) {\n /**\n\t\t\t * Trying to remove the configuration of the view not defined in the stack.\n\t\t\t *\n\t\t\t * @error contextualballoon-remove-view-not-exist\n\t\t\t */\n throw new CKEditorError('contextualballoon-remove-view-not-exist: Cannot remove the configuration of a non-existent view.', [\n this,\n view\n ]);\n }\n const stack = this._viewToStack.get(view);\n if (this._singleViewMode && this.visibleView === view) {\n this._singleViewMode = false;\n }\n // When visible view will be removed we need to show a preceding view or next stack\n // if a view is the only view in the stack.\n if (this.visibleView === view) {\n if (stack.size === 1) {\n if (this._idToStack.size > 1) {\n this._showNextStack();\n } else {\n this.view.hide();\n this.visibleView = null;\n this._rotatorView.hideView();\n }\n } else {\n this._showView(Array.from(stack.values())[stack.size - 2]);\n }\n }\n if (stack.size === 1) {\n this._idToStack.delete(this._getStackId(stack));\n this._numberOfStacks = this._idToStack.size;\n } else {\n stack.delete(view);\n }\n this._viewToStack.delete(view);\n }\n /**\n\t * Updates the position of the balloon using the position data of the first visible view in the stack.\n\t * When new position data is given, the position data of the currently visible view will be updated.\n\t *\n\t * @param {module:utils/dom/position~Options} [position] position options.\n\t */\n updatePosition(position) {\n if (position) {\n this._visibleStack.get(this.visibleView).position = position;\n }\n this.view.pin(this._getBalloonPosition());\n this._fakePanelsView.updatePosition();\n }\n /**\n\t * Shows the last view from the stack of a given ID.\n\t *\n\t * @param {String} id\n\t */\n showStack(id) {\n this.visibleStack = id;\n const stack = this._idToStack.get(id);\n if (!stack) {\n /**\n\t\t\t * Trying to show a stack that does not exist.\n\t\t\t *\n\t\t\t * @error contextualballoon-showstack-stack-not-exist\n\t\t\t */\n throw new CKEditorError('contextualballoon-showstack-stack-not-exist: Cannot show a stack that does not exist.', this);\n }\n if (this._visibleStack === stack) {\n return;\n }\n this._showView(Array.from(stack.values()).pop());\n }\n /**\n\t * Returns the stack of the currently visible view.\n\t *\n\t * @private\n\t * @type {Set}\n\t */\n get _visibleStack() {\n return this._viewToStack.get(this.visibleView);\n }\n /**\n\t * Returns the ID of the given stack.\n\t *\n\t * @private\n\t * @param {Set} stack\n\t * @returns {String}\n\t */\n _getStackId(stack) {\n const entry = Array.from(this._idToStack.entries()).find(entry => entry[1] === stack);\n return entry[0];\n }\n /**\n\t * Shows the last view from the next stack.\n\t *\n\t * @private\n\t */\n _showNextStack() {\n const stacks = Array.from(this._idToStack.values());\n let nextIndex = stacks.indexOf(this._visibleStack) + 1;\n if (!stacks[nextIndex]) {\n nextIndex = 0;\n }\n this.showStack(this._getStackId(stacks[nextIndex]));\n }\n /**\n\t * Shows the last view from the previous stack.\n\t *\n\t * @private\n\t */\n _showPrevStack() {\n const stacks = Array.from(this._idToStack.values());\n let nextIndex = stacks.indexOf(this._visibleStack) - 1;\n if (!stacks[nextIndex]) {\n nextIndex = stacks.length - 1;\n }\n this.showStack(this._getStackId(stacks[nextIndex]));\n }\n /**\n\t * Creates a rotator view.\n\t *\n\t * @private\n\t * @returns {module:ui/panel/balloon/contextualballoon~RotatorView}\n\t */\n _createRotatorView() {\n const view = new RotatorView(this.editor.locale);\n const t = this.editor.locale.t;\n this.view.content.add(view);\n // Hide navigation when there is only a one stack & not in single view mode.\n view.bind('isNavigationVisible').to(this, '_numberOfStacks', this, '_singleViewMode', (value, isSingleViewMode) => {\n return !isSingleViewMode && value > 1;\n });\n // Update balloon position after toggling navigation.\n view.on('change:isNavigationVisible', () => this.updatePosition(), { priority: 'low' });\n // Update stacks counter value.\n view.bind('counter').to(this, 'visibleView', this, '_numberOfStacks', (visibleView, numberOfStacks) => {\n if (numberOfStacks < 2) {\n return '';\n }\n const current = Array.from(this._idToStack.values()).indexOf(this._visibleStack) + 1;\n return t('cm', [\n current,\n numberOfStacks\n ]);\n });\n view.buttonNextView.on('execute', () => {\n // When current view has a focus then move focus to the editable before removing it,\n // otherwise editor will lost focus.\n if (view.focusTracker.isFocused) {\n this.editor.editing.view.focus();\n }\n this._showNextStack();\n });\n view.buttonPrevView.on('execute', () => {\n // When current view has a focus then move focus to the editable before removing it,\n // otherwise editor will lost focus.\n if (view.focusTracker.isFocused) {\n this.editor.editing.view.focus();\n }\n this._showPrevStack();\n });\n return view;\n }\n /**\n\t * @returns {module:ui/view~View}\n\t */\n _createFakePanelsView() {\n const view = new FakePanelsView(this.editor.locale, this.view);\n view.bind('numberOfPanels').to(this, '_numberOfStacks', this, '_singleViewMode', (number, isSingleViewMode) => {\n const showPanels = !isSingleViewMode && number >= 2;\n return showPanels ? Math.min(number - 1, 2) : 0;\n });\n view.listenTo(this.view, 'change:top', () => view.updatePosition());\n view.listenTo(this.view, 'change:left', () => view.updatePosition());\n this.editor.ui.view.body.add(view);\n return view;\n }\n /**\n\t * Sets the view as the content of the balloon and attaches the balloon using position\n\t * options of the first view.\n\t *\n\t * @private\n\t * @param {Object} data Configuration.\n\t * @param {module:ui/view~View} [data.view] The view to show in the balloon.\n\t * @param {String} [data.balloonClassName=''] Additional class name which will be added to the {@link #view balloon}.\n\t * @param {Boolean} [data.withArrow=true] Whether the {@link #view balloon} should be rendered with an arrow.\n\t */\n _showView({view, balloonClassName = '', withArrow = true, singleViewMode = false}) {\n this.view.class = balloonClassName;\n this.view.withArrow = withArrow;\n this._rotatorView.showView(view);\n this.visibleView = view;\n this.view.pin(this._getBalloonPosition());\n this._fakePanelsView.updatePosition();\n if (singleViewMode) {\n this._singleViewMode = true;\n }\n }\n /**\n\t * Returns position options of the last view in the stack.\n\t * This keeps the balloon in the same position when the view is changed.\n\t *\n\t * @private\n\t * @returns {module:utils/dom/position~Options}\n\t */\n _getBalloonPosition() {\n let position = Array.from(this._visibleStack.values()).pop().position;\n // Use the default limiter if none has been specified.\n if (position && !position.limiter) {\n // Don't modify the original options object.\n position = Object.assign({}, position, { limiter: this.positionLimiter });\n }\n return position;\n }\n}\n/**\n * Rotator view is a helper class for the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon ContextualBalloon}.\n * It is used for displaying the last view from the current stack and providing navigation buttons for switching stacks.\n * See the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon ContextualBalloon} documentation to learn more.\n *\n * @extends module:ui/view~View\n */\nclass RotatorView extends View {\n /**\n\t * @inheritDoc\n\t */\n constructor(locale) {\n super(locale);\n const t = locale.t;\n const bind = this.bindTemplate;\n /**\n\t\t * Defines whether navigation is visible or not.\n\t\t *\n\t\t * @member {Boolean} #isNavigationVisible\n\t\t */\n this.set('isNavigationVisible', true);\n /**\n\t\t * Used for checking if a view is focused or not.\n\t\t *\n\t\t * @type {module:utils/focustracker~FocusTracker}\n\t\t */\n this.focusTracker = new FocusTracker();\n /**\n\t\t * Navigation button for switching the stack to the previous one.\n\t\t *\n\t\t * @type {module:ui/button/buttonview~ButtonView}\n\t\t */\n this.buttonPrevView = this._createButtonView(t('cn'), prevIcon);\n /**\n\t\t * Navigation button for switching the stack to the next one.\n\t\t *\n\t\t * @type {module:ui/button/buttonview~ButtonView}\n\t\t */\n this.buttonNextView = this._createButtonView(t('co'), nextIcon);\n /**\n\t\t * A collection of the child views that creates the rotator content.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n this.content = this.createCollection();\n this.setTemplate({\n tag: 'div',\n attributes: {\n class: [\n 'ck',\n 'ck-balloon-rotator'\n ],\n 'z-index': '-1'\n },\n children: [\n {\n tag: 'div',\n attributes: {\n class: [\n 'ck-balloon-rotator__navigation',\n bind.to('isNavigationVisible', value => value ? '' : 'ck-hidden')\n ]\n },\n children: [\n this.buttonPrevView,\n {\n tag: 'span',\n attributes: { class: ['ck-balloon-rotator__counter'] },\n children: [{ text: bind.to('counter') }]\n },\n this.buttonNextView\n ]\n },\n {\n tag: 'div',\n attributes: { class: 'ck-balloon-rotator__content' },\n children: this.content\n }\n ]\n });\n }\n /**\n\t * @inheritDoc\n\t */\n render() {\n super.render();\n this.focusTracker.add(this.element);\n }\n /**\n\t * Shows a given view.\n\t *\n\t * @param {module:ui/view~View} view The view to show.\n\t */\n showView(view) {\n this.hideView();\n this.content.add(view);\n }\n /**\n\t * Hides the currently displayed view.\n\t */\n hideView() {\n this.content.clear();\n }\n /**\n\t * Creates a navigation button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @returns {module:ui/button/buttonview~ButtonView}\n\t */\n _createButtonView(label, icon) {\n const view = new ButtonView(this.locale);\n view.set({\n label,\n icon,\n tooltip: true\n });\n return view;\n }\n}\n// Displays additional layers under the balloon when multiple stacks are added to the balloon.\n//\n// @private\n// @extends module:ui/view~View\nclass FakePanelsView extends View {\n // @inheritDoc\n constructor(locale, balloonPanelView) {\n super(locale);\n const bind = this.bindTemplate;\n // Fake panels top offset.\n //\n // @observable\n // @member {Number} #top\n this.set('top', 0);\n // Fake panels left offset.\n //\n // @observable\n // @member {Number} #left\n this.set('left', 0);\n // Fake panels height.\n //\n // @observable\n // @member {Number} #height\n this.set('height', 0);\n // Fake panels width.\n //\n // @observable\n // @member {Number} #width\n this.set('width', 0);\n // Number of rendered fake panels.\n //\n // @observable\n // @member {Number} #numberOfPanels\n this.set('numberOfPanels', 0);\n // Collection of the child views which creates fake panel content.\n //\n // @readonly\n // @type {module:ui/viewcollection~ViewCollection}\n this.content = this.createCollection();\n // Context.\n //\n // @private\n // @type {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n this._balloonPanelView = balloonPanelView;\n this.setTemplate({\n tag: 'div',\n attributes: {\n class: [\n 'ck-fake-panel',\n bind.to('numberOfPanels', number => number ? '' : 'ck-hidden')\n ],\n style: {\n top: bind.to('top', toPx),\n left: bind.to('left', toPx),\n width: bind.to('width', toPx),\n height: bind.to('height', toPx)\n }\n },\n children: this.content\n });\n this.on('change:numberOfPanels', (evt, name, next, prev) => {\n if (next > prev) {\n this._addPanels(next - prev);\n } else {\n this._removePanels(prev - next);\n }\n this.updatePosition();\n });\n }\n // @private\n // @param {Number} number\n _addPanels(number) {\n while (number--) {\n const view = new View();\n view.setTemplate({ tag: 'div' });\n this.content.add(view);\n this.registerChild(view);\n }\n }\n // @private\n // @param {Number} number\n _removePanels(number) {\n while (number--) {\n const view = this.content.last;\n this.content.remove(view);\n this.deregisterChild(view);\n view.destroy();\n }\n }\n // Updates coordinates of fake panels.\n updatePosition() {\n if (this.numberOfPanels) {\n const {top, left} = this._balloonPanelView;\n const {width, height} = new Rect(this._balloonPanelView.element);\n Object.assign(this, {\n top,\n left,\n width,\n height\n });\n }\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.463 5.187a.888.888 0 111.254 1.255L9.16 10l3.557 3.557a.888.888 0 11-1.254 1.255L7.26 10.61a.888.888 0 01.16-1.382l4.043-4.042z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M8.537 14.813a.888.888 0 11-1.254-1.255L10.84 10 7.283 6.442a.888.888 0 111.254-1.255L12.74 9.39a.888.888 0 01-.16 1.382l-4.043 4.042z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 image/image/ui/utils\n */\n\nimport BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview';\nimport { getSelectedImageWidget } from '../utils';\n\n/**\n * A helper utility that positions the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} instance\n * with respect to the image in the editor content, if one is selected.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n */\nexport function repositionContextualBalloon( editor ) {\n\tconst balloon = editor.plugins.get( 'ContextualBalloon' );\n\n\tif ( getSelectedImageWidget( editor.editing.view.document.selection ) ) {\n\t\tconst position = getBalloonPositionData( editor );\n\n\t\tballoon.updatePosition( position );\n\t}\n}\n\n/**\n * Returns the positioning options that control the geometry of the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} with respect\n * to the selected element in the editor content.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @returns {module:utils/dom/position~Options}\n */\nexport function getBalloonPositionData( editor ) {\n\tconst editingView = editor.editing.view;\n\tconst defaultPositions = BalloonPanelView.defaultPositions;\n\n\treturn {\n\t\ttarget: editingView.domConverter.viewToDom( editingView.document.selection.getSelectedElement() ),\n\t\tpositions: [\n\t\t\tdefaultPositions.northArrowSouth,\n\t\t\tdefaultPositions.northArrowSouthWest,\n\t\t\tdefaultPositions.northArrowSouthEast,\n\t\t\tdefaultPositions.southArrowNorth,\n\t\t\tdefaultPositions.southArrowNorthWest,\n\t\t\tdefaultPositions.southArrowNorthEast\n\t\t]\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module image/imagetextalternative/imagetextalternativeui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler';\nimport TextAlternativeFormView from './ui/textalternativeformview';\nimport ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';\nimport textAlternativeIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/low-vision.svg';\nimport {\n repositionContextualBalloon,\n getBalloonPositionData\n} from '../image/ui/utils';\nimport { getSelectedImageWidget } from '../image/utils';\n/**\n * The image text alternative UI plugin.\n *\n * The plugin uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageTextAlternativeUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get requires() {\n return [ContextualBalloon];\n }\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'ImageTextAlternativeUI';\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n this._createButton();\n this._createForm();\n }\n /**\n\t * @inheritDoc\n\t */\n destroy() {\n super.destroy();\n // Destroy created UI components as they are not automatically destroyed (see ckeditor5#1341).\n this._form.destroy();\n }\n /**\n\t * Creates a button showing the balloon panel for changing the image text alternative and\n\t * registers it in the editor {@link module:ui/componentfactory~ComponentFactory ComponentFactory}.\n\t *\n\t * @private\n\t */\n _createButton() {\n const editor = this.editor;\n const t = editor.t;\n editor.ui.componentFactory.add('imageTextAlternative', locale => {\n const command = editor.commands.get('imageTextAlternative');\n const view = new ButtonView(locale);\n view.set({\n label: t('bi'),\n icon: textAlternativeIcon,\n tooltip: true\n });\n view.bind('isEnabled').to(command, 'isEnabled');\n this.listenTo(view, 'execute', () => {\n this._showForm();\n });\n return view;\n });\n }\n /**\n\t * Creates the {@link module:image/imagetextalternative/ui/textalternativeformview~TextAlternativeFormView}\n\t * form.\n\t *\n\t * @private\n\t */\n _createForm() {\n const editor = this.editor;\n const view = editor.editing.view;\n const viewDocument = view.document;\n /**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n this._balloon = this.editor.plugins.get('ContextualBalloon');\n /**\n\t\t * A form containing a textarea and buttons, used to change the `alt` text value.\n\t\t *\n\t\t * @member {module:image/imagetextalternative/ui/textalternativeformview~TextAlternativeFormView}\n\t\t */\n this._form = new TextAlternativeFormView(editor.locale);\n // Render the form so its #element is available for clickOutsideHandler.\n this._form.render();\n this.listenTo(this._form, 'submit', () => {\n editor.execute('imageTextAlternative', { newValue: this._form.labeledInput.inputView.element.value });\n this._hideForm(true);\n });\n this.listenTo(this._form, 'cancel', () => {\n this._hideForm(true);\n });\n // Close the form on Esc key press.\n this._form.keystrokes.set('Esc', (data, cancel) => {\n this._hideForm(true);\n cancel();\n });\n // Reposition the balloon or hide the form if an image widget is no longer selected.\n this.listenTo(editor.ui, 'update', () => {\n if (!getSelectedImageWidget(viewDocument.selection)) {\n this._hideForm(true);\n } else if (this._isVisible) {\n repositionContextualBalloon(editor);\n }\n });\n // Close on click outside of balloon panel element.\n clickOutsideHandler({\n emitter: this._form,\n activator: () => this._isVisible,\n contextElements: [this._balloon.view.element],\n callback: () => this._hideForm()\n });\n }\n /**\n\t * Shows the {@link #_form} in the {@link #_balloon}.\n\t *\n\t * @private\n\t */\n _showForm() {\n if (this._isVisible) {\n return;\n }\n const editor = this.editor;\n const command = editor.commands.get('imageTextAlternative');\n const labeledInput = this._form.labeledInput;\n if (!this._isInBalloon) {\n this._balloon.add({\n view: this._form,\n position: getBalloonPositionData(editor)\n });\n }\n // Make sure that each time the panel shows up, the field remains in sync with the value of\n // the command. If the user typed in the input, then canceled the balloon (`labeledInput#value`\n // stays unaltered) and re-opened it without changing the value of the command, they would see the\n // old value instead of the actual value of the command.\n // https://github.com/ckeditor/ckeditor5-image/issues/114\n labeledInput.value = labeledInput.inputView.element.value = command.value || '';\n this._form.labeledInput.select();\n }\n /**\n\t * Removes the {@link #_form} from the {@link #_balloon}.\n\t *\n\t * @param {Boolean} [focusEditable=false] Controls whether the editing view is focused afterwards.\n\t * @private\n\t */\n _hideForm(focusEditable) {\n if (!this._isInBalloon) {\n return;\n }\n // Blur the input element before removing it from DOM to prevent issues in some browsers.\n // See https://github.com/ckeditor/ckeditor5/issues/1501.\n if (this._form.focusTracker.isFocused) {\n this._form.saveButtonView.focus();\n }\n this._balloon.remove(this._form);\n if (focusEditable) {\n this.editor.editing.view.focus();\n }\n }\n /**\n\t * Returns `true` when the {@link #_form} is the visible view in the {@link #_balloon}.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n get _isVisible() {\n return this._balloon.visibleView === this._form;\n }\n /**\n\t * Returns `true` when the {@link #_form} is in the {@link #_balloon}.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n get _isInBalloon() {\n return this._balloon.hasView(this._form);\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M5.085 6.22L2.943 4.078a.75.75 0 111.06-1.06l2.592 2.59A11.094 11.094 0 0110 5.068c4.738 0 8.578 3.101 8.578 5.083 0 1.197-1.401 2.803-3.555 3.887l1.714 1.713a.75.75 0 01-.09 1.138.488.488 0 01-.15.084.75.75 0 01-.821-.16L6.17 7.304c-.258.11-.51.233-.757.365l6.239 6.24-.006.005.78.78c-.388.094-.78.166-1.174.215l-1.11-1.11h.011L4.55 8.197a7.2 7.2 0 00-.665.514l-.112.098 4.897 4.897-.005.006 1.276 1.276a10.164 10.164 0 01-1.477-.117l-.479-.479-.009.009-4.863-4.863-.022.031a2.563 2.563 0 00-.124.2c-.043.077-.08.158-.108.241a.534.534 0 00-.028.133.29.29 0 00.008.072.927.927 0 00.082.226c.067.133.145.26.234.379l3.242 3.365.025.01.59.623c-3.265-.918-5.59-3.155-5.59-4.668 0-1.194 1.448-2.838 3.663-3.93zm7.07.531a4.632 4.632 0 011.108 5.992l.345.344.046-.018a9.313 9.313 0 002-1.112c.256-.187.5-.392.727-.613.137-.134.27-.277.392-.431.072-.091.141-.185.203-.286.057-.093.107-.19.148-.292a.72.72 0 00.036-.12.29.29 0 00.008-.072.492.492 0 00-.028-.133.999.999 0 00-.036-.096 2.165 2.165 0 00-.071-.145 2.917 2.917 0 00-.125-.2 3.592 3.592 0 00-.263-.335 5.444 5.444 0 00-.53-.523 7.955 7.955 0 00-1.054-.768 9.766 9.766 0 00-1.879-.891c-.337-.118-.68-.219-1.027-.301zm-2.85.21l-.069.002a.508.508 0 00-.254.097.496.496 0 00-.104.679.498.498 0 00.326.199l.045.005c.091.003.181.003.272.012a2.45 2.45 0 012.017 1.513c.024.061.043.125.069.185a.494.494 0 00.45.287h.008a.496.496 0 00.35-.158.482.482 0 00.13-.335.638.638 0 00-.048-.219 3.379 3.379 0 00-.36-.723 3.438 3.438 0 00-2.791-1.543l-.028-.001h-.013z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 image/imagetextalternative\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageTextAlternativeEditing from './imagetextalternative/imagetextalternativeediting';\nimport ImageTextAlternativeUI from './imagetextalternative/imagetextalternativeui';\n\n/**\n * The image text alternative plugin.\n *\n * For a detailed overview, check the {@glink features/image#image-styles image styles} documentation.\n *\n * This is a \"glue\" plugin which loads the\n * {@link module:image/imagetextalternative/imagetextalternativeediting~ImageTextAlternativeEditing}\n * and {@link module:image/imagetextalternative/imagetextalternativeui~ImageTextAlternativeUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageTextAlternative extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageTextAlternativeEditing, ImageTextAlternativeUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageTextAlternative';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 image/image\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageEditing from '../src/image/imageediting';\nimport Widget from '@ckeditor/ckeditor5-widget/src/widget';\nimport ImageTextAlternative from './imagetextalternative';\n\nimport '../theme/image.css';\n\n/**\n * The image plugin.\n *\n * For a detailed overview, check the {@glink features/image image feature} documentation.\n *\n * This is a \"glue\" plugin which loads the following plugins:\n *\n * * {@link module:image/image/imageediting~ImageEditing},\n * * {@link module:image/imagetextalternative~ImageTextAlternative}.\n *\n * Usually, it is used in conjuction with other plugins from this package. See the {@glink api/image package page}\n * for more information.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Image extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageEditing, Widget, ImageTextAlternative ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Image';\n\t}\n}\n\n/**\n * The configuration of the image features. Used by the image features in the `@ckeditor/ckeditor5-image` package.\n *\n * Read more in {@link module:image/image~ImageConfig}.\n *\n * @member {module:image/image~ImageConfig} module:core/editor/editorconfig~EditorConfig#image\n */\n\n/**\n * The configuration of the image features. Used by the image features in the `@ckeditor/ckeditor5-image` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\timage: ... // Image 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 ImageConfig\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 upload/ui/filedialogbuttonview\n */\n\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport View from '@ckeditor/ckeditor5-ui/src/view';\n\n/**\n * The file dialog button view.\n *\n * This component provides a button that opens the native file selection dialog.\n * It can be used to implement the UI of a file upload feature.\n *\n *\t\tconst view = new FileDialogButtonView( locale );\n *\n *\t\tview.set( {\n *\t\t\tacceptedType: 'image/*',\n *\t\t\tallowMultipleFiles: true\n *\t\t} );\n *\n *\t\tview.buttonView.set( {\n *\t\t\tlabel: t( 'Insert image' ),\n *\t\t\ticon: imageIcon,\n *\t\t\ttooltip: true\n *\t\t} );\n *\n *\t\tview.on( 'done', ( evt, files ) => {\n *\t\t\tfor ( const file of Array.from( files ) ) {\n *\t\t\t\tconsole.log( 'Selected file', file );\n *\t\t\t}\n *\t\t} );\n *\n * @extends module:ui/view~View\n */\nexport default class FileDialogButtonView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The button view of the component.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.buttonView = new ButtonView( locale );\n\n\t\t/**\n\t\t * A hidden `<input>` view used to execute file dialog.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:upload/ui/filedialogbuttonview~FileInputView}\n\t\t */\n\t\tthis._fileInputView = new FileInputView( locale );\n\n\t\t/**\n\t\t * Accepted file types. Can be provided in form of file extensions, media type or one of:\n\t\t * * `audio/*`,\n\t\t * * `video/*`,\n\t\t * * `image/*`.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #acceptedType\n\t\t */\n\t\tthis._fileInputView.bind( 'acceptedType' ).to( this );\n\n\t\t/**\n\t\t * Indicates if multiple files can be selected. Defaults to `true`.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #allowMultipleFiles\n\t\t */\n\t\tthis._fileInputView.bind( 'allowMultipleFiles' ).to( this );\n\n\t\t/**\n\t\t * Fired when file dialog is closed with file selected.\n\t\t *\n\t\t *\t\tview.on( 'done', ( evt, files ) => {\n\t\t *\t\t\tfor ( const file of files ) {\n\t\t *\t\t\t\tconsole.log( 'Selected file', file );\n\t\t *\t\t\t}\n\t\t *\t\t}\n\t\t *\n\t\t * @event done\n\t\t * @param {Array.<File>} files Array of selected files.\n\t\t */\n\t\tthis._fileInputView.delegate( 'done' ).to( this );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-file-dialog-button',\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\tthis.buttonView,\n\t\t\t\tthis._fileInputView\n\t\t\t]\n\t\t} );\n\n\t\tthis.buttonView.on( 'execute', () => {\n\t\t\tthis._fileInputView.open();\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the {@link #buttonView}.\n\t */\n\tfocus() {\n\t\tthis.buttonView.focus();\n\t}\n}\n\n/**\n * The hidden file input view class.\n *\n * @private\n * @extends module:ui/view~View\n */\nclass FileInputView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Accepted file types. Can be provided in form of file extensions, media type or one of:\n\t\t * * `audio/*`,\n\t\t * * `video/*`,\n\t\t * * `image/*`.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #acceptedType\n\t\t */\n\t\tthis.set( 'acceptedType' );\n\n\t\t/**\n\t\t * Indicates if multiple files can be selected. Defaults to `false`.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #allowMultipleFiles\n\t\t */\n\t\tthis.set( 'allowMultipleFiles', false );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'input',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-hidden'\n\t\t\t\t],\n\t\t\t\ttype: 'file',\n\t\t\t\ttabindex: '-1',\n\t\t\t\taccept: bind.to( 'acceptedType' ),\n\t\t\t\tmultiple: bind.to( 'allowMultipleFiles' )\n\t\t\t},\n\n\t\t\ton: {\n\t\t\t\t// Removing from code coverage since we cannot programmatically set input element files.\n\t\t\t\tchange: bind.to( /* istanbul ignore next */ () => {\n\t\t\t\t\tif ( this.element && this.element.files && this.element.files.length ) {\n\t\t\t\t\t\tthis.fire( 'done', this.element.files );\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.element.value = '';\n\t\t\t\t} )\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Opens file dialog.\n\t */\n\topen() {\n\t\tthis.element.click();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 image/imageupload/utils\n */\n\n/* global fetch, File */\n\n/**\n * Creates a regular expression used to test for image files.\n *\n *\t\tconst imageType = createImageTypeRegExp( [ 'png', 'jpeg', 'svg+xml', 'vnd.microsoft.icon' ] );\n *\n *\t\tconsole.log( 'is supported image', imageType.test( file.type ) );\n *\n * @param {Array.<String>} types\n * @returns {RegExp}\n */\nexport function createImageTypeRegExp( types ) {\n\t// Sanitize the MIME type name which may include: \"+\", \"-\" or \".\".\n\tconst regExpSafeNames = types.map( type => type.replace( '+', '\\\\+' ) );\n\n\treturn new RegExp( `^image\\\\/(${ regExpSafeNames.join( '|' ) })$` );\n}\n\n/**\n * Creates a promise that fetches the image local source (Base64 or blob) and resolves with a `File` object.\n *\n * @param {module:engine/view/element~Element} image Image whose source to fetch.\n * @returns {Promise.<File>} A promise which resolves when an image source is fetched and converted to a `File` instance.\n * It resolves with a `File` object. If there were any errors during file processing, the promise will be rejected.\n */\nexport function fetchLocalImage( image ) {\n\treturn new Promise( ( resolve, reject ) => {\n\t\tconst imageSrc = image.getAttribute( 'src' );\n\n\t\t// Fetch works asynchronously and so does not block browser UI when processing data.\n\t\tfetch( imageSrc )\n\t\t\t.then( resource => resource.blob() )\n\t\t\t.then( blob => {\n\t\t\t\tconst mimeType = getImageMimeType( blob, imageSrc );\n\t\t\t\tconst ext = mimeType.replace( 'image/', '' );\n\t\t\t\tconst filename = `image.${ ext }`;\n\t\t\t\tconst file = createFileFromBlob( blob, filename, mimeType );\n\n\t\t\t\tfile ? resolve( file ) : reject();\n\t\t\t} )\n\t\t\t.catch( reject );\n\t} );\n}\n\n/**\n * Checks whether a given node is an image element with a local source (Base64 or blob).\n *\n * @param {module:engine/view/node~Node} node The node to check.\n * @returns {Boolean}\n */\nexport function isLocalImage( node ) {\n\tif ( !node.is( 'element', 'img' ) || !node.getAttribute( 'src' ) ) {\n\t\treturn false;\n\t}\n\n\treturn node.getAttribute( 'src' ).match( /^data:image\\/\\w+;base64,/g ) ||\n\t\tnode.getAttribute( 'src' ).match( /^blob:/g );\n}\n\n// Extracts an image type based on its blob representation or its source.\n//\n// @param {String} src Image `src` attribute value.\n// @param {Blob} blob Image blob representation.\n// @returns {String}\nfunction getImageMimeType( blob, src ) {\n\tif ( blob.type ) {\n\t\treturn blob.type;\n\t} else if ( src.match( /data:(image\\/\\w+);base64/ ) ) {\n\t\treturn src.match( /data:(image\\/\\w+);base64/ )[ 1 ].toLowerCase();\n\t} else {\n\t\t// Fallback to 'jpeg' as common extension.\n\t\treturn 'image/jpeg';\n\t}\n}\n\n// Creates a `File` instance from the given `Blob` instance using the specified file name.\n//\n// @param {Blob} blob The `Blob` instance from which the file will be created.\n// @param {String} filename The file name used during the file creation.\n// @param {String} mimeType The file MIME type.\n// @returns {File|null} The `File` instance created from the given blob or `null` if `File API` is not available.\nfunction createFileFromBlob( blob, filename, mimeType ) {\n\ttry {\n\t\treturn new File( [ blob ], filename, { type: mimeType } );\n\t} catch ( err ) {\n\t\t// Edge does not support `File` constructor ATM, see https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/9551546/.\n\t\t// However, the `File` function is present (so cannot be checked with `!window.File` or `typeof File === 'function'`), but\n\t\t// calling it with `new File( ... )` throws an error. This try-catch prevents that. Also when the function will\n\t\t// be implemented correctly in Edge the code will start working without any changes (see #247).\n\t\treturn null;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module image/imageupload/imageuploadui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FileDialogButtonView from '@ckeditor/ckeditor5-upload/src/ui/filedialogbuttonview';\nimport imageIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/image.svg';\nimport { createImageTypeRegExp } from './utils';\n/**\n * The image upload button plugin.\n *\n * For a detailed overview, check the {@glink features/image-upload/image-upload Image upload feature} documentation.\n *\n * Adds the `'imageUpload'` button to the {@link module:ui/componentfactory~ComponentFactory UI component factory}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageUploadUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n // Setup `imageUpload` button.\n editor.ui.componentFactory.add('imageUpload', locale => {\n const view = new FileDialogButtonView(locale);\n const command = editor.commands.get('imageUpload');\n const imageTypes = editor.config.get('image.upload.types');\n const imageTypesRegExp = createImageTypeRegExp(imageTypes);\n view.set({\n acceptedType: imageTypes.map(type => `image/${ type }`).join(','),\n allowMultipleFiles: true\n });\n view.buttonView.set({\n label: t('y'),\n icon: imageIcon,\n tooltip: true\n });\n view.buttonView.bind('isEnabled').to(command);\n view.on('done', (evt, files) => {\n const imagesToUpload = Array.from(files).filter(file => imageTypesRegExp.test(file.type));\n if (imagesToUpload.length) {\n editor.execute('imageUpload', { file: imagesToUpload });\n }\n });\n return view;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M6.91 10.54c.26-.23.64-.21.88.03l3.36 3.14 2.23-2.06a.64.64 0 01.87 0l2.52 2.97V4.5H3.2v10.12l3.71-4.08zm10.27-7.51c.6 0 1.09.47 1.09 1.05v11.84c0 .59-.49 1.06-1.09 1.06H2.79c-.6 0-1.09-.47-1.09-1.06V4.08c0-.58.49-1.05 1.1-1.05h14.38zm-5.22 5.56a1.96 1.96 0 113.4-1.96 1.96 1.96 0 01-3.4 1.96z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 image/imageupload/imageuploadprogress\n */\n\n/* globals setTimeout */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';\nimport uploadingPlaceholder from '../../theme/assets/icons/image_placeholder.svg';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\nimport '../../theme/imageuploadprogress.css';\nimport '../../theme/imageuploadicon.css';\nimport '../../theme/imageuploadloader.css';\n\n/**\n * The image upload progress plugin.\n * It shows a placeholder when the image is read from the disk and a progress bar while the image is uploading.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageUploadProgress extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The image placeholder that is displayed before real image data can be accessed.\n\t\t *\n\t\t * @protected\n\t\t * @member {String} #placeholder\n\t\t */\n\t\tthis.placeholder = 'data:image/svg+xml;utf8,' + encodeURIComponent( uploadingPlaceholder );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Upload status change - update image's view according to that status.\n\t\teditor.editing.downcastDispatcher.on( 'attribute:uploadStatus:image', ( ...args ) => this.uploadStatusChange( ...args ) );\n\t}\n\n\t/**\n\t * This method is called each time the image `uploadStatus` attribute is changed.\n\t *\n\t * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n\t */\n\tuploadStatusChange( evt, data, conversionApi ) {\n\t\tconst editor = this.editor;\n\t\tconst modelImage = data.item;\n\t\tconst uploadId = modelImage.getAttribute( 'uploadId' );\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst fileRepository = editor.plugins.get( FileRepository );\n\t\tconst status = uploadId ? data.attributeNewValue : null;\n\t\tconst placeholder = this.placeholder;\n\t\tconst viewFigure = editor.editing.mapper.toViewElement( modelImage );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\tif ( status == 'reading' ) {\n\t\t\t// Start \"appearing\" effect and show placeholder with infinite progress bar on the top\n\t\t\t// while image is read from disk.\n\t\t\t_startAppearEffect( viewFigure, viewWriter );\n\t\t\t_showPlaceholder( placeholder, viewFigure, viewWriter );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Show progress bar on the top of the image when image is uploading.\n\t\tif ( status == 'uploading' ) {\n\t\t\tconst loader = fileRepository.loaders.get( uploadId );\n\n\t\t\t// Start appear effect if needed - see https://github.com/ckeditor/ckeditor5-image/issues/191.\n\t\t\t_startAppearEffect( viewFigure, viewWriter );\n\n\t\t\tif ( !loader ) {\n\t\t\t\t// There is no loader associated with uploadId - this means that image came from external changes.\n\t\t\t\t// In such cases we still want to show the placeholder until image is fully uploaded.\n\t\t\t\t// Show placeholder if needed - see https://github.com/ckeditor/ckeditor5-image/issues/191.\n\t\t\t\t_showPlaceholder( placeholder, viewFigure, viewWriter );\n\t\t\t} else {\n\t\t\t\t// Hide placeholder and initialize progress bar showing upload progress.\n\t\t\t\t_hidePlaceholder( viewFigure, viewWriter );\n\t\t\t\t_showProgressBar( viewFigure, viewWriter, loader, editor.editing.view );\n\t\t\t\t_displayLocalImage( viewFigure, viewWriter, loader );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Because in Edge there is no way to show fancy animation of completeIcon we need to skip it.\n\t\tif ( status == 'complete' && fileRepository.loaders.get( uploadId ) && !env.isEdge ) {\n\t\t\t_showCompleteIcon( viewFigure, viewWriter, editor.editing.view );\n\t\t}\n\n\t\t// Clean up.\n\t\t_hideProgressBar( viewFigure, viewWriter );\n\t\t_hidePlaceholder( viewFigure, viewWriter );\n\t\t_stopAppearEffect( viewFigure, viewWriter );\n\t}\n}\n\n// Adds ck-appear class to the image figure if one is not already applied.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _startAppearEffect( viewFigure, writer ) {\n\tif ( !viewFigure.hasClass( 'ck-appear' ) ) {\n\t\twriter.addClass( 'ck-appear', viewFigure );\n\t}\n}\n\n// Removes ck-appear class to the image figure if one is not already removed.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _stopAppearEffect( viewFigure, writer ) {\n\twriter.removeClass( 'ck-appear', viewFigure );\n}\n\n// Shows placeholder together with infinite progress bar on given image figure.\n//\n// @param {String} Data-uri with a svg placeholder.\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _showPlaceholder( placeholder, viewFigure, writer ) {\n\tif ( !viewFigure.hasClass( 'ck-image-upload-placeholder' ) ) {\n\t\twriter.addClass( 'ck-image-upload-placeholder', viewFigure );\n\t}\n\n\tconst viewImg = viewFigure.getChild( 0 );\n\n\tif ( viewImg.getAttribute( 'src' ) !== placeholder ) {\n\t\twriter.setAttribute( 'src', placeholder, viewImg );\n\t}\n\n\tif ( !_getUIElement( viewFigure, 'placeholder' ) ) {\n\t\twriter.insert( writer.createPositionAfter( viewImg ), _createPlaceholder( writer ) );\n\t}\n}\n\n// Removes placeholder together with infinite progress bar on given image figure.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _hidePlaceholder( viewFigure, writer ) {\n\tif ( viewFigure.hasClass( 'ck-image-upload-placeholder' ) ) {\n\t\twriter.removeClass( 'ck-image-upload-placeholder', viewFigure );\n\t}\n\n\t_removeUIElement( viewFigure, writer, 'placeholder' );\n}\n\n// Shows progress bar displaying upload progress.\n// Attaches it to the file loader to update when upload percentace is changed.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:upload/filerepository~FileLoader} loader\n// @param {module:engine/view/view~View} view\nfunction _showProgressBar( viewFigure, writer, loader, view ) {\n\tconst progressBar = _createProgressBar( writer );\n\twriter.insert( writer.createPositionAt( viewFigure, 'end' ), progressBar );\n\n\t// Update progress bar width when uploadedPercent is changed.\n\tloader.on( 'change:uploadedPercent', ( evt, name, value ) => {\n\t\tview.change( writer => {\n\t\t\twriter.setStyle( 'width', value + '%', progressBar );\n\t\t} );\n\t} );\n}\n\n// Hides upload progress bar.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _hideProgressBar( viewFigure, writer ) {\n\t_removeUIElement( viewFigure, writer, 'progressBar' );\n}\n\n// Shows complete icon and hides after a certain amount of time.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:engine/view/view~View} view\nfunction _showCompleteIcon( viewFigure, writer, view ) {\n\tconst completeIcon = writer.createUIElement( 'div', { class: 'ck-image-upload-complete-icon' } );\n\n\twriter.insert( writer.createPositionAt( viewFigure, 'end' ), completeIcon );\n\n\tsetTimeout( () => {\n\t\tview.change( writer => writer.remove( writer.createRangeOn( completeIcon ) ) );\n\t}, 3000 );\n}\n\n// Create progress bar element using {@link module:engine/view/uielement~UIElement}.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {module:engine/view/uielement~UIElement}\nfunction _createProgressBar( writer ) {\n\tconst progressBar = writer.createUIElement( 'div', { class: 'ck-progress-bar' } );\n\n\twriter.setCustomProperty( 'progressBar', true, progressBar );\n\n\treturn progressBar;\n}\n\n// Create placeholder element using {@link module:engine/view/uielement~UIElement}.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {module:engine/view/uielement~UIElement}\nfunction _createPlaceholder( writer ) {\n\tconst placeholder = writer.createUIElement( 'div', { class: 'ck-upload-placeholder-loader' } );\n\n\twriter.setCustomProperty( 'placeholder', true, placeholder );\n\n\treturn placeholder;\n}\n\n// Returns {@link module:engine/view/uielement~UIElement} of given unique property from image figure element.\n// Returns `undefined` if element is not found.\n//\n// @private\n// @param {module:engine/view/element~Element} imageFigure\n// @param {String} uniqueProperty\n// @returns {module:engine/view/uielement~UIElement|undefined}\nfunction _getUIElement( imageFigure, uniqueProperty ) {\n\tfor ( const child of imageFigure.getChildren() ) {\n\t\tif ( child.getCustomProperty( uniqueProperty ) ) {\n\t\t\treturn child;\n\t\t}\n\t}\n}\n\n// Removes {@link module:engine/view/uielement~UIElement} of given unique property from image figure element.\n//\n// @private\n// @param {module:engine/view/element~Element} imageFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {String} uniqueProperty\nfunction _removeUIElement( viewFigure, writer, uniqueProperty ) {\n\tconst element = _getUIElement( viewFigure, uniqueProperty );\n\n\tif ( element ) {\n\t\twriter.remove( writer.createRangeOn( element ) );\n\t}\n}\n\n// Displays local data from file loader.\n//\n// @param {module:engine/view/element~Element} imageFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:upload/filerepository~FileLoader} loader\nfunction _displayLocalImage( viewFigure, writer, loader ) {\n\tif ( loader.data ) {\n\t\tconst viewImg = viewFigure.getChild( 0 );\n\n\t\twriter.setAttribute( 'src', loader.data, viewImg );\n\t}\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" viewBox=\\\"0 0 700 250\\\"><rect rx=\\\"4\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 module:engine/view/upcastwriter\n */\n\nimport DocumentFragment from './documentfragment';\nimport Element from './element';\nimport Text from './text';\nimport { isPlainObject } from 'lodash-es';\nimport Position from './position';\nimport Range from './range';\nimport Selection from './selection';\n\n/**\n * View upcast writer. It provides a set of methods used to manipulate non-semantic view trees.\n *\n * It should be used only while working on a non-semantic view\n * (e.g. a view created from HTML string on paste).\n * To manipulate a view which was or is being downcasted from the the model use the\n * {@link module:engine/view/downcastwriter~DowncastWriter downcast writer}.\n *\n * Read more about changing the view in the {@glink framework/guides/architecture/editing-engine#changing-the-view Changing the view}\n * section of the {@glink framework/guides/architecture/editing-engine Editing engine architecture} guide.\n *\n * Unlike `DowncastWriter`, which is available in the {@link module:engine/view/view~View#change `View#change()`} block,\n * `UpcastWriter` can be created wherever you need it:\n *\n *\t\tconst writer = new UpcastWriter();\n *\t\tconst text = writer.createText( 'foo!' );\n *\n *\t\twriter.appendChild( text, someViewElement );\n */\nexport default class UpcastWriter {\n\t/**\n\t * Creates a new {@link module:engine/view/documentfragment~DocumentFragment} instance.\n\t *\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into the created document fragment.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} The created document fragment.\n\t */\n\tcreateDocumentFragment( children ) {\n\t\treturn new DocumentFragment( children );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/element~Element} instance.\n\t *\n\t * Attributes can be passed in various formats:\n\t *\n\t *\t\tupcastWriter.createElement( 'div', { class: 'editor', contentEditable: 'true' } ); // object\n\t *\t\tupcastWriter.createElement( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator\n\t *\t\tupcastWriter.createElement( 'div', mapOfAttributes ); // map\n\t *\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t * @returns {module:engine/view/element~Element} Created element.\n\t */\n\tcreateElement( name, attrs, children ) {\n\t\treturn new Element( name, attrs, children );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/text~Text} instance.\n\t *\n\t * @param {String} data The text's data.\n\t * @returns {module:engine/view/text~Text} The created text node.\n\t */\n\tcreateText( data ) {\n\t\treturn new Text( data );\n\t}\n\n\t/**\n\t * Clones the provided element.\n\t *\n\t * @see module:engine/view/element~Element#_clone\n\t * @param {module:engine/view/element~Element} element Element to be cloned.\n\t * @param {Boolean} [deep=false] If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any children.\n\t * @returns {module:engine/view/element~Element} Clone of this element.\n\t */\n\tclone( element, deep = false ) {\n\t\treturn element._clone( deep );\n\t}\n\n\t/**\n\t * Appends a child node or a list of child nodes at the end of this node\n\t * and sets the parent of these nodes to this element.\n\t *\n\t * @see module:engine/view/element~Element#_appendChild\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} element Element\n\t * to which items will be appended.\n\t * @fires module:engine/view/node~Node#event:change\n\t * @returns {Number} Number of appended nodes.\n\t */\n\tappendChild( items, element ) {\n\t\treturn element._appendChild( items );\n\t}\n\n\t/**\n\t * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to\n\t * this element.\n\t *\n\t * @see module:engine/view/element~Element#_insertChild\n\t * @param {Number} index Offset at which nodes should be inserted.\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} element Element\n\t * to which items will be inserted.\n\t * @fires module:engine/view/node~Node#event:change\n\t * @returns {Number} Number of inserted nodes.\n\t */\n\tinsertChild( index, items, element ) {\n\t\treturn element._insertChild( index, items );\n\t}\n\n\t/**\n\t * Removes the given number of child nodes starting at the given index and set the parent of these nodes to `null`.\n\t *\n\t * @see module:engine/view/element~Element#_removeChildren\n\t * @param {Number} index Offset from which nodes will be removed.\n\t * @param {Number} howMany Number of nodes to remove.\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} element Element\n\t * which children will be removed.\n\t * @fires module:engine/view/node~Node#event:change\n\t * @returns {Array.<module:engine/view/node~Node>} The array containing removed nodes.\n\t */\n\tremoveChildren( index, howMany, element ) {\n\t\treturn element._removeChildren( index, howMany );\n\t}\n\n\t/**\n\t * Removes given element from the view structure. Will not have effect on detached elements.\n\t *\n\t * @param {module:engine/view/element~Element} element Element which will be removed.\n\t * @returns {Array.<module:engine/view/node~Node>} The array containing removed nodes.\n\t */\n\tremove( element ) {\n\t\tconst parent = element.parent;\n\n\t\tif ( parent ) {\n\t\t\treturn this.removeChildren( parent.getChildIndex( element ), 1, parent );\n\t\t}\n\n\t\treturn [];\n\t}\n\n\t/**\n\t * Replaces given element with the new one in the view structure. Will not have effect on detached elements.\n\t *\n\t * @param {module:engine/view/element~Element} oldElement Element which will be replaced.\n\t * @param {module:engine/view/element~Element} newElement Element which will be inserted in the place of the old element.\n\t * @returns {Boolean} Whether old element was successfully replaced.\n\t */\n\treplace( oldElement, newElement ) {\n\t\tconst parent = oldElement.parent;\n\n\t\tif ( parent ) {\n\t\t\tconst index = parent.getChildIndex( oldElement );\n\n\t\t\tthis.removeChildren( index, 1, parent );\n\t\t\tthis.insertChild( index, newElement, parent );\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Removes given element from view structure and places its children in its position.\n\t * It does nothing if element has no parent.\n\t *\n\t * @param {module:engine/view/element~Element} element Element to unwrap.\n\t */\n\tunwrapElement( element ) {\n\t\tconst parent = element.parent;\n\n\t\tif ( parent ) {\n\t\t\tconst index = parent.getChildIndex( element );\n\n\t\t\tthis.remove( element );\n\t\t\tthis.insertChild( index, element.getChildren(), parent );\n\t\t}\n\t}\n\n\t/**\n\t * Renames element by creating a copy of a given element but with its name changed and then moving contents of the\n\t * old element to the new one.\n\t *\n\t * Since this function creates a new element and removes the given one, the new element is returned to keep reference.\n\t *\n\t * @param {String} newName New element name.\n\t * @param {module:engine/view/element~Element} element Element to be renamed.\n\t * @returns {module:engine/view/element~Element|null} New element or null if the old element\n\t * was not replaced (happens for detached elements).\n\t */\n\trename( newName, element ) {\n\t\tconst newElement = new Element( newName, element.getAttributes(), element.getChildren() );\n\n\t\treturn this.replace( element, newElement ) ? newElement : null;\n\t}\n\n\t/**\n\t * Adds or overwrites element's attribute with a specified key and value.\n\t *\n\t *\t\twriter.setAttribute( linkElement, 'href', 'http://ckeditor.com' );\n\t *\n\t * @see module:engine/view/element~Element#_setAttribute\n\t * @param {String} key Attribute key.\n\t * @param {String} value Attribute value.\n\t * @param {module:engine/view/element~Element} element Element for which attribute will be set.\n\t */\n\tsetAttribute( key, value, element ) {\n\t\telement._setAttribute( key, value );\n\t}\n\n\t/**\n\t * Removes attribute from the element.\n\t *\n\t *\t\twriter.removeAttribute( linkElement, 'href' );\n\t *\n\t * @see module:engine/view/element~Element#_removeAttribute\n\t * @param {String} key Attribute key.\n\t * @param {module:engine/view/element~Element} element Element from which attribute will be removed.\n\t */\n\tremoveAttribute( key, element ) {\n\t\telement._removeAttribute( key );\n\t}\n\n\t/**\n\t * Adds specified class to the element.\n\t *\n\t *\t\twriter.addClass( linkElement, 'foo' );\n\t *\t\twriter.addClass( linkElement, [ 'foo', 'bar' ] );\n\t *\n\t * @see module:engine/view/element~Element#_addClass\n\t * @param {Array.<String>|String} className Single class name or array of class names which will be added.\n\t * @param {module:engine/view/element~Element} element Element for which class will be added.\n\t */\n\taddClass( className, element ) {\n\t\telement._addClass( className );\n\t}\n\n\t/**\n\t * Removes specified class from the element.\n\t *\n\t *\t\twriter.removeClass( linkElement, 'foo' );\n\t *\t\twriter.removeClass( linkElement, [ 'foo', 'bar' ] );\n\t *\n\t * @see module:engine/view/element~Element#_removeClass\n\t * @param {Array.<String>|String} className Single class name or array of class names which will be removed.\n\t * @param {module:engine/view/element~Element} element Element from which class will be removed.\n\t */\n\tremoveClass( className, element ) {\n\t\telement._removeClass( className );\n\t}\n\n\t/**\n\t * Adds style to the element.\n\t *\n\t *\t\twriter.setStyle( element, 'color', 'red' );\n\t *\t\twriter.setStyle( element, {\n\t *\t\t\tcolor: 'red',\n\t *\t\t\tposition: 'fixed'\n\t *\t\t} );\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details.\n\t *\n\t * @see module:engine/view/element~Element#_setStyle\n\t * @param {String|Object} property Property name or object with key - value pairs.\n\t * @param {String} [value] Value to set. This parameter is ignored if object is provided as the first parameter.\n\t * @param {module:engine/view/element~Element} element Element for which style will be added.\n\t */\n\tsetStyle( property, value, element ) {\n\t\tif ( isPlainObject( property ) && element === undefined ) {\n\t\t\telement = value;\n\t\t}\n\t\telement._setStyle( property, value );\n\t}\n\n\t/**\n\t * Removes specified style from the element.\n\t *\n\t *\t\twriter.removeStyle( element, 'color' ); // Removes 'color' style.\n\t *\t\twriter.removeStyle( element, [ 'color', 'border-top' ] ); // Removes both 'color' and 'border-top' styles.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.\n\t *\n\t * @see module:engine/view/element~Element#_removeStyle\n\t * @param {Array.<String>|String} property Style property name or names to be removed.\n\t * @param {module:engine/view/element~Element} element Element from which style will be removed.\n\t */\n\tremoveStyle( property, element ) {\n\t\telement._removeStyle( property );\n\t}\n\n\t/**\n\t * Sets a custom property on element. Unlike attributes, custom properties are not rendered to the DOM,\n\t * so they can be used to add special data to elements.\n\t *\n\t * @see module:engine/view/element~Element#_setCustomProperty\n\t * @param {String|Symbol} key Custom property name/key.\n\t * @param {*} value Custom property value to be stored.\n\t * @param {module:engine/view/element~Element} element Element for which custom property will be set.\n\t */\n\tsetCustomProperty( key, value, element ) {\n\t\telement._setCustomProperty( key, value );\n\t}\n\n\t/**\n\t * Removes a custom property stored under the given key.\n\t *\n\t * @see module:engine/view/element~Element#_removeCustomProperty\n\t * @param {String|Symbol} key Name/key of the custom property to be removed.\n\t * @param {module:engine/view/element~Element} element Element from which the custom property will be removed.\n\t * @returns {Boolean} Returns true if property was removed.\n\t */\n\tremoveCustomProperty( key, element ) {\n\t\treturn element._removeCustomProperty( key );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link #createPositionBefore},\n\t * * {@link #createPositionAfter},\n\t *\n\t * @param {module:engine/view/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn Position._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn Position._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn Position._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn Range._createOn( item );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn Range._createIn( element );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/selection~Selection} instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = writer.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = writer.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t * @returns {module:engine/view/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn new Selection( selectable, placeOrOffset, options );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { insertImage, isImageAllowed } from '../image/utils';\n\n/**\n * @module image/imageupload/imageuploadcommand\n */\n\n/**\n * The image upload command.\n *\n * The command is registered by the {@link module:image/imageupload/imageuploadediting~ImageUploadEditing} plugin as `'imageUpload'`.\n *\n * In order to upload an image at the current selection position\n * (according to the {@link module:widget/utils~findOptimalInsertionPosition} algorithm),\n * execute the command and pass the native image file instance:\n *\n *\t\tthis.listenTo( editor.editing.view.document, 'clipboardInput', ( evt, data ) => {\n *\t\t\t// Assuming that only images were pasted:\n *\t\t\tconst images = Array.from( data.dataTransfer.files );\n *\n *\t\t\t// Upload the first image:\n *\t\t\teditor.execute( 'imageUpload', { file: images[ 0 ] } );\n *\t\t} );\n *\n * It is also possible to insert multiple images at once:\n *\n *\t\teditor.execute( 'imageUpload', {\n *\t\t\tfile: [\n *\t\t\t\tfile1,\n *\t\t\t\tfile2\n *\t\t\t]\n *\t\t} );\n *\n * @extends module:core/command~Command\n */\nexport default class ImageUploadCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = isImageAllowed( this.editor.model );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t * @param {Object} options Options for the executed command.\n\t * @param {File|Array.<File>} options.file The image file or an array of image files to upload.\n\t */\n\texecute( options ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\tconst fileRepository = editor.plugins.get( FileRepository );\n\n\t\tmodel.change( writer => {\n\t\t\tconst filesToUpload = Array.isArray( options.file ) ? options.file : [ options.file ];\n\n\t\t\tfor ( const file of filesToUpload ) {\n\t\t\t\tuploadImage( writer, model, fileRepository, file );\n\t\t\t}\n\t\t} );\n\t}\n}\n\n// Handles uploading single file.\n//\n// @param {module:engine/model/writer~writer} writer\n// @param {module:engine/model/model~Model} model\n// @param {File} file\nfunction uploadImage( writer, model, fileRepository, file ) {\n\tconst loader = fileRepository.createLoader( file );\n\n\t// Do not throw when upload adapter is not set. FileRepository will log an error anyway.\n\tif ( !loader ) {\n\t\treturn;\n\t}\n\n\tinsertImage( writer, model, { uploadId: loader.id } );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module image/imageupload/imageuploadediting\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';\nimport Notification from '@ckeditor/ckeditor5-ui/src/notification/notification';\nimport Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';\nimport UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\nimport ImageUploadCommand from '../../src/imageupload/imageuploadcommand';\nimport {\n fetchLocalImage,\n isLocalImage\n} from '../../src/imageupload/utils';\nimport { createImageTypeRegExp } from './utils';\n/**\n * The editing part of the image upload feature. It registers the `'imageUpload'` command.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageUploadEditing extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get requires() {\n return [\n FileRepository,\n Notification,\n Clipboard\n ];\n }\n static get pluginName() {\n return 'ImageUploadEditing';\n }\n /**\n\t * @inheritDoc\n\t */\n constructor(editor) {\n super(editor);\n editor.config.define('image', {\n upload: {\n types: [\n 'jpeg',\n 'png',\n 'gif',\n 'bmp',\n 'webp',\n 'tiff'\n ]\n }\n });\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const doc = editor.model.document;\n const schema = editor.model.schema;\n const conversion = editor.conversion;\n const fileRepository = editor.plugins.get(FileRepository);\n const imageTypes = createImageTypeRegExp(editor.config.get('image.upload.types'));\n // Setup schema to allow uploadId and uploadStatus for images.\n schema.extend('image', {\n allowAttributes: [\n 'uploadId',\n 'uploadStatus'\n ]\n });\n // Register imageUpload command.\n editor.commands.add('imageUpload', new ImageUploadCommand(editor));\n // Register upcast converter for uploadId.\n conversion.for('upcast').attributeToAttribute({\n view: {\n name: 'img',\n key: 'uploadId'\n },\n model: 'uploadId'\n });\n // Handle pasted images.\n // For every image file, a new file loader is created and a placeholder image is\n // inserted into the content. Then, those images are uploaded once they appear in the model\n // (see Document#change listener below).\n this.listenTo(editor.editing.view.document, 'clipboardInput', (evt, data) => {\n // Skip if non empty HTML data is included.\n // https://github.com/ckeditor/ckeditor5-upload/issues/68\n if (isHtmlIncluded(data.dataTransfer)) {\n return;\n }\n const images = Array.from(data.dataTransfer.files).filter(file => {\n // See https://github.com/ckeditor/ckeditor5-image/pull/254.\n if (!file) {\n return false;\n }\n return imageTypes.test(file.type);\n });\n const ranges = data.targetRanges.map(viewRange => editor.editing.mapper.toModelRange(viewRange));\n editor.model.change(writer => {\n // Set selection to paste target.\n writer.setSelection(ranges);\n if (images.length) {\n evt.stop();\n // Upload images after the selection has changed in order to ensure the command's state is refreshed.\n editor.model.enqueueChange('default', () => {\n editor.execute('imageUpload', { file: images });\n });\n }\n });\n });\n // Handle HTML pasted with images with base64 or blob sources.\n // For every image file, a new file loader is created and a placeholder image is\n // inserted into the content. Then, those images are uploaded once they appear in the model\n // (see Document#change listener below).\n this.listenTo(editor.plugins.get(Clipboard), 'inputTransformation', (evt, data) => {\n const fetchableImages = Array.from(editor.editing.view.createRangeIn(data.content)).filter(value => isLocalImage(value.item) && !value.item.getAttribute('uploadProcessed')).map(value => {\n return {\n promise: fetchLocalImage(value.item),\n imageElement: value.item\n };\n });\n if (!fetchableImages.length) {\n return;\n }\n const writer = new UpcastWriter();\n for (const fetchableImage of fetchableImages) {\n // Set attribute marking that the image was processed already.\n writer.setAttribute('uploadProcessed', true, fetchableImage.imageElement);\n const loader = fileRepository.createLoader(fetchableImage.promise);\n if (loader) {\n writer.setAttribute('src', '', fetchableImage.imageElement);\n writer.setAttribute('uploadId', loader.id, fetchableImage.imageElement);\n }\n }\n });\n // Prevents from the browser redirecting to the dropped image.\n editor.editing.view.document.on('dragover', (evt, data) => {\n data.preventDefault();\n });\n // Upload placeholder images that appeared in the model.\n doc.on('change', () => {\n const changes = doc.differ.getChanges({ includeChangesInGraveyard: true });\n for (const entry of changes) {\n if (entry.type == 'insert' && entry.name != '$text') {\n const item = entry.position.nodeAfter;\n const isInGraveyard = entry.position.root.rootName == '$graveyard';\n for (const image of getImagesFromChangeItem(editor, item)) {\n // Check if the image element still has upload id.\n const uploadId = image.getAttribute('uploadId');\n if (!uploadId) {\n continue;\n }\n // Check if the image is loaded on this client.\n const loader = fileRepository.loaders.get(uploadId);\n if (!loader) {\n continue;\n }\n if (isInGraveyard) {\n // If the image was inserted to the graveyard - abort the loading process.\n loader.abort();\n } else if (loader.status == 'idle') {\n // If the image was inserted into content and has not been loaded yet, start loading it.\n this._readAndUpload(loader, image);\n }\n }\n }\n }\n });\n }\n /**\n\t * Reads and uploads an image.\n\t *\n\t * The image is read from the disk and as a Base64-encoded string it is set temporarily to\n\t * `image[src]`. When the image is successfully uploaded, the temporary data is replaced with the target\n\t * image's URL (the URL to the uploaded image on the server).\n\t *\n\t * @protected\n\t * @param {module:upload/filerepository~FileLoader} loader\n\t * @param {module:engine/model/element~Element} imageElement\n\t * @returns {Promise}\n\t */\n _readAndUpload(loader, imageElement) {\n const editor = this.editor;\n const model = editor.model;\n const t = editor.locale.t;\n const fileRepository = editor.plugins.get(FileRepository);\n const notification = editor.plugins.get(Notification);\n model.enqueueChange('transparent', writer => {\n writer.setAttribute('uploadStatus', 'reading', imageElement);\n });\n return loader.read().then(() => {\n const promise = loader.upload();\n // Force re–paint in Safari. Without it, the image will display with a wrong size.\n // https://github.com/ckeditor/ckeditor5/issues/1975\n /* istanbul ignore next */\n if (env.isSafari) {\n const viewFigure = editor.editing.mapper.toViewElement(imageElement);\n const viewImg = viewFigure.getChild(0);\n editor.editing.view.once('render', () => {\n // Early returns just to be safe. There might be some code ran\n // in between the outer scope and this callback.\n if (!viewImg.parent) {\n return;\n }\n const domFigure = editor.editing.view.domConverter.mapViewToDom(viewImg.parent);\n if (!domFigure) {\n return;\n }\n const originalDisplay = domFigure.style.display;\n domFigure.style.display = 'none';\n // Make sure this line will never be removed during minification for having \"no effect\".\n domFigure._ckHack = domFigure.offsetHeight;\n domFigure.style.display = originalDisplay;\n });\n }\n model.enqueueChange('transparent', writer => {\n writer.setAttribute('uploadStatus', 'uploading', imageElement);\n });\n return promise;\n }).then(data => {\n model.enqueueChange('transparent', writer => {\n writer.setAttributes({\n uploadStatus: 'complete',\n src: data.default\n }, imageElement);\n this._parseAndSetSrcsetAttributeOnImage(data, imageElement, writer);\n });\n clean();\n }).catch(error => {\n // If status is not 'error' nor 'aborted' - throw error because it means that something else went wrong,\n // it might be generic error and it would be real pain to find what is going on.\n if (loader.status !== 'error' && loader.status !== 'aborted') {\n throw error;\n }\n // Might be 'aborted'.\n if (loader.status == 'error' && error) {\n notification.showWarning(error, {\n title: t('ag'),\n namespace: 'upload'\n });\n }\n clean();\n // Permanently remove image from insertion batch.\n model.enqueueChange('transparent', writer => {\n writer.remove(imageElement);\n });\n });\n function clean() {\n model.enqueueChange('transparent', writer => {\n writer.removeAttribute('uploadId', imageElement);\n writer.removeAttribute('uploadStatus', imageElement);\n });\n fileRepository.destroyLoader(loader);\n }\n }\n /**\n\t * Creates the `srcset` attribute based on a given file upload response and sets it as an attribute to a specific image element.\n\t *\n\t * @protected\n\t * @param {Object} data Data object from which `srcset` will be created.\n\t * @param {module:engine/model/element~Element} image The image element on which the `srcset` attribute will be set.\n\t * @param {module:engine/model/writer~Writer} writer\n\t */\n _parseAndSetSrcsetAttributeOnImage(data, image, writer) {\n // Srcset attribute for responsive images support.\n let maxWidth = 0;\n const srcsetAttribute = Object.keys(data) // Filter out keys that are not integers.\n.filter(key => {\n const width = parseInt(key, 10);\n if (!isNaN(width)) {\n maxWidth = Math.max(maxWidth, width);\n return true;\n }\n }) // Convert each key to srcset entry.\n.map(key => `${ data[key] } ${ key }w`) // Join all entries.\n.join(', ');\n if (srcsetAttribute != '') {\n writer.setAttribute('srcset', {\n data: srcsetAttribute,\n width: maxWidth\n }, image);\n }\n }\n}\n// Returns `true` if non-empty `text/html` is included in the data transfer.\n//\n// @param {module:clipboard/datatransfer~DataTransfer} dataTransfer\n// @returns {Boolean}\nexport function isHtmlIncluded(dataTransfer) {\n return Array.from(dataTransfer.types).includes('text/html') && dataTransfer.getData('text/html') !== '';\n}\nfunction getImagesFromChangeItem(editor, item) {\n return Array.from(editor.model.createRangeOn(item)).filter(value => value.item.is('image')).map(value => value.item);\n}","/**\n * @license Copyright (c) 2003-2020, 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 image/imageupload\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageUploadUI from './imageupload/imageuploadui';\nimport ImageUploadProgress from './imageupload/imageuploadprogress';\nimport ImageUploadEditing from './imageupload/imageuploadediting';\n\n/**\n * The image upload plugin.\n *\n * For a detailed overview, check the {@glink features/image-upload/image-upload image upload feature} documentation.\n *\n * This plugin does not do anything directly, but it loads a set of specific plugins to enable image uploading:\n *\n * * {@link module:image/imageupload/imageuploadediting~ImageUploadEditing},\n * * {@link module:image/imageupload/imageuploadui~ImageUploadUI},\n * * {@link module:image/imageupload/imageuploadprogress~ImageUploadProgress}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageUpload extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageUpload';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageUploadEditing, ImageUploadUI, ImageUploadProgress ];\n\t}\n}\n\n/**\n * Image upload configuration.\n *\n * @member {module:image/imageupload~ImageUploadConfig} module:image/image~ImageConfig#upload\n */\n\n/**\n * The configuration of the image upload feature. Used by the image upload feature in the `@ckeditor/ckeditor5-image` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\timage: {\n * \t\t\t\t\tupload: ... // Image upload feature options.\n * \t\t\t\t}\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 module:image/imageupload~ImageUploadConfig\n */\n\n/**\n * The list of accepted image types.\n *\n * The accepted types of images can be customized to allow only certain types of images:\n *\n *\t\t// Allow only JPEG and PNG images:\n *\t\tconst imageUploadConfig = {\n *\t\t\ttypes: [ 'png', 'jpeg' ]\n *\t\t};\n *\n * The type string should match [one of the sub-types](https://www.iana.org/assignments/media-types/media-types.xhtml#image)\n * of the image MIME type. E.g. for the `image/jpeg` MIME type, add `'jpeg'` to your image upload configuration.\n *\n * **Note:** This setting only restricts some image types to be selected and uploaded through the CKEditor UI and commands. Image type\n * recognition and filtering should also be implemented on the server which accepts image uploads.\n *\n * @member {Array.<String>} module:image/imageupload~ImageUploadConfig#types\n * @default [ 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff' ]\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 paragraph/paragraphcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The paragraph command.\n *\n * @extends module:core/command~Command\n */\nexport default class ParagraphCommand extends Command {\n\t/**\n\t * The value of the command. Indicates whether the selection start is placed in a paragraph.\n\t *\n\t * @readonly\n\t * @observable\n\t * @member {Boolean} #value\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\t\tconst block = first( document.selection.getSelectedBlocks() );\n\n\t\tthis.value = !!block && block.is( 'paragraph' );\n\t\tthis.isEnabled = !!block && checkCanBecomeParagraph( block, model.schema );\n\t}\n\n\t/**\n\t * Executes the command. All the blocks (see {@link module:engine/model/schema~Schema}) in the selection\n\t * will be turned to paragraphs.\n\t *\n\t * @fires execute\n\t * @param {Object} [options] Options for the executed command.\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} [options.selection]\n\t * The selection that the command should be applied to.\n\t * By default, if not provided, the command is applied to the {@link module:engine/model/document~Document#selection}.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\tmodel.change( writer => {\n\t\t\tconst blocks = ( options.selection || document.selection ).getSelectedBlocks();\n\n\t\t\tfor ( const block of blocks ) {\n\t\t\t\tif ( !block.is( 'paragraph' ) && checkCanBecomeParagraph( block, model.schema ) ) {\n\t\t\t\t\twriter.rename( block, 'paragraph' );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n\n// Checks whether the given block can be replaced by a paragraph.\n//\n// @private\n// @param {module:engine/model/element~Element} block A block to be tested.\n// @param {module:engine/model/schema~Schema} schema The schema of the document.\n// @returns {Boolean}\nfunction checkCanBecomeParagraph( block, schema ) {\n\treturn schema.checkChild( block.parent, 'paragraph' ) && !schema.isObject( block );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 paragraph/paragraph\n */\n\nimport ParagraphCommand from './paragraphcommand';\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * The paragraph feature for the editor.\n *\n * It introduces the `<paragraph>` element in the model which renders as a `<p>` element in the DOM and data.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Paragraph extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Paragraph';\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 data = editor.data;\n\n\t\teditor.commands.add( 'paragraph', new ParagraphCommand( editor ) );\n\n\t\t// Schema.\n\t\tmodel.schema.register( 'paragraph', { inheritAllFrom: '$block' } );\n\n\t\teditor.conversion.elementToElement( { model: 'paragraph', view: 'p' } );\n\n\t\t// Content autoparagraphing. --------------------------------------------------\n\n\t\t// Handles element which has not been converted by any plugin and checks if it would be converted if\n\t\t// we wrap it in a paragraph or change it to a paragraph.\n\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t\t\tmodel: ( viewElement, modelWriter ) => {\n\t\t\t\tif ( !Paragraph.paragraphLikeElements.has( viewElement.name ) ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t// Do not auto-paragraph empty elements.\n\t\t\t\tif ( viewElement.isEmpty ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\treturn modelWriter.createElement( 'paragraph' );\n\t\t\t},\n\t\t\tconverterPriority: 'low'\n\t\t} );\n\n\t\tdata.upcastDispatcher.on( 'element', ( evt, data, conversionApi ) => {\n\t\t\t// Do not try auto-paragraphing if the element was already converted.\n\t\t\tif ( !conversionApi.consumable.test( data.viewItem, { name: data.viewItem.name } ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If the element is not paragraph-like try wrapping it in a paragraph.\n\t\t\tif ( isParagraphable( data.viewItem, data.modelCursor, conversionApi.schema ) ) {\n\t\t\t\tObject.assign( data, wrapInParagraph( data.viewItem, data.modelCursor, conversionApi ) );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\t// Handles not converted text nodes and checks if would be converted if we wraps then by a paragraph.\n\t\tdata.upcastDispatcher.on( 'text', ( evt, data, conversionApi ) => {\n\t\t\t// When node is already converted then do nothing.\n\t\t\tif ( data.modelRange ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isParagraphable( data.viewItem, data.modelCursor, conversionApi.schema ) ) {\n\t\t\t\tObject.assign( data, wrapInParagraph( data.viewItem, data.modelCursor, conversionApi ) );\n\t\t\t}\n\t\t}, { priority: 'lowest' } );\n\n\t\t// Empty roots autoparagraphing. -----------------------------------------------\n\n\t\t// Post-fixer which takes care of adding empty paragraph elements to empty roots.\n\t\t// Besides fixing content on #changesDone we also need to handle editor.data#ready event because\n\t\t// if initial data is empty or setData() wasn't even called there will be no #change fired.\n\t\tmodel.document.registerPostFixer( writer => this._autoparagraphEmptyRoots( writer ) );\n\n\t\teditor.data.on( 'ready', () => {\n\t\t\tmodel.enqueueChange( 'transparent', writer => this._autoparagraphEmptyRoots( writer ) );\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Fixes all empty roots.\n\t *\n\t * @private\n\t * @returns {Boolean} `true` if any change has been applied, `false` otherwise.\n\t */\n\t_autoparagraphEmptyRoots( writer ) {\n\t\tconst model = this.editor.model;\n\n\t\tfor ( const rootName of model.document.getRootNames() ) {\n\t\t\tconst root = model.document.getRoot( rootName );\n\n\t\t\tif ( root.isEmpty && root.rootName != '$graveyard' ) {\n\t\t\t\t// If paragraph element is allowed in the root, create paragraph element.\n\t\t\t\tif ( model.schema.checkChild( root, 'paragraph' ) ) {\n\t\t\t\t\twriter.insertElement( 'paragraph', root );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * A list of element names which should be treated by the autoparagraphing algorithms as\n * paragraph-like. This means that e.g. the following content:\n *\n *\t\t<h1>Foo</h1>\n *\t\t<table>\n *\t\t\t<tr>\n *\t\t\t\t<td>X</td>\n *\t\t\t\t<td>\n *\t\t\t\t\t<ul>\n *\t\t\t\t\t\t<li>Y</li>\n *\t\t\t\t\t\t<li>Z</li>\n *\t\t\t\t\t</ul>\n *\t\t\t\t</td>\n *\t\t\t</tr>\n *\t\t</table>\n *\n * contains five paragraph-like elements: `<h1>`, two `<td>`s and two `<li>`s.\n * Hence, if none of the features is going to convert those elements the above content will be automatically handled\n * by the paragraph feature and converted to:\n *\n *\t\t<p>Foo</p>\n *\t\t<p>X</p>\n *\t\t<p>Y</p>\n *\t\t<p>Z</p>\n *\n * Note: The `<td>` containing two `<li>` elements was ignored as the innermost paragraph-like elements\n * have a priority upon conversion.\n *\n * @member {Set.<String>} module:paragraph/paragraph~Paragraph.paragraphLikeElements\n */\nParagraph.paragraphLikeElements = new Set( [\n\t'blockquote',\n\t'dd',\n\t'div',\n\t'dt',\n\t'h1',\n\t'h2',\n\t'h3',\n\t'h4',\n\t'h5',\n\t'h6',\n\t'li',\n\t'p',\n\t'td'\n] );\n\nfunction wrapInParagraph( input, position, conversionApi ) {\n\tconst paragraph = conversionApi.writer.createElement( 'paragraph' );\n\n\tconversionApi.writer.insert( paragraph, position );\n\treturn conversionApi.convertItem( input, conversionApi.writer.createPositionAt( paragraph, 0 ) );\n}\n\nfunction isParagraphable( node, position, schema ) {\n\tconst context = schema.createContext( position );\n\n\t// When paragraph is allowed in this context...\n\tif ( !schema.checkChild( context, 'paragraph' ) ) {\n\t\treturn false;\n\t}\n\n\t// And a node would be allowed in this paragraph...\n\tif ( !schema.checkChild( context.push( 'paragraph' ), node ) ) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 heading/headingcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The heading command. It is used by the {@link module:heading/heading~Heading heading feature} to apply headings.\n *\n * @extends module:core/command~Command\n */\nexport default class HeadingCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor Editor instance.\n\t * @param {Array.<String>} modelElements Names of the element which this command can apply in the model.\n\t */\n\tconstructor( editor, modelElements ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * If the selection starts in a heading (which {@link #modelElements is supported by this command})\n\t\t * the value is set to the name of that heading model element.\n\t\t * It is set to `false` otherwise.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean|String} #value\n\t\t */\n\n\t\t/**\n\t\t * Set of defined model's elements names that this command support.\n\t\t * See {@link module:heading/heading~HeadingOption}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<String>}\n\t\t */\n\t\tthis.modelElements = modelElements;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst block = first( this.editor.model.document.selection.getSelectedBlocks() );\n\n\t\tthis.value = !!block && this.modelElements.includes( block.name ) && block.name;\n\t\tthis.isEnabled = !!block && this.modelElements.some( heading => checkCanBecomeHeading( block, heading, this.editor.model.schema ) );\n\t}\n\n\t/**\n\t * Executes the command. Applies the heading to the selected blocks or, if the first selected\n\t * block is a heading already, turns selected headings (of this level only) to paragraphs.\n\t *\n\t * @param {Object} options\n\t * @param {String} options.value Name of the element which this command will apply in the model.\n\t * @fires execute\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\tconst modelElement = options.value;\n\n\t\tmodel.change( writer => {\n\t\t\tconst blocks = Array.from( document.selection.getSelectedBlocks() )\n\t\t\t\t.filter( block => {\n\t\t\t\t\treturn checkCanBecomeHeading( block, modelElement, model.schema );\n\t\t\t\t} );\n\n\t\t\tfor ( const block of blocks ) {\n\t\t\t\tif ( !block.is( modelElement ) ) {\n\t\t\t\t\twriter.rename( block, modelElement );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n\n// Checks whether the given block can be replaced by a specific heading.\n//\n// @private\n// @param {module:engine/model/element~Element} block A block to be tested.\n// @param {module:heading/headingcommand~HeadingCommand#modelElement} heading Command element name in the model.\n// @param {module:engine/model/schema~Schema} schema The schema of the document.\n// @returns {Boolean}\nfunction checkCanBecomeHeading( block, heading, schema ) {\n\treturn schema.checkChild( block.parent, heading ) && !schema.isObject( block );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 heading/headingediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\nimport HeadingCommand from './headingcommand';\n\nimport priorities from '@ckeditor/ckeditor5-utils/src/priorities';\n\nconst defaultModelElement = 'paragraph';\n\n/**\n * The headings engine feature. It handles switching between block formats – headings and paragraph.\n * This class represents the engine part of the heading feature. See also {@link module:heading/heading~Heading}.\n * It introduces `heading1`-`headingN` commands which allow to convert paragraphs into headings.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HeadingEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'HeadingEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'heading', {\n\t\t\toptions: [\n\t\t\t\t{ model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },\n\t\t\t\t{ model: 'heading1', view: 'h2', title: 'Heading 1', class: 'ck-heading_heading1' },\n\t\t\t\t{ model: 'heading2', view: 'h3', title: 'Heading 2', class: 'ck-heading_heading2' },\n\t\t\t\t{ model: 'heading3', view: 'h4', title: 'Heading 3', class: 'ck-heading_heading3' }\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Paragraph ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst options = editor.config.get( 'heading.options' );\n\n\t\tconst modelElements = [];\n\n\t\tfor ( const option of options ) {\n\t\t\t// Skip paragraph - it is defined in required Paragraph feature.\n\t\t\tif ( option.model !== defaultModelElement ) {\n\t\t\t\t// Schema.\n\t\t\t\teditor.model.schema.register( option.model, {\n\t\t\t\t\tinheritAllFrom: '$block'\n\t\t\t\t} );\n\n\t\t\t\teditor.conversion.elementToElement( option );\n\n\t\t\t\tmodelElements.push( option.model );\n\t\t\t}\n\t\t}\n\n\t\tthis._addDefaultH1Conversion( editor );\n\n\t\t// Register the heading command for this option.\n\t\teditor.commands.add( 'heading', new HeadingCommand( editor, modelElements ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\t// If the enter command is added to the editor, alter its behavior.\n\t\t// Enter at the end of a heading element should create a paragraph.\n\t\tconst editor = this.editor;\n\t\tconst enterCommand = editor.commands.get( 'enter' );\n\t\tconst options = editor.config.get( 'heading.options' );\n\n\t\tif ( enterCommand ) {\n\t\t\tthis.listenTo( enterCommand, 'afterExecute', ( evt, data ) => {\n\t\t\t\tconst positionParent = editor.model.document.selection.getFirstPosition().parent;\n\t\t\t\tconst isHeading = options.some( option => positionParent.is( option.model ) );\n\n\t\t\t\tif ( isHeading && !positionParent.is( defaultModelElement ) && positionParent.childCount === 0 ) {\n\t\t\t\t\tdata.writer.rename( positionParent, defaultModelElement );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Adds default conversion for `h1` -> `heading1` with a low priority.\n\t *\n\t * @private\n\t * @param {module:core/editor/editor~Editor} editor Editor instance on which to add the `h1` conversion.\n\t */\n\t_addDefaultH1Conversion( editor ) {\n\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t\t\tmodel: 'heading1',\n\t\t\tview: 'h1',\n\t\t\t// With a `low` priority, `paragraph` plugin autoparagraphing mechanism is executed. Make sure\n\t\t\t// this listener is called before it. If not, `h1` will be transformed into a paragraph.\n\t\t\tconverterPriority: priorities.get( 'low' ) + 1\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/model\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport { extend } from 'lodash-es';\n\n/**\n * The base MVC model class.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Model {\n\t/**\n\t * Creates a new Model instance.\n\t *\n\t * @param {Object} [attributes] The model state attributes to be defined during the instance creation.\n\t * @param {Object} [properties] The (out of state) properties to be appended to the instance during creation.\n\t */\n\tconstructor( attributes, properties ) {\n\t\t// Extend this instance with the additional (out of state) properties.\n\t\tif ( properties ) {\n\t\t\textend( this, properties );\n\t\t}\n\n\t\t// Initialize the attributes.\n\t\tif ( attributes ) {\n\t\t\tthis.set( attributes );\n\t\t}\n\t}\n}\n\nmix( Model, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module heading/headingui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Model from '@ckeditor/ckeditor5-ui/src/model';\nimport {\n createDropdown,\n addListToDropdown\n} from '@ckeditor/ckeditor5-ui/src/dropdown/utils';\nimport { getLocalizedOptions } from './utils';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport '../theme/heading.css';\n/**\n * The headings UI feature. It introduces the `headings` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HeadingUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n const options = getLocalizedOptions(editor);\n const defaultTitle = t('l');\n const dropdownTooltip = t('m');\n // Register UI component.\n editor.ui.componentFactory.add('heading', locale => {\n const titles = {};\n const itemDefinitions = new Collection();\n const headingCommand = editor.commands.get('heading');\n const paragraphCommand = editor.commands.get('paragraph');\n const commands = [headingCommand];\n for (const option of options) {\n const def = {\n type: 'button',\n model: new Model({\n label: option.title,\n class: option.class,\n withText: true\n })\n };\n if (option.model === 'paragraph') {\n def.model.bind('isOn').to(paragraphCommand, 'value');\n def.model.set('commandName', 'paragraph');\n commands.push(paragraphCommand);\n } else {\n def.model.bind('isOn').to(headingCommand, 'value', value => value === option.model);\n def.model.set({\n commandName: 'heading',\n commandValue: option.model\n });\n }\n // Add the option to the collection.\n itemDefinitions.add(def);\n titles[option.model] = option.title;\n }\n const dropdownView = createDropdown(locale);\n addListToDropdown(dropdownView, itemDefinitions);\n dropdownView.buttonView.set({\n isOn: false,\n withText: true,\n tooltip: dropdownTooltip\n });\n dropdownView.extendTemplate({ attributes: { class: ['ck-heading-dropdown'] } });\n dropdownView.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled) => {\n return areEnabled.some(isEnabled => isEnabled);\n });\n dropdownView.buttonView.bind('label').to(headingCommand, 'value', paragraphCommand, 'value', (value, para) => {\n const whichModel = value || para && 'paragraph';\n // If none of the commands is active, display default title.\n return titles[whichModel] ? titles[whichModel] : defaultTitle;\n });\n // Execute command when an item from the dropdown is selected.\n this.listenTo(dropdownView, 'execute', evt => {\n editor.execute(evt.source.commandName, evt.source.commandValue ? { value: evt.source.commandValue } : undefined);\n editor.editing.view.focus();\n });\n return dropdownView;\n });\n }\n}","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module heading/utils\n */\n/**\n * Returns heading options as defined in `config.heading.options` but processed to consider\n * the editor localization, i.e. to display {@link module:heading/heading~HeadingOption}\n * in the correct language.\n *\n * Note: The reason behind this method is that there is no way to use {@link module:utils/locale~Locale#t}\n * when the user configuration is defined because the editor does not exist yet.\n *\n * @param {module:core/editor/editor~Editor} editor\n * @returns {Array.<module:heading/heading~HeadingOption>}.\n */\nexport function getLocalizedOptions(editor) {\n const t = editor.t;\n const localizedTitles = {\n Paragraph: t('dk'),\n 'Heading 1': t('dl'),\n 'Heading 2': t('dm'),\n 'Heading 3': t('dn'),\n 'Heading 4': t('do'),\n 'Heading 5': t('dp'),\n 'Heading 6': t('dq')\n };\n return editor.config.get('heading.options').map(option => {\n const title = localizedTitles[option.title];\n if (title && title != option.title) {\n option.title = title;\n }\n return option;\n });\n}","/**\n * @license Copyright (c) 2003-2020, 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 image/imagecaption/utils\n */\n\nimport { enablePlaceholder } from '@ckeditor/ckeditor5-engine/src/view/placeholder';\nimport { toWidgetEditable } from '@ckeditor/ckeditor5-widget/src/utils';\n\n/**\n * Returns a function that creates a caption editable element for the given {@link module:engine/view/document~Document}.\n *\n * @param {module:engine/view/view~View} view\n * @param {String} placeholderText The text to be displayed when the caption is empty.\n * @returns {Function}\n */\nexport function captionElementCreator( view, placeholderText ) {\n\treturn writer => {\n\t\tconst editable = writer.createEditableElement( 'figcaption' );\n\t\twriter.setCustomProperty( 'imageCaption', true, editable );\n\n\t\tenablePlaceholder( {\n\t\t\tview,\n\t\t\telement: editable,\n\t\t\ttext: placeholderText\n\t\t} );\n\n\t\treturn toWidgetEditable( editable, writer );\n\t};\n}\n\n/**\n * Returns `true` if a given view element is the image caption editable.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @returns {Boolean}\n */\nexport function isCaption( viewElement ) {\n\treturn !!viewElement.getCustomProperty( 'imageCaption' );\n}\n\n/**\n * Returns the caption model element from a given image element. Returns `null` if no caption is found.\n *\n * @param {module:engine/model/element~Element} imageModelElement\n * @returns {module:engine/model/element~Element|null}\n */\nexport function getCaptionFromImage( imageModelElement ) {\n\tfor ( const node of imageModelElement.getChildren() ) {\n\t\tif ( !!node && node.is( 'caption' ) ) {\n\t\t\treturn node;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * {@link module:engine/view/matcher~Matcher} pattern. Checks if a given element is a `<figcaption>` element that is placed\n * inside the image `<figure>` element.\n *\n * @param {module:engine/view/element~Element} element\n * @returns {Object|null} Returns the object accepted by {@link module:engine/view/matcher~Matcher} or `null` if the element\n * cannot be matched.\n */\nexport function matchImageCaption( element ) {\n\tconst parent = element.parent;\n\n\t// Convert only captions for images.\n\tif ( element.name == 'figcaption' && parent && parent.name == 'figure' && parent.hasClass( 'image' ) ) {\n\t\treturn { name: true };\n\t}\n\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module image/imagecaption/imagecaptionediting\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { isImage } from '../image/utils';\nimport {\n captionElementCreator,\n getCaptionFromImage,\n matchImageCaption\n} from './utils';\n/**\n * The image caption engine plugin.\n *\n * It registers proper converters. It takes care of adding a caption element if the image without it is inserted\n * to the model document.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageCaptionEditing extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'ImageCaptionEditing';\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const view = editor.editing.view;\n const schema = editor.model.schema;\n const data = editor.data;\n const editing = editor.editing;\n const t = editor.t;\n /**\n\t\t * The last selected caption editable.\n\t\t * It is used for hiding the editable when it is empty and the image widget is no longer selected.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/editableelement~EditableElement} #_lastSelectedCaption\n\t\t */\n // Schema configuration.\n schema.register('caption', {\n allowIn: 'image',\n allowContentOf: '$block',\n isLimit: true\n });\n // Add caption element to each image inserted without it.\n editor.model.document.registerPostFixer(writer => this._insertMissingModelCaptionElement(writer));\n // View to model converter for the data pipeline.\n editor.conversion.for('upcast').elementToElement({\n view: matchImageCaption,\n model: 'caption'\n });\n // Model to view converter for the data pipeline.\n const createCaptionForData = writer => writer.createContainerElement('figcaption');\n data.downcastDispatcher.on('insert:caption', captionModelToView(createCaptionForData, false));\n // Model to view converter for the editing pipeline.\n const createCaptionForEditing = captionElementCreator(view, t('z'));\n editing.downcastDispatcher.on('insert:caption', captionModelToView(createCaptionForEditing));\n // Always show caption in view when something is inserted in model.\n editing.downcastDispatcher.on('insert', this._fixCaptionVisibility(data => data.item), { priority: 'high' });\n // Hide caption when everything is removed from it.\n editing.downcastDispatcher.on('remove', this._fixCaptionVisibility(data => data.position.parent), { priority: 'high' });\n // Update caption visibility on view in post fixer.\n view.document.registerPostFixer(writer => this._updateCaptionVisibility(writer));\n }\n /**\n\t * Updates the view before each rendering, making sure that empty captions (so unnecessary ones) are hidden\n\t * and then visible when the image is selected.\n\t *\n\t * @private\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n\t * @returns {Boolean} Returns `true` when the view is updated.\n\t */\n _updateCaptionVisibility(viewWriter) {\n const mapper = this.editor.editing.mapper;\n const lastCaption = this._lastSelectedCaption;\n let viewCaption;\n // If whole image is selected.\n const modelSelection = this.editor.model.document.selection;\n const selectedElement = modelSelection.getSelectedElement();\n if (selectedElement && selectedElement.is('image')) {\n const modelCaption = getCaptionFromImage(selectedElement);\n viewCaption = mapper.toViewElement(modelCaption);\n }\n // If selection is placed inside caption.\n const position = modelSelection.getFirstPosition();\n const modelCaption = getParentCaption(position.parent);\n if (modelCaption) {\n viewCaption = mapper.toViewElement(modelCaption);\n }\n // Is currently any caption selected?\n if (viewCaption) {\n // Was any caption selected before?\n if (lastCaption) {\n // Same caption as before?\n if (lastCaption === viewCaption) {\n return showCaption(viewCaption, viewWriter);\n } else {\n hideCaptionIfEmpty(lastCaption, viewWriter);\n this._lastSelectedCaption = viewCaption;\n return showCaption(viewCaption, viewWriter);\n }\n } else {\n this._lastSelectedCaption = viewCaption;\n return showCaption(viewCaption, viewWriter);\n }\n } else {\n // Was any caption selected before?\n if (lastCaption) {\n const viewModified = hideCaptionIfEmpty(lastCaption, viewWriter);\n this._lastSelectedCaption = null;\n return viewModified;\n } else {\n return false;\n }\n }\n }\n /**\n\t * Returns a converter that fixes caption visibility during the model-to-view conversion.\n\t * Checks if the changed node is placed inside the caption element and fixes its visibility in the view.\n\t *\n\t * @private\n\t * @param {Function} nodeFinder\n\t * @returns {Function}\n\t */\n _fixCaptionVisibility(nodeFinder) {\n return (evt, data, conversionApi) => {\n const node = nodeFinder(data);\n const modelCaption = getParentCaption(node);\n const mapper = this.editor.editing.mapper;\n const viewWriter = conversionApi.writer;\n if (modelCaption) {\n const viewCaption = mapper.toViewElement(modelCaption);\n if (viewCaption) {\n if (modelCaption.childCount) {\n viewWriter.removeClass('ck-hidden', viewCaption);\n } else {\n viewWriter.addClass('ck-hidden', viewCaption);\n }\n }\n }\n };\n }\n /**\n\t * Checks whether the data inserted to the model document have an image element that has no caption element inside it.\n\t * If there is none, it adds it to the image element.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer The writer to make changes with.\n\t * @returns {Boolean} `true` if any change was applied, `false` otherwise.\n\t */\n _insertMissingModelCaptionElement(writer) {\n const model = this.editor.model;\n const changes = model.document.differ.getChanges();\n const imagesWithoutCaption = [];\n for (const entry of changes) {\n if (entry.type == 'insert' && entry.name != '$text') {\n const item = entry.position.nodeAfter;\n if (item.is('image') && !getCaptionFromImage(item)) {\n imagesWithoutCaption.push(item);\n }\n // Check elements with children for nested images.\n if (!item.is('image') && item.childCount) {\n for (const nestedItem of model.createRangeIn(item).getItems()) {\n if (nestedItem.is('image') && !getCaptionFromImage(nestedItem)) {\n imagesWithoutCaption.push(nestedItem);\n }\n }\n }\n }\n }\n for (const image of imagesWithoutCaption) {\n writer.appendElement('caption', image);\n }\n return !!imagesWithoutCaption.length;\n }\n}\n// Creates a converter that converts image caption model element to view element.\n//\n// @private\n// @param {Function} elementCreator\n// @param {Boolean} [hide=true] When set to `false` view element will not be inserted when it's empty.\n// @returns {Function}\nfunction captionModelToView(elementCreator, hide = true) {\n return (evt, data, conversionApi) => {\n const captionElement = data.item;\n // Return if element shouldn't be present when empty.\n if (!captionElement.childCount && !hide) {\n return;\n }\n if (isImage(captionElement.parent)) {\n if (!conversionApi.consumable.consume(data.item, 'insert')) {\n return;\n }\n const viewImage = conversionApi.mapper.toViewElement(data.range.start.parent);\n const viewCaption = elementCreator(conversionApi.writer);\n const viewWriter = conversionApi.writer;\n // Hide if empty.\n if (!captionElement.childCount) {\n viewWriter.addClass('ck-hidden', viewCaption);\n }\n insertViewCaptionAndBind(viewCaption, data.item, viewImage, conversionApi);\n }\n };\n}\n// Inserts `viewCaption` at the end of `viewImage` and binds it to `modelCaption`.\n//\n// @private\n// @param {module:engine/view/containerelement~ContainerElement} viewCaption\n// @param {module:engine/model/element~Element} modelCaption\n// @param {module:engine/view/containerelement~ContainerElement} viewImage\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction insertViewCaptionAndBind(viewCaption, modelCaption, viewImage, conversionApi) {\n const viewPosition = conversionApi.writer.createPositionAt(viewImage, 'end');\n conversionApi.writer.insert(viewPosition, viewCaption);\n conversionApi.mapper.bindElements(modelCaption, viewCaption);\n}\n// Checks if the provided node or one of its ancestors is a caption element, and returns it.\n//\n// @private\n// @param {module:engine/model/node~Node} node\n// @returns {module:engine/model/element~Element|null}\nfunction getParentCaption(node) {\n const ancestors = node.getAncestors({ includeSelf: true });\n const caption = ancestors.find(ancestor => ancestor.name == 'caption');\n if (caption && caption.parent && caption.parent.name == 'image') {\n return caption;\n }\n return null;\n}\n// Hides a given caption in the view if it is empty.\n//\n// @private\n// @param {module:engine/view/containerelement~ContainerElement} caption\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @returns {Boolean} Returns `true` if the view was modified.\nfunction hideCaptionIfEmpty(caption, viewWriter) {\n if (!caption.childCount && !caption.hasClass('ck-hidden')) {\n viewWriter.addClass('ck-hidden', caption);\n return true;\n }\n return false;\n}\n// Shows the caption.\n//\n// @private\n// @param {module:engine/view/containerelement~ContainerElement} caption\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @returns {Boolean} Returns `true` if the view was modified.\nfunction showCaption(caption, viewWriter) {\n if (caption.hasClass('ck-hidden')) {\n viewWriter.removeClass('ck-hidden', caption);\n return true;\n }\n return false;\n}","/**\n * @license Copyright (c) 2003-2020, 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 image/imagestyle/imagestylecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { isImage } from '../image/utils';\n\n/**\n * The image style command. It is used to apply different image styles.\n *\n * @extends module:core/command~Command\n */\nexport default class ImageStyleCommand extends Command {\n\t/**\n\t * Creates an instance of the image style command. Each command instance is handling one style.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles The styles that this command supports.\n\t */\n\tconstructor( editor, styles ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The name of the default style, if it is present. If there is no default style, it defaults to `false`.\n\t\t *\n\t\t * @readonly\n\t\t * @type {Boolean|String}\n\t\t */\n\t\tthis.defaultStyle = false;\n\n\t\t/**\n\t\t * A style handled by this command.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} #styles\n\t\t */\n\t\tthis.styles = styles.reduce( ( styles, style ) => {\n\t\t\tstyles[ style.name ] = style;\n\n\t\t\tif ( style.isDefault ) {\n\t\t\t\tthis.defaultStyle = style.name;\n\t\t\t}\n\n\t\t\treturn styles;\n\t\t}, {} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst element = this.editor.model.document.selection.getSelectedElement();\n\n\t\tthis.isEnabled = isImage( element );\n\n\t\tif ( !element ) {\n\t\t\tthis.value = false;\n\t\t} else if ( element.hasAttribute( 'imageStyle' ) ) {\n\t\t\tconst attributeValue = element.getAttribute( 'imageStyle' );\n\t\t\tthis.value = this.styles[ attributeValue ] ? attributeValue : false;\n\t\t} else {\n\t\t\tthis.value = this.defaultStyle;\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t *\t\teditor.execute( 'imageStyle', { value: 'side' } );\n\t *\n\t * @param {Object} options\n\t * @param {String} options.value The name of the style (based on the\n\t * {@link module:image/image~ImageConfig#styles `image.styles`} configuration option).\n\t * @fires execute\n\t */\n\texecute( options ) {\n\t\tconst styleName = options.value;\n\n\t\tconst model = this.editor.model;\n\t\tconst imageElement = model.document.selection.getSelectedElement();\n\n\t\tmodel.change( writer => {\n\t\t\t// Default style means that there is no `imageStyle` attribute in the model.\n\t\t\t// https://github.com/ckeditor/ckeditor5-image/issues/147\n\t\t\tif ( this.styles[ styleName ].isDefault ) {\n\t\t\t\twriter.removeAttribute( 'imageStyle', imageElement );\n\t\t\t} else {\n\t\t\t\twriter.setAttribute( 'imageStyle', styleName, imageElement );\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * @module image/imagestyle/converters\n */\n\n/**\n * Returns a converter for the `imageStyle` attribute. It can be used for adding, changing and removing the attribute.\n *\n * @param {Object} styles An object containing available styles. See {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}\n * for more details.\n * @returns {Function} A model-to-view attribute converter.\n */\nexport function modelToViewStyleAttribute( styles ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if there is class name associated with given value.\n\t\tconst newStyle = getStyleByName( data.attributeNewValue, styles );\n\t\tconst oldStyle = getStyleByName( data.attributeOldValue, styles );\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\tif ( oldStyle ) {\n\t\t\tviewWriter.removeClass( oldStyle.className, viewElement );\n\t\t}\n\n\t\tif ( newStyle ) {\n\t\t\tviewWriter.addClass( newStyle.className, viewElement );\n\t\t}\n\t};\n}\n\n/**\n * Returns a view-to-model converter converting image CSS classes to a proper value in the model.\n *\n * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles The styles for which the converter is created.\n * @returns {Function} A view-to-model converter.\n */\nexport function viewToModelStyleAttribute( styles ) {\n\t// Convert only non–default styles.\n\tconst filteredStyles = styles.filter( style => !style.isDefault );\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !data.modelRange ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewFigureElement = data.viewItem;\n\t\tconst modelImageElement = first( data.modelRange.getItems() );\n\n\t\t// Check if `imageStyle` attribute is allowed for current element.\n\t\tif ( !conversionApi.schema.checkAttribute( modelImageElement, 'imageStyle' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Convert style one by one.\n\t\tfor ( const style of filteredStyles ) {\n\t\t\t// Try to consume class corresponding with style.\n\t\t\tif ( conversionApi.consumable.consume( viewFigureElement, { classes: style.className } ) ) {\n\t\t\t\t// And convert this style to model attribute.\n\t\t\t\tconversionApi.writer.setAttribute( 'imageStyle', style.name, modelImageElement );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Returns the style with a given `name` from an array of styles.\n//\n// @param {String} name\n// @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat> } styles\n// @returns {module:image/imagestyle/imagestyleediting~ImageStyleFormat|undefined}\nfunction getStyleByName( name, styles ) {\n\tfor ( const style of styles ) {\n\t\tif ( style.name === name ) {\n\t\t\treturn style;\n\t\t}\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 4.5V3h16v1.5zm2.5 3V12h11V7.5h-11zM4.061 6H15.94c.586 0 1.061.407 1.061.91v5.68c0 .503-.475.91-1.061.91H4.06c-.585 0-1.06-.407-1.06-.91V6.91C3 6.406 3.475 6 4.061 6zM2 16.5V15h16v1.5z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" clip-rule=\\\"evenodd\\\" stroke-linejoin=\\\"round\\\" stroke-miterlimit=\\\"1.414\\\"><path d=\\\"M18 4.5V3H2v1.5h16zm0 3V6h-5.674v1.5H18zm0 3V9h-5.674v1.5H18zm0 3V12h-5.674v1.5H18zm-8.5-6V12h-6V7.5h6zm.818-1.5H2.682C2.305 6 2 6.407 2 6.91v5.68c0 .503.305.91.682.91h7.636c.377 0 .682-.407.682-.91V6.91c0-.503-.305-.91-.682-.91zM18 16.5V15H2v1.5h16z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 4.5V3h16v1.5zm4.5 3V12h7V7.5h-7zM5.758 6h8.484c.419 0 .758.407.758.91v5.681c0 .502-.34.909-.758.909H5.758c-.419 0-.758-.407-.758-.91V6.91c0-.503.34-.91.758-.91zM2 16.5V15h16v1.5z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 4.5V3h16v1.5zm0 3V6h5.674v1.5zm0 3V9h5.674v1.5zm0 3V12h5.674v1.5zm8.5-6V12h6V7.5h-6zM9.682 6h7.636c.377 0 .682.407.682.91v5.68c0 .503-.305.91-.682.91H9.682c-.377 0-.682-.407-.682-.91V6.91c0-.503.305-.91.682-.91zM2 16.5V15h16v1.5z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 image/imagestyle/utils\n */\n\n/* globals console */\n\nimport fullWidthIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/object-full-width.svg';\nimport leftIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/object-left.svg';\nimport centerIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/object-center.svg';\nimport rightIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/object-right.svg';\nimport { attachLinkToDocumentation } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Default image styles provided by the plugin that can be referred in the\n * {@link module:image/image~ImageConfig#styles} configuration.\n *\n * Among them, 2 default semantic content styles are available:\n *\n * * `full` is a full–width image without any CSS class,\n * * `side` is a side image styled with the `image-style-side` CSS class.\n *\n * There are also 3 styles focused on formatting:\n *\n * * `alignLeft` aligns the image to the left using the `image-style-align-left` class,\n * * `alignCenter` centers the image using the `image-style-align-center` class,\n * * `alignRight` aligns the image to the right using the `image-style-align-right` class,\n *\n * @member {Object.<String,Object>}\n */\nconst defaultStyles = {\n\t// This option is equal to the situation when no style is applied.\n\tfull: {\n\t\tname: 'full',\n\t\ttitle: 'Full size image',\n\t\ticon: fullWidthIcon,\n\t\tisDefault: true\n\t},\n\n\t// This represents a side image.\n\tside: {\n\t\tname: 'side',\n\t\ttitle: 'Side image',\n\t\ticon: rightIcon,\n\t\tclassName: 'image-style-side'\n\t},\n\n\t// This style represents an image aligned to the left.\n\talignLeft: {\n\t\tname: 'alignLeft',\n\t\ttitle: 'Left aligned image',\n\t\ticon: leftIcon,\n\t\tclassName: 'image-style-align-left'\n\t},\n\n\t// This style represents a centered image.\n\talignCenter: {\n\t\tname: 'alignCenter',\n\t\ttitle: 'Centered image',\n\t\ticon: centerIcon,\n\t\tclassName: 'image-style-align-center'\n\t},\n\n\t// This style represents an image aligned to the right.\n\talignRight: {\n\t\tname: 'alignRight',\n\t\ttitle: 'Right aligned image',\n\t\ticon: rightIcon,\n\t\tclassName: 'image-style-align-right'\n\t}\n};\n\n/**\n * Default image style icons provided by the plugin that can be referred in the\n * {@link module:image/image~ImageConfig#styles} configuration.\n *\n * There are 4 icons available: `'full'`, `'left'`, `'center'` and `'right'`.\n *\n * @member {Object.<String, String>}\n */\nconst defaultIcons = {\n\tfull: fullWidthIcon,\n\tleft: leftIcon,\n\tright: rightIcon,\n\tcenter: centerIcon\n};\n\n/**\n * Returns a {@link module:image/image~ImageConfig#styles} array with items normalized in the\n * {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat} format and a complete `icon` markup for each style.\n *\n * @returns {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>}\n */\nexport function normalizeImageStyles( configuredStyles = [] ) {\n\treturn configuredStyles.map( _normalizeStyle );\n}\n\n// Normalizes an image style provided in the {@link module:image/image~ImageConfig#styles}\n// and returns it in a {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}.\n//\n// @param {Object} style\n// @returns {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}\nfunction _normalizeStyle( style ) {\n\t// Just the name of the style has been passed.\n\tif ( typeof style == 'string' ) {\n\t\tconst styleName = style;\n\n\t\t// If it's one of the defaults, just use it.\n\t\tif ( defaultStyles[ styleName ] ) {\n\t\t\t// Clone the style to avoid overriding defaults.\n\t\t\tstyle = Object.assign( {}, defaultStyles[ styleName ] );\n\t\t}\n\t\t// If it's just a name but none of the defaults, warn because probably it's a mistake.\n\t\telse {\n\t\t\tconsole.warn(\n\t\t\t\tattachLinkToDocumentation( 'image-style-not-found: There is no such image style of given name.' ),\n\t\t\t\t{ name: styleName }\n\t\t\t);\n\n\t\t\t// Normalize the style anyway to prevent errors.\n\t\t\tstyle = {\n\t\t\t\tname: styleName\n\t\t\t};\n\t\t}\n\t}\n\t// If an object style has been passed and if the name matches one of the defaults,\n\t// extend it with defaults – the user wants to customize a default style.\n\t// Note: Don't override the user–defined style object, clone it instead.\n\telse if ( defaultStyles[ style.name ] ) {\n\t\tconst defaultStyle = defaultStyles[ style.name ];\n\t\tconst extendedStyle = Object.assign( {}, style );\n\n\t\tfor ( const prop in defaultStyle ) {\n\t\t\tif ( !style.hasOwnProperty( prop ) ) {\n\t\t\t\textendedStyle[ prop ] = defaultStyle[ prop ];\n\t\t\t}\n\t\t}\n\n\t\tstyle = extendedStyle;\n\t}\n\n\t// If an icon is defined as a string and correspond with a name\n\t// in default icons, use the default icon provided by the plugin.\n\tif ( typeof style.icon == 'string' && defaultIcons[ style.icon ] ) {\n\t\tstyle.icon = defaultIcons[ style.icon ];\n\t}\n\n\treturn style;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 image/imagestyle/imagestyleediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageStyleCommand from './imagestylecommand';\nimport { viewToModelStyleAttribute, modelToViewStyleAttribute } from './converters';\nimport { normalizeImageStyles } from './utils';\n\n/**\n * The image style engine plugin. It sets the default configuration, creates converters and registers\n * {@link module:image/imagestyle/imagestylecommand~ImageStyleCommand ImageStyleCommand}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageStyleEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageStyleEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst data = editor.data;\n\t\tconst editing = editor.editing;\n\n\t\t// Define default configuration.\n\t\teditor.config.define( 'image.styles', [ 'full', 'side' ] );\n\n\t\t// Get configuration.\n\t\tconst styles = normalizeImageStyles( editor.config.get( 'image.styles' ) );\n\n\t\t// Allow imageStyle attribute in image.\n\t\t// We could call it 'style' but https://github.com/ckeditor/ckeditor5-engine/issues/559.\n\t\tschema.extend( 'image', { allowAttributes: 'imageStyle' } );\n\n\t\t// Converters for imageStyle attribute from model to view.\n\t\tconst modelToViewConverter = modelToViewStyleAttribute( styles );\n\t\tediting.downcastDispatcher.on( 'attribute:imageStyle:image', modelToViewConverter );\n\t\tdata.downcastDispatcher.on( 'attribute:imageStyle:image', modelToViewConverter );\n\n\t\t// Converter for figure element from view to model.\n\t\tdata.upcastDispatcher.on( 'element:figure', viewToModelStyleAttribute( styles ), { priority: 'low' } );\n\n\t\t// Register imageStyle command.\n\t\teditor.commands.add( 'imageStyle', new ImageStyleCommand( editor, styles ) );\n\t}\n}\n\n/**\n * The image style format descriptor.\n *\n *\t\timport fullSizeIcon from 'path/to/icon.svg';\n *\n *\t\tconst imageStyleFormat = {\n *\t\t\tname: 'fullSize',\n *\t\t\ticon: fullSizeIcon,\n *\t\t\ttitle: 'Full size image',\n *\t\t\tclassName: 'image-full-size'\n *\t\t}\n *\n * @typedef {Object} module:image/imagestyle/imagestyleediting~ImageStyleFormat\n *\n * @property {String} name The unique name of the style. It will be used to:\n *\n * * Store the chosen style in the model by setting the `imageStyle` attribute of the `<image>` element.\n * * As a value of the {@link module:image/imagestyle/imagestylecommand~ImageStyleCommand#execute `imageStyle` command},\n * * when registering a button for each of the styles (`'imageStyle:{name}'`) in the\n * {@link module:ui/componentfactory~ComponentFactory UI components factory} (this functionality is provided by the\n * {@link module:image/imagestyle/imagestyleui~ImageStyleUI} plugin).\n *\n * @property {Boolean} [isDefault] When set, the style will be used as the default one.\n * A default style does not apply any CSS class to the view element.\n *\n * @property {String} icon One of the following to be used when creating the style's button:\n *\n * * An SVG icon source (as an XML string).\n * * One of {@link module:image/imagestyle/utils~defaultIcons} to use a default icon provided by the plugin.\n *\n * @property {String} title The style's title.\n *\n * @property {String} className The CSS class used to represent the style in the view.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module image/imagestyle/imagestyleui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport { normalizeImageStyles } from './utils';\nimport '../../theme/imagestyle.css';\n/**\n * The image style UI plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageStyleUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'ImageStyleUI';\n }\n /**\n\t * Returns the default localized style titles provided by the plugin.\n\t *\n\t * The following localized titles corresponding with\n\t * {@link module:image/imagestyle/utils~defaultStyles} are available:\n\t *\n\t * * `'Full size image'`,\n\t * * `'Side image'`,\n\t * * `'Left aligned image'`,\n\t * * `'Centered image'`,\n\t * * `'Right aligned image'`\n\t *\n\t * @returns {Object.<String,String>}\n\t */\n get localizedDefaultStylesTitles() {\n const t = this.editor.t;\n return {\n 'Full size image': t('n'),\n 'Side image': t('o'),\n 'Left aligned image': t('p'),\n 'Centered image': t('q'),\n 'Right aligned image': t('r')\n };\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const configuredStyles = editor.config.get('image.styles');\n const translatedStyles = translateStyles(normalizeImageStyles(configuredStyles), this.localizedDefaultStylesTitles);\n for (const style of translatedStyles) {\n this._createButton(style);\n }\n }\n /**\n\t * Creates a button for each style and stores it in the editor {@link module:ui/componentfactory~ComponentFactory ComponentFactory}.\n\t *\n\t * @private\n\t * @param {module:image/imagestyle/imagestyleediting~ImageStyleFormat} style\n\t */\n _createButton(style) {\n const editor = this.editor;\n const componentName = `imageStyle:${ style.name }`;\n editor.ui.componentFactory.add(componentName, locale => {\n const command = editor.commands.get('imageStyle');\n const view = new ButtonView(locale);\n view.set({\n label: style.title,\n icon: style.icon,\n tooltip: true,\n isToggleable: true\n });\n view.bind('isEnabled').to(command, 'isEnabled');\n view.bind('isOn').to(command, 'value', value => value === style.name);\n this.listenTo(view, 'execute', () => {\n editor.execute('imageStyle', { value: style.name });\n editor.editing.view.focus();\n });\n return view;\n });\n }\n}\n/**\n * Returns the translated `title` from the passed styles array.\n *\n * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles\n * @param titles\n * @returns {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>}\n */\nfunction translateStyles(styles, titles) {\n for (const style of styles) {\n // Localize the titles of the styles, if a title corresponds with\n // a localized default provided by the plugin.\n if (titles[style.title]) {\n style.title = titles[style.title];\n }\n }\n return styles;\n}","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module widget/widgettoolbarrepository\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';\nimport ToolbarView from '@ckeditor/ckeditor5-ui/src/toolbar/toolbarview';\nimport BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview';\nimport { isWidget } from './utils';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n/**\n * Widget toolbar repository plugin. A central point for registering widget toolbars. This plugin handles the whole\n * toolbar rendering process and exposes a concise API.\n *\n * To add a toolbar for your widget use the {@link ~WidgetToolbarRepository#register `WidgetToolbarRepository#register()`} method.\n *\n * The following example comes from the {@link module:image/imagetoolbar~ImageToolbar} plugin:\n *\n * \t\tclass ImageToolbar extends Plugin {\n *\t\t\tstatic get requires() {\n *\t\t\t\treturn [ WidgetToolbarRepository ];\n *\t\t\t}\n *\n *\t\t\tafterInit() {\n *\t\t\t\tconst editor = this.editor;\n *\t\t\t\tconst widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );\n *\n *\t\t\t\twidgetToolbarRepository.register( 'image', {\n *\t\t\t\t\titems: editor.config.get( 'image.toolbar' ),\n *\t\t\t\t\tgetRelatedElement: getSelectedImageWidget\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n */\nexport default class WidgetToolbarRepository extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get requires() {\n return [ContextualBalloon];\n }\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'WidgetToolbarRepository';\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n // Disables the default balloon toolbar for all widgets.\n if (editor.plugins.has('BalloonToolbar')) {\n const balloonToolbar = editor.plugins.get('BalloonToolbar');\n this.listenTo(balloonToolbar, 'show', evt => {\n if (isWidgetSelected(editor.editing.view.document.selection)) {\n evt.stop();\n }\n }, { priority: 'high' });\n }\n /**\n\t\t * A map of toolbar definitions.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map.<String,module:widget/widgettoolbarrepository~WidgetRepositoryToolbarDefinition>} #_toolbarDefinitions\n\t\t */\n this._toolbarDefinitions = new Map();\n /**\n\t\t * @private\n\t\t */\n this._balloon = this.editor.plugins.get('ContextualBalloon');\n this.on('change:isEnabled', () => {\n this._updateToolbarsVisibility();\n });\n this.listenTo(editor.ui, 'update', () => {\n this._updateToolbarsVisibility();\n });\n // UI#update is not fired after focus is back in editor, we need to check if balloon panel should be visible.\n this.listenTo(editor.ui.focusTracker, 'change:isFocused', () => {\n this._updateToolbarsVisibility();\n }, { priority: 'low' });\n }\n destroy() {\n super.destroy();\n for (const toolbarConfig of this._toolbarDefinitions.values()) {\n toolbarConfig.view.destroy();\n }\n }\n /**\n\t * Registers toolbar in the WidgetToolbarRepository. It renders it in the `ContextualBalloon` based on the value of the invoked\n\t * `getRelatedElement` function. Toolbar items are gathered from `items` array.\n\t * The balloon's CSS class is by default `ck-toolbar-container` and may be override with the `balloonClassName` option.\n\t *\n\t * Note: This method should be called in the {@link module:core/plugin~PluginInterface#afterInit `Plugin#afterInit()`}\n\t * callback (or later) to make sure that the given toolbar items were already registered by other plugins.\n\t *\n\t * @param {String} toolbarId An id for the toolbar. Used to\n\t * @param {Object} options\n\t * @param {String} [options.ariaLabel] Label used by assistive technologies to describe this toolbar element.\n\t * @param {Array.<String>} options.items Array of toolbar items.\n\t * @param {Function} options.getRelatedElement Callback which returns an element the toolbar should be attached to.\n\t * @param {String} [options.balloonClassName='ck-toolbar-container'] CSS class for the widget balloon.\n\t */\n register(toolbarId, {ariaLabel, items, getRelatedElement, balloonClassName = 'ck-toolbar-container'}) {\n const editor = this.editor;\n const t = editor.t;\n const toolbarView = new ToolbarView(editor.locale);\n toolbarView.ariaLabel = ariaLabel || t('aj');\n if (this._toolbarDefinitions.has(toolbarId)) {\n /**\n\t\t\t * Toolbar with the given id was already added.\n\t\t\t *\n\t\t\t * @error widget-toolbar-duplicated\n\t\t\t * @param toolbarId Toolbar id.\n\t\t\t */\n throw new CKEditorError('widget-toolbar-duplicated: Toolbar with the given id was already added.', this, { toolbarId });\n }\n toolbarView.fillFromConfig(items, editor.ui.componentFactory);\n this._toolbarDefinitions.set(toolbarId, {\n view: toolbarView,\n getRelatedElement,\n balloonClassName\n });\n }\n /**\n\t * Iterates over stored toolbars and makes them visible or hidden.\n\t *\n\t * @private\n\t */\n _updateToolbarsVisibility() {\n let maxRelatedElementDepth = 0;\n let deepestRelatedElement = null;\n let deepestToolbarDefinition = null;\n for (const definition of this._toolbarDefinitions.values()) {\n const relatedElement = definition.getRelatedElement(this.editor.editing.view.document.selection);\n if (!this.isEnabled || !relatedElement) {\n if (this._isToolbarInBalloon(definition)) {\n this._hideToolbar(definition);\n }\n } else if (!this.editor.ui.focusTracker.isFocused) {\n if (this._isToolbarVisible(definition)) {\n this._hideToolbar(definition);\n }\n } else {\n const relatedElementDepth = relatedElement.getAncestors().length;\n // Many toolbars can express willingness to be displayed but they do not know about\n // each other. Figure out which toolbar is deepest in the view tree to decide which\n // should be displayed. For instance, if a selected image is inside a table cell, display\n // the ImageToolbar rather than the TableToolbar (#60).\n if (relatedElementDepth > maxRelatedElementDepth) {\n maxRelatedElementDepth = relatedElementDepth;\n deepestRelatedElement = relatedElement;\n deepestToolbarDefinition = definition;\n }\n }\n }\n if (deepestToolbarDefinition) {\n this._showToolbar(deepestToolbarDefinition, deepestRelatedElement);\n }\n }\n /**\n\t * Hides the given toolbar.\n\t *\n\t * @private\n\t * @param {module:widget/widgettoolbarrepository~WidgetRepositoryToolbarDefinition} toolbarDefinition\n\t */\n _hideToolbar(toolbarDefinition) {\n this._balloon.remove(toolbarDefinition.view);\n this.stopListening(this._balloon, 'change:visibleView');\n }\n /**\n\t * Shows up the toolbar if the toolbar is not visible.\n\t * Otherwise, repositions the toolbar's balloon when toolbar's view is the most top view in balloon stack.\n\t *\n\t * It might happen here that the toolbar's view is under another view. Then do nothing as the other toolbar view\n\t * should be still visible after the {@link module:core/editor/editorui~EditorUI#event:update}.\n\t *\n\t * @private\n\t * @param {module:widget/widgettoolbarrepository~WidgetRepositoryToolbarDefinition} toolbarDefinition\n\t * @param {module:engine/view/element~Element} relatedElement\n\t */\n _showToolbar(toolbarDefinition, relatedElement) {\n if (this._isToolbarVisible(toolbarDefinition)) {\n repositionContextualBalloon(this.editor, relatedElement);\n } else if (!this._isToolbarInBalloon(toolbarDefinition)) {\n this._balloon.add({\n view: toolbarDefinition.view,\n position: getBalloonPositionData(this.editor, relatedElement),\n balloonClassName: toolbarDefinition.balloonClassName\n });\n // Update toolbar position each time stack with toolbar view is switched to visible.\n // This is in a case target element has changed when toolbar was in invisible stack\n // e.g. target image was wrapped by a block quote.\n // See https://github.com/ckeditor/ckeditor5-widget/issues/92.\n this.listenTo(this._balloon, 'change:visibleView', () => {\n for (const definition of this._toolbarDefinitions.values()) {\n if (this._isToolbarVisible(definition)) {\n const relatedElement = definition.getRelatedElement(this.editor.editing.view.document.selection);\n repositionContextualBalloon(this.editor, relatedElement);\n }\n }\n });\n }\n }\n /**\n\t * @private\n\t * @param {Object} toolbar\n\t * @returns {Boolean}\n\t */\n _isToolbarVisible(toolbar) {\n return this._balloon.visibleView === toolbar.view;\n }\n /**\n\t * @private\n\t * @param {Object} toolbar\n\t * @returns {Boolean}\n\t */\n _isToolbarInBalloon(toolbar) {\n return this._balloon.hasView(toolbar.view);\n }\n}\nfunction repositionContextualBalloon(editor, relatedElement) {\n const balloon = editor.plugins.get('ContextualBalloon');\n const position = getBalloonPositionData(editor, relatedElement);\n balloon.updatePosition(position);\n}\nfunction getBalloonPositionData(editor, relatedElement) {\n const editingView = editor.editing.view;\n const defaultPositions = BalloonPanelView.defaultPositions;\n return {\n target: editingView.domConverter.mapViewToDom(relatedElement),\n positions: [\n defaultPositions.northArrowSouth,\n defaultPositions.northArrowSouthWest,\n defaultPositions.northArrowSouthEast,\n defaultPositions.southArrowNorth,\n defaultPositions.southArrowNorthWest,\n defaultPositions.southArrowNorthEast\n ]\n };\n}\nfunction isWidgetSelected(selection) {\n const viewElement = selection.getSelectedElement();\n return !!(viewElement && isWidget(viewElement));\n} /**\n * The toolbar definition object used by the toolbar repository to manage toolbars.\n * It contains information necessary to display the toolbar in the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} and\n * update it during its life (display) cycle.\n *\n * @typedef {Object} module:widget/widgettoolbarrepository~WidgetRepositoryToolbarDefinition\n *\n * @property {module:ui/view~View} view The UI view of the toolbar.\n * @property {Function} getRelatedElement A function that returns an engine {@link module:engine/view/view~View}\n * element the toolbar is to be attached to. For instance, an image widget or a table widget (or `null` when\n * there is no such element). The function accepts an instance of {@link module:engine/view/selection~Selection}.\n * @property {String} balloonClassName CSS class for the widget balloon when a toolbar is displayed.\n */","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport Command from './command';\n\n/**\n * @module core/multicommand\n */\n\n/**\n * A CKEditor command that aggregates other commands.\n *\n * This command is used to proxy multiple commands. The multi-command is enabled when\n * at least one of its registered child commands is enabled.\n * When executing a multi-command the first command that is enabled will be executed.\n *\n *\t\tconst multiCommand = new MultiCommand( editor );\n *\n *\t\tconst commandFoo = new Command( editor );\n *\t\tconst commandBar = new Command( editor );\n *\n *\t\t// Register child commands.\n *\t\tmultiCommand.registerChildCommand( commandFoo );\n *\t\tmultiCommand.registerChildCommand( commandBar );\n *\n *\t\t// Enable one of the commands.\n *\t\tcommandBar.isEnabled = true;\n *\n *\t\tmultiCommand.execute(); // Will execute commandBar.\n *\n * @extends module:core/command~Command\n */\nexport default class MultiCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * Registered child commands.\n\t\t *\n\t\t * @type {Array.<module:core/command~Command>}\n\t\t * @private\n\t\t */\n\t\tthis._childCommands = [];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\t// Override base command refresh(): the command's state is changed when one of child commands changes states.\n\t}\n\n\t/**\n\t * Executes the first of it registered child commands.\n\t */\n\texecute( ...args ) {\n\t\tconst command = this._getFirstEnabledCommand();\n\n\t\tcommand.execute( args );\n\t}\n\n\t/**\n\t * Registers a child command.\n\t *\n\t * @param {module:core/command~Command} command\n\t */\n\tregisterChildCommand( command ) {\n\t\tthis._childCommands.push( command );\n\n\t\t// Change multi command enabled state when one of registered commands changes state.\n\t\tcommand.on( 'change:isEnabled', () => this._checkEnabled() );\n\n\t\tthis._checkEnabled();\n\t}\n\n\t/**\n\t * Checks if any of child commands is enabled.\n\t *\n\t * @private\n\t */\n\t_checkEnabled() {\n\t\tthis.isEnabled = !!this._getFirstEnabledCommand();\n\t}\n\n\t/**\n\t * Returns a first enabled command or undefined if none of them is enabled.\n\t *\n\t * @returns {module:core/command~Command|undefined}\n\t * @private\n\t */\n\t_getFirstEnabledCommand() {\n\t\treturn this._childCommands.find( command => command.isEnabled );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 indent/indentediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport MultiCommand from '@ckeditor/ckeditor5-core/src/multicommand';\n\n/**\n * The indent editing feature.\n *\n * This plugin registers the `'indent'` and `'outdent'` commands.\n *\n * **Note**: In order for the commands to work, at least one of the compatible features is required. Read more in the\n * {@link module:indent/indent~Indent indent feature} API documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class IndentEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'IndentEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.commands.add( 'indent', new MultiCommand( editor ) );\n\t\teditor.commands.add( 'outdent', new MultiCommand( editor ) );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm5 6c0 .414.336.75.75.75h9.5a.75.75 0 100-1.5h-9.5a.75.75 0 00-.75.75zM2.75 16.5h14.5a.75.75 0 100-1.5H2.75a.75.75 0 100 1.5zM1.632 6.95L5.02 9.358a.4.4 0 01-.013.661l-3.39 2.207A.4.4 0 011 11.892V7.275a.4.4 0 01.632-.326z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm5 6c0 .414.336.75.75.75h9.5a.75.75 0 100-1.5h-9.5a.75.75 0 00-.75.75zM2.75 16.5h14.5a.75.75 0 100-1.5H2.75a.75.75 0 100 1.5zM4.368 6.95L.98 9.358a.4.4 0 00.013.661l3.39 2.207A.4.4 0 005 11.892V7.275a.4.4 0 00-.632-.326z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module indent/indentui\n */\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport indentIcon from '../theme/assets/icons/indent.svg';\nimport outdentIcon from '../theme/assets/icons/outdent.svg';\n/**\n * The indent UI feature.\n *\n * This plugin registers the `'indent'` and `'outdent'` buttons.\n *\n * **Note**: In order for the commands to work, at least one of the compatible features is required. Read more in\n * the {@link module:indent/indent~Indent indent feature} API documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class IndentUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'IndentUI';\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const locale = editor.locale;\n const t = editor.t;\n const localizedIndentIcon = locale.uiLanguageDirection == 'ltr' ? indentIcon : outdentIcon;\n const localizedOutdentIcon = locale.uiLanguageDirection == 'ltr' ? outdentIcon : indentIcon;\n this._defineButton('indent', t('u'), localizedIndentIcon);\n this._defineButton('outdent', t('v'), localizedOutdentIcon);\n }\n /**\n\t * Defines a UI button.\n\t *\n\t * @param {String} commandName\n\t * @param {String} label\n\t * @param {String} icon\n\t * @private\n\t */\n _defineButton(commandName, label, icon) {\n const editor = this.editor;\n editor.ui.componentFactory.add(commandName, locale => {\n const command = editor.commands.get(commandName);\n const view = new ButtonView(locale);\n view.set({\n label,\n icon,\n tooltip: true\n });\n view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n this.listenTo(view, 'execute', () => {\n editor.execute(commandName);\n editor.editing.view.focus();\n });\n return view;\n });\n }\n}","\n/**\n * @license Copyright (c) 2003-2020, 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 engine/view/observer/clickobserver\n */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * {@link module:engine/view/document~Document#event:click Click} event observer.\n *\n * Note that this observer is not available by default. To make it available it needs to be added to\n * {@link module:engine/view/view~View view controller}\n * by a {@link module:engine/view/view~View#addObserver} method.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class ClickObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = 'click';\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired when one of the editables has been clicked.\n *\n * Introduced by {@link module:engine/view/observer/clickobserver~ClickObserver}.\n *\n * Note that this event is not available by default. To make it available\n * {@link module:engine/view/observer/clickobserver~ClickObserver} needs to be added\n * to {@link module:engine/view/view~View} by a {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:engine/view/observer/clickobserver~ClickObserver\n * @event module:engine/view/document~Document#event:click\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module link/ui/linkformview\n */\nimport View from '@ckeditor/ckeditor5-ui/src/view';\nimport ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport SwitchButtonView from '@ckeditor/ckeditor5-ui/src/button/switchbuttonview';\nimport LabeledInputView from '@ckeditor/ckeditor5-ui/src/labeledinput/labeledinputview';\nimport InputTextView from '@ckeditor/ckeditor5-ui/src/inputtext/inputtextview';\nimport submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport checkIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/check.svg';\nimport cancelIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/cancel.svg';\nimport '../../theme/linkform.css';\n/**\n * The link form view controller class.\n *\n * See {@link module:link/ui/linkformview~LinkFormView}.\n *\n * @extends module:ui/view~View\n */\nexport default class LinkFormView extends View {\n /**\n\t * Creates an instance of the {@link module:link/ui/linkformview~LinkFormView} class.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t * @param {module:utils/collection~Collection} [manualDecorators] Reference to manual decorators in\n\t * {@link module:link/linkcommand~LinkCommand#manualDecorators}.\n\t */\n constructor(locale, manualDecorators = []) {\n super(locale);\n const t = locale.t;\n /**\n\t\t * Tracks information about DOM focus in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n this.focusTracker = new FocusTracker();\n /**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n this.keystrokes = new KeystrokeHandler();\n /**\n\t\t * The URL input view.\n\t\t *\n\t\t * @member {module:ui/labeledinput/labeledinputview~LabeledInputView}\n\t\t */\n this.urlInputView = this._createUrlInput();\n /**\n\t\t * The Save button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n this.saveButtonView = this._createButton(t('cf'), checkIcon, 'ck-button-save');\n this.saveButtonView.type = 'submit';\n /**\n\t\t * The Cancel button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n this.cancelButtonView = this._createButton(t('cg'), cancelIcon, 'ck-button-cancel', 'cancel');\n /**\n\t\t * A collection of {@link module:ui/button/switchbuttonview~SwitchButtonView},\n\t\t * which corresponds to {@link module:link/linkcommand~LinkCommand#manualDecorators manual decorators}\n\t\t * configured in the editor.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n this._manualDecoratorSwitches = this._createManualDecoratorSwitches(manualDecorators);\n /**\n\t\t * A collection of child views in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n this.children = this._createFormChildren(manualDecorators);\n /**\n\t\t * A collection of views that can be focused in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this._focusables = new ViewCollection();\n /**\n\t\t * Helps cycling over {@link #_focusables} in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n this._focusCycler = new FocusCycler({\n focusables: this._focusables,\n focusTracker: this.focusTracker,\n keystrokeHandler: this.keystrokes,\n actions: {\n // Navigate form fields backwards using the Shift + Tab keystroke.\n focusPrevious: 'shift + tab',\n // Navigate form fields forwards using the Tab key.\n focusNext: 'tab'\n }\n });\n const classList = [\n 'ck',\n 'ck-link-form'\n ];\n if (manualDecorators.length) {\n classList.push('ck-link-form_layout-vertical');\n }\n this.setTemplate({\n tag: 'form',\n attributes: {\n class: classList,\n // https://github.com/ckeditor/ckeditor5-link/issues/90\n tabindex: '-1'\n },\n children: this.children\n });\n }\n /**\n\t * Obtains the state of the {@link module:ui/button/switchbuttonview~SwitchButtonView switch buttons} representing\n\t * {@link module:link/linkcommand~LinkCommand#manualDecorators manual link decorators}\n\t * in the {@link module:link/ui/linkformview~LinkFormView}.\n\t *\n\t * @returns {Object.<String,Boolean>} Key-value pairs, where the key is the name of the decorator and the value is\n\t * its state.\n\t */\n getDecoratorSwitchesState() {\n return Array.from(this._manualDecoratorSwitches).reduce((accumulator, switchButton) => {\n accumulator[switchButton.name] = switchButton.isOn;\n return accumulator;\n }, {});\n }\n /**\n\t * @inheritDoc\n\t */\n render() {\n super.render();\n submitHandler({ view: this });\n const childViews = [\n this.urlInputView,\n ...this._manualDecoratorSwitches,\n this.saveButtonView,\n this.cancelButtonView\n ];\n childViews.forEach(v => {\n // Register the view as focusable.\n this._focusables.add(v);\n // Register the view in the focus tracker.\n this.focusTracker.add(v.element);\n });\n // Start listening for the keystrokes coming from #element.\n this.keystrokes.listenTo(this.element);\n }\n /**\n\t * Focuses the fist {@link #_focusables} in the form.\n\t */\n focus() {\n this._focusCycler.focusFirst();\n }\n /**\n\t * Creates a labeled input view.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledinput/labeledinputview~LabeledInputView} Labeled input view instance.\n\t */\n _createUrlInput() {\n const t = this.locale.t;\n const labeledInput = new LabeledInputView(this.locale, InputTextView);\n labeledInput.label = t('ck');\n labeledInput.inputView.placeholder = 'https://example.com';\n return labeledInput;\n }\n /**\n\t * Creates a button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @param {String} className The additional button CSS class name.\n\t * @param {String} [eventName] An event name that the `ButtonView#execute` event will be delegated to.\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n _createButton(label, icon, className, eventName) {\n const button = new ButtonView(this.locale);\n button.set({\n label,\n icon,\n tooltip: true\n });\n button.extendTemplate({ attributes: { class: className } });\n if (eventName) {\n button.delegate('execute').to(this, eventName);\n }\n return button;\n }\n /**\n\t * Populates {@link module:ui/viewcollection~ViewCollection} of {@link module:ui/button/switchbuttonview~SwitchButtonView}\n\t * made based on {@link module:link/linkcommand~LinkCommand#manualDecorators}.\n\t *\n\t * @private\n\t * @param {module:utils/collection~Collection} manualDecorators A reference to the\n\t * collection of manual decorators stored in the link command.\n\t * @returns {module:ui/viewcollection~ViewCollection} of switch buttons.\n\t */\n _createManualDecoratorSwitches(manualDecorators) {\n const switches = this.createCollection();\n for (const manualDecorator of manualDecorators) {\n const switchButton = new SwitchButtonView(this.locale);\n switchButton.set({\n name: manualDecorator.id,\n label: manualDecorator.label,\n withText: true\n });\n switchButton.bind('isOn').to(manualDecorator, 'value');\n switchButton.on('execute', () => {\n manualDecorator.set('value', !switchButton.isOn);\n });\n switches.add(switchButton);\n }\n return switches;\n }\n /**\n\t * Populates the {@link #children} collection of the form.\n\t *\n\t * If {@link module:link/linkcommand~LinkCommand#manualDecorators manual decorators} are configured in the editor, it creates an\n\t * additional `View` wrapping all {@link #_manualDecoratorSwitches} switch buttons corresponding\n\t * to these decorators.\n\t *\n\t * @private\n\t * @param {module:utils/collection~Collection} manualDecorators A reference to\n\t * the collection of manual decorators stored in the link command.\n\t * @returns {module:ui/viewcollection~ViewCollection} The children of link form view.\n\t */\n _createFormChildren(manualDecorators) {\n const children = this.createCollection();\n children.add(this.urlInputView);\n if (manualDecorators.length) {\n const additionalButtonsView = new View();\n additionalButtonsView.setTemplate({\n tag: 'ul',\n children: this._manualDecoratorSwitches.map(switchButton => ({\n tag: 'li',\n children: [switchButton],\n attributes: {\n class: [\n 'ck',\n 'ck-list__item'\n ]\n }\n })),\n attributes: {\n class: [\n 'ck',\n 'ck-reset',\n 'ck-list'\n ]\n }\n });\n children.add(additionalButtonsView);\n }\n children.add(this.saveButtonView);\n children.add(this.cancelButtonView);\n return children;\n }\n} /**\n * Fired when the form view is submitted (when one of the children triggered the submit event),\n * for example with a click on {@link #saveButtonView}.\n *\n * @event submit\n */\n /**\n * Fired when the form view is canceled, for example with a click on {@link #cancelButtonView}.\n *\n * @event cancel\n */","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module link/ui/linkactionsview\n */\nimport View from '@ckeditor/ckeditor5-ui/src/view';\nimport ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport { ensureSafeUrl } from '../utils';\nimport unlinkIcon from '../../theme/assets/icons/unlink.svg';\nimport pencilIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/pencil.svg';\nimport '../../theme/linkactions.css';\n/**\n * The link actions view class. This view displays the link preview, allows\n * unlinking or editing the link.\n *\n * @extends module:ui/view~View\n */\nexport default class LinkActionsView extends View {\n /**\n\t * @inheritDoc\n\t */\n constructor(locale) {\n super(locale);\n const t = locale.t;\n /**\n\t\t * Tracks information about DOM focus in the actions.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n this.focusTracker = new FocusTracker();\n /**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n this.keystrokes = new KeystrokeHandler();\n /**\n\t\t * The href preview view.\n\t\t *\n\t\t * @member {module:ui/view~View}\n\t\t */\n this.previewButtonView = this._createPreviewButton();\n /**\n\t\t * The unlink button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n this.unlinkButtonView = this._createButton(t('cb'), unlinkIcon, 'unlink');\n /**\n\t\t * The edit link button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n this.editButtonView = this._createButton(t('cc'), pencilIcon, 'edit');\n /**\n\t\t * The value of the \"href\" attribute of the link to use in the {@link #previewButtonView}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String}\n\t\t */\n this.set('href');\n /**\n\t\t * A collection of views that can be focused in the view.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this._focusables = new ViewCollection();\n /**\n\t\t * Helps cycling over {@link #_focusables} in the view.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n this._focusCycler = new FocusCycler({\n focusables: this._focusables,\n focusTracker: this.focusTracker,\n keystrokeHandler: this.keystrokes,\n actions: {\n // Navigate fields backwards using the Shift + Tab keystroke.\n focusPrevious: 'shift + tab',\n // Navigate fields forwards using the Tab key.\n focusNext: 'tab'\n }\n });\n this.setTemplate({\n tag: 'div',\n attributes: {\n class: [\n 'ck',\n 'ck-link-actions'\n ],\n // https://github.com/ckeditor/ckeditor5-link/issues/90\n tabindex: '-1'\n },\n children: [\n this.previewButtonView,\n this.editButtonView,\n this.unlinkButtonView\n ]\n });\n }\n /**\n\t * @inheritDoc\n\t */\n render() {\n super.render();\n const childViews = [\n this.previewButtonView,\n this.editButtonView,\n this.unlinkButtonView\n ];\n childViews.forEach(v => {\n // Register the view as focusable.\n this._focusables.add(v);\n // Register the view in the focus tracker.\n this.focusTracker.add(v.element);\n });\n // Start listening for the keystrokes coming from #element.\n this.keystrokes.listenTo(this.element);\n }\n /**\n\t * Focuses the fist {@link #_focusables} in the actions.\n\t */\n focus() {\n this._focusCycler.focusFirst();\n }\n /**\n\t * Creates a button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @param {String} [eventName] An event name that the `ButtonView#execute` event will be delegated to.\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n _createButton(label, icon, eventName) {\n const button = new ButtonView(this.locale);\n button.set({\n label,\n icon,\n tooltip: true\n });\n button.delegate('execute').to(this, eventName);\n return button;\n }\n /**\n\t * Creates a link href preview button.\n\t *\n\t * @private\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n _createPreviewButton() {\n const button = new ButtonView(this.locale);\n const bind = this.bindTemplate;\n const t = this.t;\n button.set({\n withText: true,\n tooltip: t('cd')\n });\n button.extendTemplate({\n attributes: {\n class: [\n 'ck',\n 'ck-link-actions__preview'\n ],\n href: bind.to('href', href => href && ensureSafeUrl(href)),\n target: '_blank',\n rel: 'noopener noreferrer'\n }\n });\n button.bind('label').to(this, 'href', href => {\n return href || t('ce');\n });\n button.bind('isEnabled').to(this, 'href', href => !!href);\n button.template.tag = 'a';\n button.template.eventListeners = {};\n return button;\n }\n} /**\n * Fired when the {@link #editButtonView} is clicked.\n *\n * @event edit\n */\n /**\n * Fired when the {@link #unlinkButtonView} is clicked.\n *\n * @event unlink\n */","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.077 15l.991-1.416a.75.75 0 111.229.86l-1.148 1.64a.748.748 0 01-.217.206 5.251 5.251 0 01-8.503-5.955.741.741 0 01.12-.274l1.147-1.639a.75.75 0 111.228.86L4.933 10.7l.006.003a3.75 3.75 0 006.132 4.294l.006.004zm5.494-5.335a.748.748 0 01-.12.274l-1.147 1.639a.75.75 0 11-1.228-.86l.86-1.23a3.75 3.75 0 00-6.144-4.301l-.86 1.229a.75.75 0 01-1.229-.86l1.148-1.64a.748.748 0 01.217-.206 5.251 5.251 0 018.503 5.955zm-4.563-2.532a.75.75 0 01.184 1.045l-3.155 4.505a.75.75 0 11-1.229-.86l3.155-4.506a.75.75 0 011.045-.184zm4.919 10.562l-1.414 1.414a.75.75 0 11-1.06-1.06l1.414-1.415-1.415-1.414a.75.75 0 011.061-1.06l1.414 1.414 1.414-1.415a.75.75 0 011.061 1.061l-1.414 1.414 1.414 1.415a.75.75 0 01-1.06 1.06l-1.415-1.414z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M7.3 17.37l-.061.088a1.518 1.518 0 01-.934.535l-4.178.663-.806-4.153a1.495 1.495 0 01.187-1.058l.056-.086L8.77 2.639c.958-1.351 2.803-1.076 4.296-.03 1.497 1.047 2.387 2.693 1.433 4.055L7.3 17.37zM9.14 4.728l-5.545 8.346 3.277 2.294 5.544-8.346L9.14 4.728zM6.07 16.512l-3.276-2.295.53 2.73 2.746-.435zM9.994 3.506L13.271 5.8c.316-.452-.16-1.333-1.065-1.966-.905-.634-1.895-.78-2.212-.328zM8 18.5L9.375 17H19v1.5H8z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module link/linkui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ClickObserver from '@ckeditor/ckeditor5-engine/src/view/observer/clickobserver';\nimport { isLinkElement } from './utils';\nimport ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';\nimport clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport LinkFormView from './ui/linkformview';\nimport LinkActionsView from './ui/linkactionsview';\nimport linkIcon from '../theme/assets/icons/link.svg';\nconst linkKeystroke = 'Ctrl+K';\n/**\n * The link UI plugin. It introduces the `'link'` and `'unlink'` buttons and support for the <kbd>Ctrl+K</kbd> keystroke.\n *\n * It uses the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class LinkUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get requires() {\n return [ContextualBalloon];\n }\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'LinkUI';\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n editor.editing.view.addObserver(ClickObserver);\n /**\n\t\t * The actions view displayed inside of the balloon.\n\t\t *\n\t\t * @member {module:link/ui/linkactionsview~LinkActionsView}\n\t\t */\n this.actionsView = this._createActionsView();\n /**\n\t\t * The form view displayed inside the balloon.\n\t\t *\n\t\t * @member {module:link/ui/linkformview~LinkFormView}\n\t\t */\n this.formView = this._createFormView();\n /**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n this._balloon = editor.plugins.get(ContextualBalloon);\n // Create toolbar buttons.\n this._createToolbarLinkButton();\n // Attach lifecycle actions to the the balloon.\n this._enableUserBalloonInteractions();\n }\n /**\n\t * @inheritDoc\n\t */\n destroy() {\n super.destroy();\n // Destroy created UI components as they are not automatically destroyed (see ckeditor5#1341).\n this.formView.destroy();\n }\n /**\n\t * Creates the {@link module:link/ui/linkactionsview~LinkActionsView} instance.\n\t *\n\t * @private\n\t * @returns {module:link/ui/linkactionsview~LinkActionsView} The link actions view instance.\n\t */\n _createActionsView() {\n const editor = this.editor;\n const actionsView = new LinkActionsView(editor.locale);\n const linkCommand = editor.commands.get('link');\n const unlinkCommand = editor.commands.get('unlink');\n actionsView.bind('href').to(linkCommand, 'value');\n actionsView.editButtonView.bind('isEnabled').to(linkCommand);\n actionsView.unlinkButtonView.bind('isEnabled').to(unlinkCommand);\n // Execute unlink command after clicking on the \"Edit\" button.\n this.listenTo(actionsView, 'edit', () => {\n this._addFormView();\n });\n // Execute unlink command after clicking on the \"Unlink\" button.\n this.listenTo(actionsView, 'unlink', () => {\n editor.execute('unlink');\n this._hideUI();\n });\n // Close the panel on esc key press when the **actions have focus**.\n actionsView.keystrokes.set('Esc', (data, cancel) => {\n this._hideUI();\n cancel();\n });\n // Open the form view on Ctrl+K when the **actions have focus**..\n actionsView.keystrokes.set(linkKeystroke, (data, cancel) => {\n this._addFormView();\n cancel();\n });\n return actionsView;\n }\n /**\n\t * Creates the {@link module:link/ui/linkformview~LinkFormView} instance.\n\t *\n\t * @private\n\t * @returns {module:link/ui/linkformview~LinkFormView} The link form view instance.\n\t */\n _createFormView() {\n const editor = this.editor;\n const linkCommand = editor.commands.get('link');\n const formView = new LinkFormView(editor.locale, linkCommand.manualDecorators);\n formView.urlInputView.bind('value').to(linkCommand, 'value');\n // Form elements should be read-only when corresponding commands are disabled.\n formView.urlInputView.bind('isReadOnly').to(linkCommand, 'isEnabled', value => !value);\n formView.saveButtonView.bind('isEnabled').to(linkCommand);\n // Execute link command after clicking the \"Save\" button.\n this.listenTo(formView, 'submit', () => {\n editor.execute('link', formView.urlInputView.inputView.element.value, formView.getDecoratorSwitchesState());\n this._closeFormView();\n });\n // Hide the panel after clicking the \"Cancel\" button.\n this.listenTo(formView, 'cancel', () => {\n this._closeFormView();\n });\n // Close the panel on esc key press when the **form has focus**.\n formView.keystrokes.set('Esc', (data, cancel) => {\n this._closeFormView();\n cancel();\n });\n return formView;\n }\n /**\n\t * Creates a toolbar Link button. Clicking this button will show\n\t * a {@link #_balloon} attached to the selection.\n\t *\n\t * @private\n\t */\n _createToolbarLinkButton() {\n const editor = this.editor;\n const linkCommand = editor.commands.get('link');\n const t = editor.t;\n // Handle the `Ctrl+K` keystroke and show the panel.\n editor.keystrokes.set(linkKeystroke, (keyEvtData, cancel) => {\n // Prevent focusing the search bar in FF and opening new tab in Edge. #153, #154.\n cancel();\n this._showUI(true);\n });\n editor.ui.componentFactory.add('link', locale => {\n const button = new ButtonView(locale);\n button.isEnabled = true;\n button.label = t('bh');\n button.icon = linkIcon;\n button.keystroke = linkKeystroke;\n button.tooltip = true;\n button.isToggleable = true;\n // Bind button to the command.\n button.bind('isEnabled').to(linkCommand, 'isEnabled');\n button.bind('isOn').to(linkCommand, 'value', value => !!value);\n // Show the panel on button click.\n this.listenTo(button, 'execute', () => this._showUI(true));\n return button;\n });\n }\n /**\n\t * Attaches actions that control whether the balloon panel containing the\n\t * {@link #formView} is visible or not.\n\t *\n\t * @private\n\t */\n _enableUserBalloonInteractions() {\n const viewDocument = this.editor.editing.view.document;\n // Handle click on view document and show panel when selection is placed inside the link element.\n // Keep panel open until selection will be inside the same link element.\n this.listenTo(viewDocument, 'click', () => {\n const parentLink = this._getSelectedLinkElement();\n if (parentLink) {\n // Then show panel but keep focus inside editor editable.\n this._showUI();\n }\n });\n // Focus the form if the balloon is visible and the Tab key has been pressed.\n this.editor.keystrokes.set('Tab', (data, cancel) => {\n if (this._areActionsVisible && !this.actionsView.focusTracker.isFocused) {\n this.actionsView.focus();\n cancel();\n }\n }, {\n // Use the high priority because the link UI navigation is more important\n // than other feature's actions, e.g. list indentation.\n // https://github.com/ckeditor/ckeditor5-link/issues/146\n priority: 'high'\n });\n // Close the panel on the Esc key press when the editable has focus and the balloon is visible.\n this.editor.keystrokes.set('Esc', (data, cancel) => {\n if (this._isUIVisible) {\n this._hideUI();\n cancel();\n }\n });\n // Close on click outside of balloon panel element.\n clickOutsideHandler({\n emitter: this.formView,\n activator: () => this._isUIInPanel,\n contextElements: [this._balloon.view.element],\n callback: () => this._hideUI()\n });\n }\n /**\n\t * Adds the {@link #actionsView} to the {@link #_balloon}.\n\t *\n\t * @protected\n\t */\n _addActionsView() {\n if (this._areActionsInPanel) {\n return;\n }\n this._balloon.add({\n view: this.actionsView,\n position: this._getBalloonPositionData()\n });\n }\n /**\n\t * Adds the {@link #formView} to the {@link #_balloon}.\n\t *\n\t * @protected\n\t */\n _addFormView() {\n if (this._isFormInPanel) {\n return;\n }\n const editor = this.editor;\n const linkCommand = editor.commands.get('link');\n this._balloon.add({\n view: this.formView,\n position: this._getBalloonPositionData()\n });\n // Select input when form view is currently visible.\n if (this._balloon.visibleView === this.formView) {\n this.formView.urlInputView.select();\n }\n // Make sure that each time the panel shows up, the URL field remains in sync with the value of\n // the command. If the user typed in the input, then canceled the balloon (`urlInputView#value` stays\n // unaltered) and re-opened it without changing the value of the link command (e.g. because they\n // clicked the same link), they would see the old value instead of the actual value of the command.\n // https://github.com/ckeditor/ckeditor5-link/issues/78\n // https://github.com/ckeditor/ckeditor5-link/issues/123\n this.formView.urlInputView.inputView.element.value = linkCommand.value || '';\n }\n /**\n\t * Closes the form view. Decides whether the balloon should be hidden completely or if the action view should be shown. This is\n\t * decided upon the link command value (which has a value if the document selection is in the link).\n\t *\n\t * Additionally, if any {@link module:link/link~LinkConfig#decorators} are defined in the editor configuration, the state of\n\t * switch buttons responsible for manual decorator handling is restored.\n\t *\n\t * @private\n\t */\n _closeFormView() {\n const linkCommand = this.editor.commands.get('link');\n // Restore manual decorator states to represent the current model state. This case is important to reset the switch buttons\n // when the user cancels the editing form.\n linkCommand.restoreManualDecoratorStates();\n if (linkCommand.value !== undefined) {\n this._removeFormView();\n } else {\n this._hideUI();\n }\n }\n /**\n\t * Removes the {@link #formView} from the {@link #_balloon}.\n\t *\n\t * @protected\n\t */\n _removeFormView() {\n if (this._isFormInPanel) {\n // Blur the input element before removing it from DOM to prevent issues in some browsers.\n // See https://github.com/ckeditor/ckeditor5/issues/1501.\n this.formView.saveButtonView.focus();\n this._balloon.remove(this.formView);\n // Because the form has an input which has focus, the focus must be brought back\n // to the editor. Otherwise, it would be lost.\n this.editor.editing.view.focus();\n }\n }\n /**\n\t * Shows the correct UI type. It is either {@link #formView} or {@link #actionsView}.\n\t *\n\t * @param {Boolean} forceVisible\n\t * @private\n\t */\n _showUI(forceVisible = false) {\n // When there's no link under the selection, go straight to the editing UI.\n if (!this._getSelectedLinkElement()) {\n this._addActionsView();\n // Be sure panel with link is visible.\n if (forceVisible) {\n this._balloon.showStack('main');\n }\n this._addFormView();\n } // If there's a link under the selection...\n else {\n // Go to the editing UI if actions are already visible.\n if (this._areActionsVisible) {\n this._addFormView();\n } // Otherwise display just the actions UI.\n else {\n this._addActionsView();\n }\n // Be sure panel with link is visible.\n if (forceVisible) {\n this._balloon.showStack('main');\n }\n }\n // Begin responding to ui#update once the UI is added.\n this._startUpdatingUI();\n }\n /**\n\t * Removes the {@link #formView} from the {@link #_balloon}.\n\t *\n\t * See {@link #_addFormView}, {@link #_addActionsView}.\n\t *\n\t * @protected\n\t */\n _hideUI() {\n if (!this._isUIInPanel) {\n return;\n }\n const editor = this.editor;\n this.stopListening(editor.ui, 'update');\n this.stopListening(this._balloon, 'change:visibleView');\n // Make sure the focus always gets back to the editable _before_ removing the focused form view.\n // Doing otherwise causes issues in some browsers. See https://github.com/ckeditor/ckeditor5-link/issues/193.\n editor.editing.view.focus();\n // Remove form first because it's on top of the stack.\n this._removeFormView();\n // Then remove the actions view because it's beneath the form.\n this._balloon.remove(this.actionsView);\n }\n /**\n\t * Makes the UI react to the {@link module:core/editor/editorui~EditorUI#event:update} event to\n\t * reposition itself when the editor UI should be refreshed.\n\t *\n\t * See: {@link #_hideUI} to learn when the UI stops reacting to the `update` event.\n\t *\n\t * @protected\n\t */\n _startUpdatingUI() {\n const editor = this.editor;\n const viewDocument = editor.editing.view.document;\n let prevSelectedLink = this._getSelectedLinkElement();\n let prevSelectionParent = getSelectionParent();\n const update = () => {\n const selectedLink = this._getSelectedLinkElement();\n const selectionParent = getSelectionParent();\n // Hide the panel if:\n //\n // * the selection went out of the EXISTING link element. E.g. user moved the caret out\n // of the link,\n // * the selection went to a different parent when creating a NEW link. E.g. someone\n // else modified the document.\n // * the selection has expanded (e.g. displaying link actions then pressing SHIFT+Right arrow).\n //\n // Note: #_getSelectedLinkElement will return a link for a non-collapsed selection only\n // when fully selected.\n if (prevSelectedLink && !selectedLink || !prevSelectedLink && selectionParent !== prevSelectionParent) {\n this._hideUI();\n } // Update the position of the panel when:\n // * link panel is in the visible stack\n // * the selection remains in the original link element,\n // * there was no link element in the first place, i.e. creating a new link\n else if (this._isUIVisible) {\n // If still in a link element, simply update the position of the balloon.\n // If there was no link (e.g. inserting one), the balloon must be moved\n // to the new position in the editing view (a new native DOM range).\n this._balloon.updatePosition(this._getBalloonPositionData());\n }\n prevSelectedLink = selectedLink;\n prevSelectionParent = selectionParent;\n };\n function getSelectionParent() {\n return viewDocument.selection.focus.getAncestors().reverse().find(node => node.is('element'));\n }\n this.listenTo(editor.ui, 'update', update);\n this.listenTo(this._balloon, 'change:visibleView', update);\n }\n /**\n\t * Returns `true` when {@link #formView} is in the {@link #_balloon}.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n get _isFormInPanel() {\n return this._balloon.hasView(this.formView);\n }\n /**\n\t * Returns `true` when {@link #actionsView} is in the {@link #_balloon}.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n get _areActionsInPanel() {\n return this._balloon.hasView(this.actionsView);\n }\n /**\n\t * Returns `true` when {@link #actionsView} is in the {@link #_balloon} and it is\n\t * currently visible.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n get _areActionsVisible() {\n return this._balloon.visibleView === this.actionsView;\n }\n /**\n\t * Returns `true` when {@link #actionsView} or {@link #formView} is in the {@link #_balloon}.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n get _isUIInPanel() {\n return this._isFormInPanel || this._areActionsInPanel;\n }\n /**\n\t * Returns `true` when {@link #actionsView} or {@link #formView} is in the {@link #_balloon} and it is\n\t * currently visible.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n get _isUIVisible() {\n const visibleView = this._balloon.visibleView;\n return visibleView == this.formView || this._areActionsVisible;\n }\n /**\n\t * Returns positioning options for the {@link #_balloon}. They control the way the balloon is attached\n\t * to the target element or selection.\n\t *\n\t * If the selection is collapsed and inside a link element, the panel will be attached to the\n\t * entire link element. Otherwise, it will be attached to the selection.\n\t *\n\t * @private\n\t * @returns {module:utils/dom/position~Options}\n\t */\n _getBalloonPositionData() {\n const view = this.editor.editing.view;\n const viewDocument = view.document;\n const targetLink = this._getSelectedLinkElement();\n const target = targetLink ? // When selection is inside link element, then attach panel to this element.\n view.domConverter.mapViewToDom(targetLink) : // Otherwise attach panel to the selection.\n view.domConverter.viewRangeToDom(viewDocument.selection.getFirstRange());\n return { target };\n }\n /**\n\t * Returns the link {@link module:engine/view/attributeelement~AttributeElement} under\n\t * the {@link module:engine/view/document~Document editing view's} selection or `null`\n\t * if there is none.\n\t *\n\t * **Note**: For a non–collapsed selection, the link element is only returned when **fully**\n\t * selected and the **only** element within the selection boundaries.\n\t *\n\t * @private\n\t * @returns {module:engine/view/attributeelement~AttributeElement|null}\n\t */\n _getSelectedLinkElement() {\n const view = this.editor.editing.view;\n const selection = view.document.selection;\n if (selection.isCollapsed) {\n return findLinkElementAncestor(selection.getFirstPosition());\n } else {\n // The range for fully selected link is usually anchored in adjacent text nodes.\n // Trim it to get closer to the actual link element.\n const range = selection.getFirstRange().getTrimmed();\n const startLink = findLinkElementAncestor(range.start);\n const endLink = findLinkElementAncestor(range.end);\n if (!startLink || startLink != endLink) {\n return null;\n }\n // Check if the link element is fully selected.\n if (view.createRangeIn(startLink).getTrimmed().isEqual(range)) {\n return startLink;\n } else {\n return null;\n }\n }\n }\n}\n// Returns a link element if there's one among the ancestors of the provided `Position`.\n//\n// @private\n// @param {module:engine/view/position~Position} View position to analyze.\n// @returns {module:engine/view/attributeelement~AttributeElement|null} Link element at the position or null.\nfunction findLinkElementAncestor(position) {\n return position.getAncestors().find(ancestor => isLinkElement(ancestor));\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.077 15l.991-1.416a.75.75 0 111.229.86l-1.148 1.64a.748.748 0 01-.217.206 5.251 5.251 0 01-8.503-5.955.741.741 0 01.12-.274l1.147-1.639a.75.75 0 111.228.86L4.933 10.7l.006.003a3.75 3.75 0 006.132 4.294l.006.004zm5.494-5.335a.748.748 0 01-.12.274l-1.147 1.639a.75.75 0 11-1.228-.86l.86-1.23a3.75 3.75 0 00-6.144-4.301l-.86 1.229a.75.75 0 01-1.229-.86l1.148-1.64a.748.748 0 01.217-.206 5.251 5.251 0 018.503 5.955zm-4.563-2.532a.75.75 0 01.184 1.045l-3.155 4.505a.75.75 0 11-1.229-.86l3.155-4.506a.75.75 0 011.045-.184z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 list/listcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The list command. It is used by the {@link module:list/list~List list feature}.\n *\n * @extends module:core/command~Command\n */\nexport default class ListCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {'numbered'|'bulleted'} type List type that will be handled by this command.\n\t */\n\tconstructor( editor, type ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The type of the list created by the command.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'numbered'|'bulleted'|'todo'}\n\t\t */\n\t\tthis.type = type;\n\n\t\t/**\n\t\t * A flag indicating whether the command is active, which means that the selection starts in a list of the same type.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #value\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.value = this._getValue();\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @protected\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\t\tconst blocks = Array.from( document.selection.getSelectedBlocks() )\n\t\t\t.filter( block => checkCanBecomeListItem( block, model.schema ) );\n\n\t\t// Whether we are turning off some items.\n\t\tconst turnOff = this.value === true;\n\t\t// If we are turning off items, we are going to rename them to paragraphs.\n\n\t\tmodel.change( writer => {\n\t\t\t// If part of a list got turned off, we need to handle (outdent) all of sub-items of the last turned-off item.\n\t\t\t// To be sure that model is all the time in a good state, we first fix items below turned-off item.\n\t\t\tif ( turnOff ) {\n\t\t\t\t// Start from the model item that is just after the last turned-off item.\n\t\t\t\tlet next = blocks[ blocks.length - 1 ].nextSibling;\n\t\t\t\tlet currentIndent = Number.POSITIVE_INFINITY;\n\t\t\t\tlet changes = [];\n\n\t\t\t\t// Correct indent of all items after the last turned off item.\n\t\t\t\t// Rules that should be followed:\n\t\t\t\t// 1. All direct sub-items of turned-off item should become indent 0, because the first item after it\n\t\t\t\t// will be the first item of a new list. Other items are at the same level, so should have same 0 index.\n\t\t\t\t// 2. All items with indent lower than indent of turned-off item should become indent 0, because they\n\t\t\t\t// should not end up as a child of any of list items that they were not children of before.\n\t\t\t\t// 3. All other items should have their indent changed relatively to it's parent.\n\t\t\t\t//\n\t\t\t\t// For example:\n\t\t\t\t// 1 * --------\n\t\t\t\t// 2 * --------\n\t\t\t\t// 3 * --------\t\t\t<-- this is turned off.\n\t\t\t\t// 4 * --------\t\t<-- this has to become indent = 0, because it will be first item on a new list.\n\t\t\t\t// 5 * --------\t<-- this should be still be a child of item above, so indent = 1.\n\t\t\t\t// 6 * --------\t\t\t<-- this has to become indent = 0, because it should not be a child of any of items above.\n\t\t\t\t// 7 * --------\t\t<-- this should be still be a child of item above, so indent = 1.\n\t\t\t\t// 8 * --------\t\t\t\t<-- this has to become indent = 0.\n\t\t\t\t// 9 * --------\t\t\t<-- this should still be a child of item above, so indent = 1.\n\t\t\t\t// 10 * --------\t\t<-- this should still be a child of item above, so indent = 2.\n\t\t\t\t// 11 * --------\t\t<-- this should still be at the same level as item above, so indent = 2.\n\t\t\t\t// 12 * --------\t\t\t\t<-- this and all below are left unchanged.\n\t\t\t\t// 13 * --------\n\t\t\t\t// 14 * --------\n\t\t\t\t//\n\t\t\t\t// After turning off 3 the list becomes:\n\t\t\t\t//\n\t\t\t\t// 1 * --------\n\t\t\t\t// 2 * --------\n\t\t\t\t//\n\t\t\t\t// 3 --------\n\t\t\t\t//\n\t\t\t\t// 4 * --------\n\t\t\t\t// 5 * --------\n\t\t\t\t// 6 * --------\n\t\t\t\t// 7 * --------\n\t\t\t\t// 8 * --------\n\t\t\t\t// 9 * --------\n\t\t\t\t// 10 * --------\n\t\t\t\t// 11 * --------\n\t\t\t\t// 12 * --------\n\t\t\t\t// 13 * --------\n\t\t\t\t// 14 * --------\n\t\t\t\t//\n\t\t\t\t// Thanks to this algorithm no lists are mismatched and no items get unexpected children/parent, while\n\t\t\t\t// those parent-child connection which are possible to maintain are still maintained. It's worth noting\n\t\t\t\t// that this is the same effect that we would be get by multiple use of outdent command. However doing\n\t\t\t\t// it like this is much more efficient because it's less operation (less memory usage, easier OT) and\n\t\t\t\t// less conversion (faster).\n\t\t\t\twhile ( next && next.name == 'listItem' && next.getAttribute( 'listIndent' ) !== 0 ) {\n\t\t\t\t\t// Check each next list item, as long as its indent is bigger than 0.\n\t\t\t\t\t// If the indent is 0 we are not going to change anything anyway.\n\t\t\t\t\tconst indent = next.getAttribute( 'listIndent' );\n\n\t\t\t\t\t// We check if that's item indent is lower as current relative indent.\n\t\t\t\t\tif ( indent < currentIndent ) {\n\t\t\t\t\t\t// If it is, current relative indent becomes that indent.\n\t\t\t\t\t\tcurrentIndent = indent;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fix indent relatively to current relative indent.\n\t\t\t\t\t// Note, that if we just changed the current relative indent, the newIndent will be equal to 0.\n\t\t\t\t\tconst newIndent = indent - currentIndent;\n\n\t\t\t\t\t// Save the entry in changes array. We do not apply it at the moment, because we will need to\n\t\t\t\t\t// reverse the changes so the last item is changed first.\n\t\t\t\t\t// This is to keep model in correct state all the time.\n\t\t\t\t\tchanges.push( { element: next, listIndent: newIndent } );\n\n\t\t\t\t\t// Find next item.\n\t\t\t\t\tnext = next.nextSibling;\n\t\t\t\t}\n\n\t\t\t\tchanges = changes.reverse();\n\n\t\t\t\tfor ( const item of changes ) {\n\t\t\t\t\twriter.setAttribute( 'listIndent', item.listIndent, item.element );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we are turning on, we might change some items that are already `listItem`s but with different type.\n\t\t\t// Changing one nested list item to other type should also trigger changing all its siblings so the\n\t\t\t// whole nested list is of the same type.\n\t\t\t// Example (assume changing to numbered list):\n\t\t\t// * ------\t\t\t\t<-- do not fix, top level item\n\t\t\t// * ------\t\t\t<-- fix, because latter list item of this item's list is changed\n\t\t\t// * ------\t\t<-- do not fix, item is not affected (different list)\n\t\t\t// * ------\t\t\t<-- fix, because latter list item of this item's list is changed\n\t\t\t// * ------\t\t<-- fix, because latter list item of this item's list is changed\n\t\t\t// * ---[--\t\t<-- already in selection\n\t\t\t// * ------\t\t\t<-- already in selection\n\t\t\t// * ------\t\t\t<-- already in selection\n\t\t\t// * ------\t\t\t\t<-- already in selection, but does not cause other list items to change because is top-level\n\t\t\t// * ---]--\t\t\t<-- already in selection\n\t\t\t// * ------\t\t\t<-- fix, because preceding list item of this item's list is changed\n\t\t\t// * ------\t\t<-- do not fix, item is not affected (different list)\n\t\t\t// * ------\t\t\t\t<-- do not fix, top level item\n\t\t\tif ( !turnOff ) {\n\t\t\t\t// Find lowest indent among selected items. This will be indicator what is the indent of\n\t\t\t\t// top-most list affected by the command.\n\t\t\t\tlet lowestIndent = Number.POSITIVE_INFINITY;\n\n\t\t\t\tfor ( const item of blocks ) {\n\t\t\t\t\tif ( item.is( 'listItem' ) && item.getAttribute( 'listIndent' ) < lowestIndent ) {\n\t\t\t\t\t\tlowestIndent = item.getAttribute( 'listIndent' );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Do not execute the fix for top-level lists.\n\t\t\t\tlowestIndent = lowestIndent === 0 ? 1 : lowestIndent;\n\n\t\t\t\t// Fix types of list items that are \"before\" the selected blocks.\n\t\t\t\t_fixType( blocks, true, lowestIndent );\n\n\t\t\t\t// Fix types of list items that are \"after\" the selected blocks.\n\t\t\t\t_fixType( blocks, false, lowestIndent );\n\t\t\t}\n\n\t\t\t// Phew! Now it will be easier :).\n\t\t\t// For each block element that was in the selection, we will either: turn it to list item,\n\t\t\t// turn it to paragraph, or change it's type. Or leave it as it is.\n\t\t\t// Do it in reverse as there might be multiple blocks (same as with changing indents).\n\t\t\tfor ( const element of blocks.reverse() ) {\n\t\t\t\tif ( turnOff && element.name == 'listItem' ) {\n\t\t\t\t\t// We are turning off and the element is a `listItem` - it should be converted to `paragraph`.\n\t\t\t\t\t// List item specific attributes are removed by post fixer.\n\t\t\t\t\twriter.rename( element, 'paragraph' );\n\t\t\t\t} else if ( !turnOff && element.name != 'listItem' ) {\n\t\t\t\t\t// We are turning on and the element is not a `listItem` - it should be converted to `listItem`.\n\t\t\t\t\t// The order of operations is important to keep model in correct state.\n\t\t\t\t\twriter.setAttributes( { listType: this.type, listIndent: 0 }, element );\n\t\t\t\t\twriter.rename( element, 'listItem' );\n\t\t\t\t} else if ( !turnOff && element.name == 'listItem' && element.getAttribute( 'listType' ) != this.type ) {\n\t\t\t\t\t// We are turning on and the element is a `listItem` but has different type - change it's type and\n\t\t\t\t\t// type of it's all siblings that have same indent.\n\t\t\t\t\twriter.setAttribute( 'listType', this.type, element );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the command's {@link #value}.\n\t *\n\t * @private\n\t * @returns {Boolean} The current value.\n\t */\n\t_getValue() {\n\t\t// Check whether closest `listItem` ancestor of the position has a correct type.\n\t\tconst listItem = first( this.editor.model.document.selection.getSelectedBlocks() );\n\n\t\treturn !!listItem && listItem.is( 'listItem' ) && listItem.getAttribute( 'listType' ) == this.type;\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\t// If command value is true it means that we are in list item, so the command should be enabled.\n\t\tif ( this.value ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst schema = this.editor.model.schema;\n\n\t\tconst firstBlock = first( selection.getSelectedBlocks() );\n\n\t\tif ( !firstBlock ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Otherwise, check if list item can be inserted at the position start.\n\t\treturn checkCanBecomeListItem( firstBlock, schema );\n\t}\n}\n\n// Helper function used when one or more list item have their type changed. Fixes type of other list items\n// that are affected by the change (are in same lists) but are not directly in selection. The function got extracted\n// not to duplicated code, as same fix has to be performed before and after selection.\n//\n// @param {Array.<module:engine/model/node~Node>} blocks Blocks that are in selection.\n// @param {Boolean} isBackward Specified whether fix will be applied for blocks before first selected block (`true`)\n// or blocks after last selected block (`false`).\n// @param {Number} lowestIndent Lowest indent among selected blocks.\nfunction _fixType( blocks, isBackward, lowestIndent ) {\n\t// We need to check previous sibling of first changed item and next siblings of last changed item.\n\tconst startingItem = isBackward ? blocks[ 0 ] : blocks[ blocks.length - 1 ];\n\n\tif ( startingItem.is( 'listItem' ) ) {\n\t\tlet item = startingItem[ isBackward ? 'previousSibling' : 'nextSibling' ];\n\t\t// During processing items, keeps the lowest indent of already processed items.\n\t\t// This saves us from changing too many items.\n\t\t// Following example is for going forward as it is easier to read, however same applies to going backward.\n\t\t// * ------\n\t\t// * ------\n\t\t// * --[---\n\t\t// * ------\t\t<-- `lowestIndent` should be 1\n\t\t// * --]---\t\t<-- `startingItem`, `currentIndent` = 2, `lowestIndent` == 1\n\t\t// * ------\t\t<-- should be fixed, `indent` == 2 == `currentIndent`\n\t\t// * ------\t\t<-- should be fixed, set `currentIndent` to 1, `indent` == 1 == `currentIndent`\n\t\t// * ------\t\t<-- should not be fixed, item is in different list, `indent` = 2, `indent` != `currentIndent`\n\t\t// * ------\t\t<-- should be fixed, `indent` == 1 == `currentIndent`\n\t\t// * ------\t\t\t<-- break loop (`indent` < `lowestIndent`)\n\t\tlet currentIndent = startingItem.getAttribute( 'listIndent' );\n\n\t\t// Look back until a list item with indent lower than reference `lowestIndent`.\n\t\t// That would be the parent of nested sublist which contains item having `lowestIndent`.\n\t\twhile ( item && item.is( 'listItem' ) && item.getAttribute( 'listIndent' ) >= lowestIndent ) {\n\t\t\tif ( currentIndent > item.getAttribute( 'listIndent' ) ) {\n\t\t\t\tcurrentIndent = item.getAttribute( 'listIndent' );\n\t\t\t}\n\n\t\t\t// Found an item that is in the same nested sublist.\n\t\t\tif ( item.getAttribute( 'listIndent' ) == currentIndent ) {\n\t\t\t\t// Just add the item to selected blocks like it was selected by the user.\n\t\t\t\tblocks[ isBackward ? 'unshift' : 'push' ]( item );\n\t\t\t}\n\n\t\t\titem = item[ isBackward ? 'previousSibling' : 'nextSibling' ];\n\t\t}\n\t}\n}\n\n// Checks whether the given block can be replaced by a listItem.\n//\n// @private\n// @param {module:engine/model/element~Element} block A block to be tested.\n// @param {module:engine/model/schema~Schema} schema The schema of the document.\n// @returns {Boolean}\nfunction checkCanBecomeListItem( block, schema ) {\n\treturn schema.checkChild( block.parent, 'listItem' ) && !schema.isObject( block );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 list/indentcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The list indent command. It is used by the {@link module:list/list~List list feature}.\n *\n * @extends module:core/command~Command\n */\nexport default class IndentCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {'forward'|'backward'} indentDirection The direction of indent. If it is equal to `backward`, the command\n\t * will outdent a list item.\n\t */\n\tconstructor( editor, indentDirection ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * Determines by how much the command will change the list item's indent attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {Number}\n\t\t */\n\t\tthis._indentBy = indentDirection == 'forward' ? 1 : -1;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Indents or outdents (depending on the {@link #constructor}'s `indentDirection` parameter) selected list items.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tlet itemsToChange = Array.from( doc.selection.getSelectedBlocks() );\n\n\t\tmodel.change( writer => {\n\t\t\tconst lastItem = itemsToChange[ itemsToChange.length - 1 ];\n\n\t\t\t// Indenting a list item should also indent all the items that are already sub-items of indented item.\n\t\t\tlet next = lastItem.nextSibling;\n\n\t\t\t// Check all items after last indented item, as long as their indent is bigger than indent of that item.\n\t\t\twhile ( next && next.name == 'listItem' && next.getAttribute( 'listIndent' ) > lastItem.getAttribute( 'listIndent' ) ) {\n\t\t\t\titemsToChange.push( next );\n\n\t\t\t\tnext = next.nextSibling;\n\t\t\t}\n\n\t\t\t// We need to be sure to keep model in correct state after each small change, because converters\n\t\t\t// bases on that state and assumes that model is correct.\n\t\t\t// Because of that, if the command outdents items, we will outdent them starting from the last item, as\n\t\t\t// it is safer.\n\t\t\tif ( this._indentBy < 0 ) {\n\t\t\t\titemsToChange = itemsToChange.reverse();\n\t\t\t}\n\n\t\t\tfor ( const item of itemsToChange ) {\n\t\t\t\tconst indent = item.getAttribute( 'listIndent' ) + this._indentBy;\n\n\t\t\t\t// If indent is lower than 0, it means that the item got outdented when it was not indented.\n\t\t\t\t// This means that we need to convert that list item to paragraph.\n\t\t\t\tif ( indent < 0 ) {\n\t\t\t\t\t// To keep the model as correct as possible, first rename listItem, then remove attributes,\n\t\t\t\t\t// as listItem without attributes is very incorrect and will cause problems in converters.\n\t\t\t\t\t// No need to remove attributes, will be removed by post fixer.\n\t\t\t\t\twriter.rename( item, 'paragraph' );\n\t\t\t\t}\n\t\t\t\t// If indent is >= 0, change the attribute value.\n\t\t\t\telse {\n\t\t\t\t\twriter.setAttribute( 'listIndent', indent, item );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\t// Check whether any of position's ancestor is a list item.\n\t\tconst listItem = first( this.editor.model.document.selection.getSelectedBlocks() );\n\n\t\t// If selection is not in a list item, the command is disabled.\n\t\tif ( !listItem || !listItem.is( 'listItem' ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this._indentBy > 0 ) {\n\t\t\t// Cannot indent first item in it's list. Check if before `listItem` is a list item that is in same list.\n\t\t\t// To be in the same list, the item has to have same attributes and cannot be \"split\" by an item with lower indent.\n\t\t\tconst indent = listItem.getAttribute( 'listIndent' );\n\t\t\tconst type = listItem.getAttribute( 'listType' );\n\n\t\t\tlet prev = listItem.previousSibling;\n\n\t\t\twhile ( prev && prev.is( 'listItem' ) && prev.getAttribute( 'listIndent' ) >= indent ) {\n\t\t\t\tif ( prev.getAttribute( 'listIndent' ) == indent ) {\n\t\t\t\t\t// The item is on the same level.\n\t\t\t\t\t// If it has same type, it means that we found a preceding sibling from the same list.\n\t\t\t\t\t// If it does not have same type, it means that `listItem` is on different list (this can happen only\n\t\t\t\t\t// on top level lists, though).\n\t\t\t\t\treturn prev.getAttribute( 'listType' ) == type;\n\t\t\t\t}\n\n\t\t\t\tprev = prev.previousSibling;\n\t\t\t}\n\n\t\t\t// Could not find similar list item, this means that `listItem` is first in its list.\n\t\t\treturn false;\n\t\t}\n\n\t\t// If we are outdenting it is enough to be in list item. Every list item can always be outdented.\n\t\treturn true;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 list/utils\n */\n\nimport { getFillerOffset } from '@ckeditor/ckeditor5-engine/src/view/containerelement';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\n/**\n * Creates a list item {@link module:engine/view/containerelement~ContainerElement}.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer The writer instance.\n * @returns {module:engine/view/containerelement~ContainerElement}\n */\nexport function createViewListItemElement( writer ) {\n\tconst viewItem = writer.createContainerElement( 'li' );\n\n\tviewItem.getFillerOffset = getListItemFillerOffset;\n\n\treturn viewItem;\n}\n\n/**\n * Helper function that creates a `<ul><li></li></ul>` or (`<ol>`) structure out of the given `modelItem` model `listItem` element.\n * Then, it binds the created view list item (<li>) with the model `listItem` element.\n * The function then returns the created view list item (<li>).\n *\n * @param {module:engine/model/item~Item} modelItem Model list item.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface.\n * @returns {module:engine/view/containerelement~ContainerElement} View list element.\n */\nexport function generateLiInUl( modelItem, conversionApi ) {\n\tconst mapper = conversionApi.mapper;\n\tconst viewWriter = conversionApi.writer;\n\tconst listType = modelItem.getAttribute( 'listType' ) == 'numbered' ? 'ol' : 'ul';\n\tconst viewItem = createViewListItemElement( viewWriter );\n\n\tconst viewList = viewWriter.createContainerElement( listType, null );\n\n\tviewWriter.insert( viewWriter.createPositionAt( viewList, 0 ), viewItem );\n\n\tmapper.bindElements( modelItem, viewItem );\n\n\treturn viewItem;\n}\n\n/**\n * Helper function that inserts a view list at a correct place and merges it with its siblings.\n * It takes a model list item element (`modelItem`) and a corresponding view list item element (`injectedItem`). The view list item\n * should be in a view list element (`<ul>` or `<ol>`) and should be its only child.\n * See comments below to better understand the algorithm.\n *\n * @param {module:engine/view/item~Item} modelItem Model list item.\n * @param {module:engine/view/containerelement~ContainerElement} injectedItem\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface.\n * @param {module:engine/model/model~Model} model The model instance.\n */\nexport function injectViewList( modelItem, injectedItem, conversionApi, model ) {\n\tconst injectedList = injectedItem.parent;\n\tconst mapper = conversionApi.mapper;\n\tconst viewWriter = conversionApi.writer;\n\n\t// The position where the view list will be inserted.\n\tlet insertPosition = mapper.toViewPosition( model.createPositionBefore( modelItem ) );\n\n\t// 1. Find the previous list item that has the same or smaller indent. Basically we are looking for the first model item\n\t// that is a \"parent\" or \"sibling\" of the injected model item.\n\t// If there is no such list item, it means that the injected list item is the first item in \"its list\".\n\tconst refItem = getSiblingListItem( modelItem.previousSibling, {\n\t\tsameIndent: true,\n\t\tsmallerIndent: true,\n\t\tlistIndent: modelItem.getAttribute( 'listIndent' )\n\t} );\n\tconst prevItem = modelItem.previousSibling;\n\n\tif ( refItem && refItem.getAttribute( 'listIndent' ) == modelItem.getAttribute( 'listIndent' ) ) {\n\t\t// There is a list item with the same indent - we found the same-level sibling.\n\t\t// Break the list after it. The inserted view item will be added in the broken space.\n\t\tconst viewItem = mapper.toViewElement( refItem );\n\t\tinsertPosition = viewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );\n\t} else {\n\t\t// There is no list item with the same indent. Check the previous model item.\n\t\tif ( prevItem && prevItem.name == 'listItem' ) {\n\t\t\t// If it is a list item, it has to have a lower indent.\n\t\t\t// It means that the inserted item should be added to it as its nested item.\n\t\t\tinsertPosition = mapper.toViewPosition( model.createPositionAt( prevItem, 'end' ) );\n\t\t} else {\n\t\t\t// The previous item is not a list item (or does not exist at all).\n\t\t\t// Just map the position and insert the view item at the mapped position.\n\t\t\tinsertPosition = mapper.toViewPosition( model.createPositionBefore( modelItem ) );\n\t\t}\n\t}\n\n\tinsertPosition = positionAfterUiElements( insertPosition );\n\n\t// Insert the view item.\n\tviewWriter.insert( insertPosition, injectedList );\n\n\t// 2. Handle possible children of the injected model item.\n\tif ( prevItem && prevItem.name == 'listItem' ) {\n\t\tconst prevView = mapper.toViewElement( prevItem );\n\n\t\tconst walkerBoundaries = viewWriter.createRange( viewWriter.createPositionAt( prevView, 0 ), insertPosition );\n\t\tconst walker = walkerBoundaries.getWalker( { ignoreElementEnd: true } );\n\n\t\tfor ( const value of walker ) {\n\t\t\tif ( value.item.is( 'li' ) ) {\n\t\t\t\tconst breakPosition = viewWriter.breakContainer( viewWriter.createPositionBefore( value.item ) );\n\t\t\t\tconst viewList = value.item.parent;\n\n\t\t\t\tconst targetPosition = viewWriter.createPositionAt( injectedItem, 'end' );\n\t\t\t\tmergeViewLists( viewWriter, targetPosition.nodeBefore, targetPosition.nodeAfter );\n\t\t\t\tviewWriter.move( viewWriter.createRangeOn( viewList ), targetPosition );\n\n\t\t\t\twalker.position = breakPosition;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tconst nextViewList = injectedList.nextSibling;\n\n\t\tif ( nextViewList && ( nextViewList.is( 'ul' ) || nextViewList.is( 'ol' ) ) ) {\n\t\t\tlet lastSubChild = null;\n\n\t\t\tfor ( const child of nextViewList.getChildren() ) {\n\t\t\t\tconst modelChild = mapper.toModelElement( child );\n\n\t\t\t\tif ( modelChild && modelChild.getAttribute( 'listIndent' ) > modelItem.getAttribute( 'listIndent' ) ) {\n\t\t\t\t\tlastSubChild = child;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( lastSubChild ) {\n\t\t\t\tviewWriter.breakContainer( viewWriter.createPositionAfter( lastSubChild ) );\n\t\t\t\tviewWriter.move( viewWriter.createRangeOn( lastSubChild.parent ), viewWriter.createPositionAt( injectedItem, 'end' ) );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Merge the inserted view list with its possible neighbor lists.\n\tmergeViewLists( viewWriter, injectedList, injectedList.nextSibling );\n\tmergeViewLists( viewWriter, injectedList.previousSibling, injectedList );\n}\n\n/**\n * Helper function that takes two parameters that are expected to be view list elements, and merges them.\n * The merge happens only if both parameters are list elements of the same type (the same element name and the same class attributes).\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter The writer instance.\n * @param {module:engine/view/item~Item} firstList The first element to compare.\n * @param {module:engine/view/item~Item} secondList The second element to compare.\n * @returns {module:engine/view/position~Position|null} The position after merge or `null` when there was no merge.\n */\nexport function mergeViewLists( viewWriter, firstList, secondList ) {\n\t// Check if two lists are going to be merged.\n\tif ( !firstList || !secondList || ( firstList.name != 'ul' && firstList.name != 'ol' ) ) {\n\t\treturn null;\n\t}\n\n\t// Both parameters are list elements, so compare types now.\n\tif ( firstList.name != secondList.name || firstList.getAttribute( 'class' ) !== secondList.getAttribute( 'class' ) ) {\n\t\treturn null;\n\t}\n\n\treturn viewWriter.mergeContainers( viewWriter.createPositionAfter( firstList ) );\n}\n\n/**\n * Helper function that for a given `view.Position`, returns a `view.Position` that is after all `view.UIElement`s that\n * are after the given position.\n *\n * For example:\n * `<container:p>foo^<ui:span></ui:span><ui:span></ui:span>bar</container:p>`\n * For position ^, the position before \"bar\" will be returned.\n *\n * @param {module:engine/view/position~Position} viewPosition\n * @returns {module:engine/view/position~Position}\n */\nexport function positionAfterUiElements( viewPosition ) {\n\treturn viewPosition.getLastMatchingPosition( value => value.item.is( 'uiElement' ) );\n}\n\n/**\n * Helper function that searches for a previous list item sibling of a given model item that meets the given criteria\n * passed by the options object.\n *\n * @param {module:engine/model/item~Item} modelItem\n * @param {Object} options Search criteria.\n * @param {Boolean} [options.sameIndent=false] Whether the sought sibling should have the same indentation.\n * @param {Boolean} [options.smallerIndent=false] Whether the sought sibling should have a smaller indentation.\n * @param {Number} [options.listIndent] The reference indentation.\n * @returns {module:engine/model/item~Item|null}\n */\nexport function getSiblingListItem( modelItem, options ) {\n\tconst sameIndent = !!options.sameIndent;\n\tconst smallerIndent = !!options.smallerIndent;\n\tconst indent = options.listIndent;\n\n\tlet item = modelItem;\n\n\twhile ( item && item.name == 'listItem' ) {\n\t\tconst itemIndent = item.getAttribute( 'listIndent' );\n\n\t\tif ( ( sameIndent && indent == itemIndent ) || ( smallerIndent && indent > itemIndent ) ) {\n\t\t\treturn item;\n\t\t}\n\n\t\titem = item.previousSibling;\n\t}\n\n\treturn null;\n}\n\n/**\n * Helper method for creating a UI button and linking it with an appropriate command.\n *\n * @private\n * @param {module:core/editor/editor~Editor} editor The editor instance to which the UI component will be added.\n * @param {String} commandName The name of the command.\n * @param {Object} label The button label.\n * @param {String} icon The source of the icon.\n */\nexport function createUIComponent( editor, commandName, label, icon ) {\n\teditor.ui.componentFactory.add( commandName, locale => {\n\t\tconst command = editor.commands.get( commandName );\n\t\tconst buttonView = new ButtonView( locale );\n\n\t\tbuttonView.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true,\n\t\t\tisToggleable: true\n\t\t} );\n\n\t\t// Bind button model to command.\n\t\tbuttonView.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t// Execute command.\n\t\tbuttonView.on( 'execute', () => {\n\t\t\teditor.execute( commandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\treturn buttonView;\n\t} );\n}\n\n// Implementation of getFillerOffset for view list item element.\n//\n// @returns {Number|null} Block filler offset or `null` if block filler is not needed.\nfunction getListItemFillerOffset() {\n\tconst hasOnlyLists = !this.isEmpty && ( this.getChild( 0 ).name == 'ul' || this.getChild( 0 ).name == 'ol' );\n\n\tif ( this.isEmpty || hasOnlyLists ) {\n\t\treturn 0;\n\t}\n\n\treturn getFillerOffset.call( this );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 list/converters\n */\n\nimport {\n\tgenerateLiInUl,\n\tinjectViewList,\n\tmergeViewLists,\n\tgetSiblingListItem,\n\tpositionAfterUiElements\n} from './utils';\nimport TreeWalker from '@ckeditor/ckeditor5-engine/src/model/treewalker';\n\n/**\n * A model-to-view converter for the `listItem` model element insertion.\n *\n * It creates a `<ul><li></li><ul>` (or `<ol>`) view structure out of a `listItem` model element, inserts it at the correct\n * position, and merges the list with surrounding lists (if available).\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelViewInsertion( model ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst consumable = conversionApi.consumable;\n\n\t\tif ( !consumable.test( data.item, 'insert' ) ||\n\t\t\t!consumable.test( data.item, 'attribute:listType' ) ||\n\t\t\t!consumable.test( data.item, 'attribute:listIndent' )\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconsumable.consume( data.item, 'insert' );\n\t\tconsumable.consume( data.item, 'attribute:listType' );\n\t\tconsumable.consume( data.item, 'attribute:listIndent' );\n\n\t\tconst modelItem = data.item;\n\t\tconst viewItem = generateLiInUl( modelItem, conversionApi );\n\n\t\tinjectViewList( modelItem, viewItem, conversionApi, model );\n\t};\n}\n\n/**\n * A model-to-view converter for the `listItem` model element removal.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:remove\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelViewRemove( model ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewStart = conversionApi.mapper.toViewPosition( data.position ).getLastMatchingPosition( value => !value.item.is( 'li' ) );\n\t\tconst viewItem = viewStart.nodeAfter;\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// 1. Break the container after and before the list item.\n\t\t// This will create a view list with one view list item - the one to remove.\n\t\tviewWriter.breakContainer( viewWriter.createPositionBefore( viewItem ) );\n\t\tviewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );\n\n\t\t// 2. Remove the list with the item to remove.\n\t\tconst viewList = viewItem.parent;\n\t\tconst viewListPrev = viewList.previousSibling;\n\t\tconst removeRange = viewWriter.createRangeOn( viewList );\n\t\tconst removed = viewWriter.remove( removeRange );\n\n\t\t// 3. Merge the whole created by breaking and removing the list.\n\t\tif ( viewListPrev && viewListPrev.nextSibling ) {\n\t\t\tmergeViewLists( viewWriter, viewListPrev, viewListPrev.nextSibling );\n\t\t}\n\n\t\t// 4. Bring back nested list that was in the removed <li>.\n\t\tconst modelItem = conversionApi.mapper.toModelElement( viewItem );\n\n\t\thoistNestedLists( modelItem.getAttribute( 'listIndent' ) + 1, data.position, removeRange.start, viewItem, conversionApi, model );\n\n\t\t// 5. Unbind removed view item and all children.\n\t\tfor ( const child of viewWriter.createRangeIn( removed ).getItems() ) {\n\t\t\tconversionApi.mapper.unbindViewElement( child );\n\t\t}\n\n\t\tevt.stop();\n\t};\n}\n\n/**\n * A model-to-view converter for the `type` attribute change on the `listItem` model element.\n *\n * This change means that the `<li>` element parent changes from `<ul>` to `<ol>` (or vice versa). This is accomplished\n * by breaking view elements and changing their name. The next {@link module:list/converters~modelViewMergeAfterChangeType}\n * converter will attempt to merge split nodes.\n *\n * Splitting this conversion into 2 steps makes it possible to add an additional conversion in the middle.\n * Check {@link module:list/todolistconverters~modelViewChangeType} to see an example of it.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface.\n */\nexport function modelViewChangeType( evt, data, conversionApi ) {\n\tif ( !conversionApi.consumable.consume( data.item, 'attribute:listType' ) ) {\n\t\treturn;\n\t}\n\n\tconst viewItem = conversionApi.mapper.toViewElement( data.item );\n\tconst viewWriter = conversionApi.writer;\n\n\t// Break the container after and before the list item.\n\t// This will create a view list with one view list item -- the one that changed type.\n\tviewWriter.breakContainer( viewWriter.createPositionBefore( viewItem ) );\n\tviewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );\n\n\t// Change name of the view list that holds the changed view item.\n\t// We cannot just change name property, because that would not render properly.\n\tconst viewList = viewItem.parent;\n\tconst listName = data.attributeNewValue == 'numbered' ? 'ol' : 'ul';\n\n\tviewWriter.rename( listName, viewList );\n}\n\n/**\n * A model-to-view converter that attempts to merge nodes split by {@link module:list/converters~modelViewChangeType}.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface.\n */\nexport function modelViewMergeAfterChangeType( evt, data, conversionApi ) {\n\tconst viewItem = conversionApi.mapper.toViewElement( data.item );\n\tconst viewList = viewItem.parent;\n\tconst viewWriter = conversionApi.writer;\n\n\t// Merge the changed view list with other lists, if possible.\n\tmergeViewLists( viewWriter, viewList, viewList.nextSibling );\n\tmergeViewLists( viewWriter, viewList.previousSibling, viewList );\n\n\t// Consumable insertion of children inside the item. They are already handled by re-building the item in view.\n\tfor ( const child of data.item.getChildren() ) {\n\t\tconversionApi.consumable.consume( child, 'insert' );\n\t}\n}\n\n/**\n * A model-to-view converter for the `listIndent` attribute change on the `listItem` model element.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelViewChangeIndent( model ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !conversionApi.consumable.consume( data.item, 'attribute:listIndent' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewItem = conversionApi.mapper.toViewElement( data.item );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// 1. Break the container after and before the list item.\n\t\t// This will create a view list with one view list item -- the one that changed type.\n\t\tviewWriter.breakContainer( viewWriter.createPositionBefore( viewItem ) );\n\t\tviewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );\n\n\t\t// 2. Extract view list with changed view list item and merge \"hole\" possibly created by breaking and removing elements.\n\t\tconst viewList = viewItem.parent;\n\t\tconst viewListPrev = viewList.previousSibling;\n\t\tconst removeRange = viewWriter.createRangeOn( viewList );\n\t\tviewWriter.remove( removeRange );\n\n\t\tif ( viewListPrev && viewListPrev.nextSibling ) {\n\t\t\tmergeViewLists( viewWriter, viewListPrev, viewListPrev.nextSibling );\n\t\t}\n\n\t\t// 3. Bring back nested list that was in the removed <li>.\n\t\thoistNestedLists( data.attributeOldValue + 1, data.range.start, removeRange.start, viewItem, conversionApi, model );\n\n\t\t// 4. Inject view list like it is newly inserted.\n\t\tinjectViewList( data.item, viewItem, conversionApi, model );\n\n\t\t// 5. Consume insertion of children inside the item. They are already handled by re-building the item in view.\n\t\tfor ( const child of data.item.getChildren() ) {\n\t\t\tconversionApi.consumable.consume( child, 'insert' );\n\t\t}\n\t};\n}\n\n/**\n * A special model-to-view converter introduced by the {@link module:list/list~List list feature}. This converter is fired for\n * insert change of every model item, and should be fired before the actual converter. The converter checks whether the inserted\n * model item is a non-`listItem` element. If it is, and it is inserted inside a view list, the converter breaks the\n * list so the model element is inserted to the view parent element corresponding to its model parent element.\n *\n * The converter prevents such situations:\n *\n *\t\t// Model: // View:\n *\t\t<listItem>foo</listItem> <ul>\n *\t\t<listItem>bar</listItem> <li>foo</li>\n *\t\t <li>bar</li>\n *\t\t </ul>\n *\n *\t\t// After change: // Correct view guaranteed by this converter:\n *\t\t<listItem>foo</listItem> <ul><li>foo</li></ul><p>xxx</p><ul><li>bar</li></ul>\n *\t\t<paragraph>xxx</paragraph> // Instead of this wrong view state:\n *\t\t<listItem>bar</listItem> <ul><li>foo</li><p>xxx</p><li>bar</li></ul>\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface.\n */\nexport function modelViewSplitOnInsert( evt, data, conversionApi ) {\n\tif ( data.item.name != 'listItem' ) {\n\t\tlet viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst lists = [];\n\n\t\t// Break multiple ULs/OLs if there are.\n\t\t//\n\t\t// Imagine following list:\n\t\t//\n\t\t// 1 --------\n\t\t// 1.1 --------\n\t\t// 1.1.1 --------\n\t\t// 1.1.2 --------\n\t\t// 1.1.3 --------\n\t\t// 1.1.3.1 --------\n\t\t// 1.2 --------\n\t\t// 1.2.1 --------\n\t\t// 2 --------\n\t\t//\n\t\t// Insert paragraph after item 1.1.1:\n\t\t//\n\t\t// 1 --------\n\t\t// 1.1 --------\n\t\t// 1.1.1 --------\n\t\t//\n\t\t// Lorem ipsum.\n\t\t//\n\t\t// 1.1.2 --------\n\t\t// 1.1.3 --------\n\t\t// 1.1.3.1 --------\n\t\t// 1.2 --------\n\t\t// 1.2.1 --------\n\t\t// 2 --------\n\t\t//\n\t\t// In this case 1.1.2 has to become beginning of a new list.\n\t\t// We need to break list before 1.1.2 (obvious), then we need to break list also before 1.2.\n\t\t// Then we need to move those broken pieces one after another and merge:\n\t\t//\n\t\t// 1 --------\n\t\t// 1.1 --------\n\t\t// 1.1.1 --------\n\t\t//\n\t\t// Lorem ipsum.\n\t\t//\n\t\t// 1.1.2 --------\n\t\t// 1.1.3 --------\n\t\t// 1.1.3.1 --------\n\t\t// 1.2 --------\n\t\t// 1.2.1 --------\n\t\t// 2 --------\n\t\t//\n\t\twhile ( viewPosition.parent.name == 'ul' || viewPosition.parent.name == 'ol' ) {\n\t\t\tviewPosition = viewWriter.breakContainer( viewPosition );\n\n\t\t\tif ( viewPosition.parent.name != 'li' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Remove lists that are after inserted element.\n\t\t\t// They will be brought back later, below the inserted element.\n\t\t\tconst removeStart = viewPosition;\n\t\t\tconst removeEnd = viewWriter.createPositionAt( viewPosition.parent, 'end' );\n\n\t\t\t// Don't remove if there is nothing to remove.\n\t\t\tif ( !removeStart.isEqual( removeEnd ) ) {\n\t\t\t\tconst removed = viewWriter.remove( viewWriter.createRange( removeStart, removeEnd ) );\n\t\t\t\tlists.push( removed );\n\t\t\t}\n\n\t\t\tviewPosition = viewWriter.createPositionAfter( viewPosition.parent );\n\t\t}\n\n\t\t// Bring back removed lists.\n\t\tif ( lists.length > 0 ) {\n\t\t\tfor ( let i = 0; i < lists.length; i++ ) {\n\t\t\t\tconst previousList = viewPosition.nodeBefore;\n\t\t\t\tconst insertedRange = viewWriter.insert( viewPosition, lists[ i ] );\n\t\t\t\tviewPosition = insertedRange.end;\n\n\t\t\t\t// Don't merge first list! We want a split in that place (this is why this converter is introduced).\n\t\t\t\tif ( i > 0 ) {\n\t\t\t\t\tconst mergePos = mergeViewLists( viewWriter, previousList, previousList.nextSibling );\n\n\t\t\t\t\t// If `mergePos` is in `previousList` it means that the lists got merged.\n\t\t\t\t\t// In this case, we need to fix insert position.\n\t\t\t\t\tif ( mergePos && mergePos.parent == previousList ) {\n\t\t\t\t\t\tviewPosition.offset--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Merge last inserted list with element after it.\n\t\t\tmergeViewLists( viewWriter, viewPosition.nodeBefore, viewPosition.nodeAfter );\n\t\t}\n\t}\n}\n\n/**\n * A special model-to-view converter introduced by the {@link module:list/list~List list feature}. This converter takes care of\n * merging view lists after something is removed or moved from near them.\n *\n * Example:\n *\n *\t\t// Model: // View:\n *\t\t<listItem>foo</listItem> <ul><li>foo</li></ul>\n *\t\t<paragraph>xxx</paragraph> <p>xxx</p>\n *\t\t<listItem>bar</listItem> <ul><li>bar</li></ul>\n *\n *\t\t// After change: // Correct view guaranteed by this converter:\n *\t\t<listItem>foo</listItem> <ul>\n *\t\t<listItem>bar</listItem> <li>foo</li>\n *\t\t <li>bar</li>\n *\t\t </ul>\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:remove\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface.\n */\nexport function modelViewMergeAfter( evt, data, conversionApi ) {\n\tconst viewPosition = conversionApi.mapper.toViewPosition( data.position );\n\tconst viewItemPrev = viewPosition.nodeBefore;\n\tconst viewItemNext = viewPosition.nodeAfter;\n\n\t// Merge lists if something (remove, move) was done from inside of list.\n\t// Merging will be done only if both items are view lists of the same type.\n\t// The check is done inside the helper function.\n\tmergeViewLists( conversionApi.writer, viewItemPrev, viewItemNext );\n}\n\n/**\n * A view-to-model converter that converts the `<li>` view elements into the `listItem` model elements.\n *\n * To set correct values of the `listType` and `listIndent` attributes the converter:\n * * checks `<li>`'s parent,\n * * stores and increases the `conversionApi.store.indent` value when `<li>`'s sub-items are converted.\n *\n * @see module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data An object containing conversion input and a placeholder for conversion output and possibly other values.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n */\nexport function viewModelConverter( evt, data, conversionApi ) {\n\tif ( conversionApi.consumable.consume( data.viewItem, { name: true } ) ) {\n\t\tconst writer = conversionApi.writer;\n\n\t\t// 1. Create `listItem` model element.\n\t\tconst listItem = writer.createElement( 'listItem' );\n\n\t\t// 2. Handle `listItem` model element attributes.\n\t\tconst indent = getIndent( data.viewItem );\n\n\t\twriter.setAttribute( 'listIndent', indent, listItem );\n\n\t\t// Set 'bulleted' as default. If this item is pasted into a context,\n\t\tconst type = data.viewItem.parent && data.viewItem.parent.name == 'ol' ? 'numbered' : 'bulleted';\n\t\twriter.setAttribute( 'listType', type, listItem );\n\n\t\t// Try to find allowed parent for list item.\n\t\tconst splitResult = conversionApi.splitToAllowedParent( listItem, data.modelCursor );\n\n\t\t// When there is no allowed parent it means that list item cannot be converted at current model position\n\t\t// and in any of position ancestors.\n\t\tif ( !splitResult ) {\n\t\t\treturn;\n\t\t}\n\n\t\twriter.insert( listItem, splitResult.position );\n\n\t\tconst nextPosition = viewToModelListItemChildrenConverter( listItem, data.viewItem.getChildren(), conversionApi );\n\n\t\t// Result range starts before the first item and ends after the last.\n\t\tdata.modelRange = writer.createRange( data.modelCursor, nextPosition );\n\n\t\t// When `data.modelCursor` parent had to be split to insert list item...\n\t\tif ( splitResult.cursorParent ) {\n\t\t\t// Continue conversion in the split element.\n\t\t\tdata.modelCursor = writer.createPositionAt( splitResult.cursorParent, 0 );\n\t\t} else {\n\t\t\t// Otherwise continue conversion after the last list item.\n\t\t\tdata.modelCursor = data.modelRange.end;\n\t\t}\n\t}\n}\n\n/**\n * A view-to-model converter for the `<ul>` and `<ol>` view elements that cleans the input view of garbage.\n * This is mostly to clean whitespaces from between the `<li>` view elements inside the view list element, however, also\n * incorrect data can be cleared if the view was incorrect.\n *\n * @see module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data An object containing conversion input and a placeholder for conversion output and possibly other values.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n */\nexport function cleanList( evt, data, conversionApi ) {\n\tif ( conversionApi.consumable.test( data.viewItem, { name: true } ) ) {\n\t\t// Caching children because when we start removing them iterating fails.\n\t\tconst children = Array.from( data.viewItem.getChildren() );\n\n\t\tfor ( const child of children ) {\n\t\t\tconst isWrongElement = !( child.is( 'li' ) || isList( child ) );\n\n\t\t\tif ( isWrongElement ) {\n\t\t\t\tchild._remove();\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * A view-to-model converter for the `<li>` elements that cleans whitespace formatting from the input view.\n *\n * @see module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data An object containing conversion input and a placeholder for conversion output and possibly other values.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n */\nexport function cleanListItem( evt, data, conversionApi ) {\n\tif ( conversionApi.consumable.test( data.viewItem, { name: true } ) ) {\n\t\tif ( data.viewItem.childCount === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst children = [ ...data.viewItem.getChildren() ];\n\n\t\tlet foundList = false;\n\t\tlet firstNode = true;\n\n\t\tfor ( const child of children ) {\n\t\t\tif ( foundList && !isList( child ) ) {\n\t\t\t\tchild._remove();\n\t\t\t}\n\n\t\t\tif ( child.is( 'text' ) ) {\n\t\t\t\t// If this is the first node and it's a text node, left-trim it.\n\t\t\t\tif ( firstNode ) {\n\t\t\t\t\tchild._data = child.data.replace( /^\\s+/, '' );\n\t\t\t\t}\n\n\t\t\t\t// If this is the last text node before <ul> or <ol>, right-trim it.\n\t\t\t\tif ( !child.nextSibling || isList( child.nextSibling ) ) {\n\t\t\t\t\tchild._data = child.data.replace( /\\s+$/, '' );\n\t\t\t\t}\n\t\t\t} else if ( isList( child ) ) {\n\t\t\t\t// If this is a <ul> or <ol>, do not process it, just mark that we already visited list element.\n\t\t\t\tfoundList = true;\n\t\t\t}\n\n\t\t\tfirstNode = false;\n\t\t}\n\t}\n}\n\n/**\n * Returns a callback for model position to view position mapping for {@link module:engine/conversion/mapper~Mapper}. The callback fixes\n * positions between the `listItem` elements that would be incorrectly mapped because of how list items are represented in the model\n * and in the view.\n *\n * @see module:engine/conversion/mapper~Mapper#event:modelToViewPosition\n * @param {module:engine/view/view~View} view A view instance.\n * @returns {Function}\n */\nexport function modelToViewPosition( view ) {\n\treturn ( evt, data ) => {\n\t\tif ( data.isPhantom ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelItem = data.modelPosition.nodeBefore;\n\n\t\tif ( modelItem && modelItem.is( 'listItem' ) ) {\n\t\t\tconst viewItem = data.mapper.toViewElement( modelItem );\n\t\t\tconst topmostViewList = viewItem.getAncestors().find( isList );\n\t\t\tconst walker = view.createPositionAt( viewItem, 0 ).getWalker();\n\n\t\t\tfor ( const value of walker ) {\n\t\t\t\tif ( value.type == 'elementStart' && value.item.is( 'li' ) ) {\n\t\t\t\t\tdata.viewPosition = value.previousPosition;\n\n\t\t\t\t\tbreak;\n\t\t\t\t} else if ( value.type == 'elementEnd' && value.item == topmostViewList ) {\n\t\t\t\t\tdata.viewPosition = value.nextPosition;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * The callback for view position to model position mapping for {@link module:engine/conversion/mapper~Mapper}. The callback fixes\n * positions between the `<li>` elements that would be incorrectly mapped because of how list items are represented in the model\n * and in the view.\n *\n * @see module:engine/conversion/mapper~Mapper#event:viewToModelPosition\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function viewToModelPosition( model ) {\n\treturn ( evt, data ) => {\n\t\tconst viewPos = data.viewPosition;\n\t\tconst viewParent = viewPos.parent;\n\t\tconst mapper = data.mapper;\n\n\t\tif ( viewParent.name == 'ul' || viewParent.name == 'ol' ) {\n\t\t\t// Position is directly in <ul> or <ol>.\n\t\t\tif ( !viewPos.isAtEnd ) {\n\t\t\t\t// If position is not at the end, it must be before <li>.\n\t\t\t\t// Get that <li>, map it to `listItem` and set model position before that `listItem`.\n\t\t\t\tconst modelNode = mapper.toModelElement( viewPos.nodeAfter );\n\n\t\t\t\tdata.modelPosition = model.createPositionBefore( modelNode );\n\t\t\t} else {\n\t\t\t\t// Position is at the end of <ul> or <ol>, so there is no <li> after it to be mapped.\n\t\t\t\t// There is <li> before the position, but we cannot just map it to `listItem` and set model position after it,\n\t\t\t\t// because that <li> may contain nested items.\n\t\t\t\t// We will check \"model length\" of that <li>, in other words - how many `listItem`s are in that <li>.\n\t\t\t\tconst modelNode = mapper.toModelElement( viewPos.nodeBefore );\n\t\t\t\tconst modelLength = mapper.getModelLength( viewPos.nodeBefore );\n\n\t\t\t\t// Then we get model position before mapped `listItem` and shift it accordingly.\n\t\t\t\tdata.modelPosition = model.createPositionBefore( modelNode ).getShiftedBy( modelLength );\n\t\t\t}\n\n\t\t\tevt.stop();\n\t\t} else if (\n\t\t\tviewParent.name == 'li' &&\n\t\t\tviewPos.nodeBefore &&\n\t\t\t( viewPos.nodeBefore.name == 'ul' || viewPos.nodeBefore.name == 'ol' )\n\t\t) {\n\t\t\t// In most cases when view position is in <li> it is in text and this is a correct position.\n\t\t\t// However, if position is after <ul> or <ol> we have to fix it -- because in model <ul>/<ol> are not in the `listItem`.\n\t\t\tconst modelNode = mapper.toModelElement( viewParent );\n\n\t\t\t// Check all <ul>s and <ol>s that are in the <li> but before mapped position.\n\t\t\t// Get model length of those elements and then add it to the offset of `listItem` mapped to the original <li>.\n\t\t\tlet modelLength = 1; // Starts from 1 because the original <li> has to be counted in too.\n\t\t\tlet viewList = viewPos.nodeBefore;\n\n\t\t\twhile ( viewList && isList( viewList ) ) {\n\t\t\t\tmodelLength += mapper.getModelLength( viewList );\n\n\t\t\t\tviewList = viewList.previousSibling;\n\t\t\t}\n\n\t\t\tdata.modelPosition = model.createPositionBefore( modelNode ).getShiftedBy( modelLength );\n\n\t\t\tevt.stop();\n\t\t}\n\t};\n}\n\n/**\n * Post-fixer that reacts to changes on document and fixes incorrect model states.\n *\n * In the example below, there is a correct list structure.\n * Then the middle element is removed so the list structure will become incorrect:\n *\n *\t\t<listItem listType=\"bulleted\" listIndent=0>Item 1</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=1>Item 2</listItem> <--- this is removed.\n *\t\t<listItem listType=\"bulleted\" listIndent=2>Item 3</listItem>\n *\n * The list structure after the middle element is removed:\n *\n * \t\t<listItem listType=\"bulleted\" listIndent=0>Item 1</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=2>Item 3</listItem>\n *\n * Should become:\n *\n *\t\t<listItem listType=\"bulleted\" listIndent=0>Item 1</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=1>Item 3</listItem> <--- note that indent got post-fixed.\n *\n * @param {module:engine/model/model~Model} model The data model.\n * @param {module:engine/model/writer~Writer} writer The writer to do changes with.\n * @returns {Boolean} `true` if any change has been applied, `false` otherwise.\n */\nexport function modelChangePostFixer( model, writer ) {\n\tconst changes = model.document.differ.getChanges();\n\tconst itemToListHead = new Map();\n\n\tlet applied = false;\n\n\tfor ( const entry of changes ) {\n\t\tif ( entry.type == 'insert' && entry.name == 'listItem' ) {\n\t\t\t_addListToFix( entry.position );\n\t\t} else if ( entry.type == 'insert' && entry.name != 'listItem' ) {\n\t\t\tif ( entry.name != '$text' ) {\n\t\t\t\t// In case of renamed element.\n\t\t\t\tconst item = entry.position.nodeAfter;\n\n\t\t\t\tif ( item.hasAttribute( 'listIndent' ) ) {\n\t\t\t\t\twriter.removeAttribute( 'listIndent', item );\n\n\t\t\t\t\tapplied = true;\n\t\t\t\t}\n\n\t\t\t\tif ( item.hasAttribute( 'listType' ) ) {\n\t\t\t\t\twriter.removeAttribute( 'listType', item );\n\n\t\t\t\t\tapplied = true;\n\t\t\t\t}\n\n\t\t\t\tfor ( const innerItem of Array.from( model.createRangeIn( item ) ).filter( e => e.item.is( 'listItem' ) ) ) {\n\t\t\t\t\t_addListToFix( innerItem.previousPosition );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst posAfter = entry.position.getShiftedBy( entry.length );\n\n\t\t\t_addListToFix( posAfter );\n\t\t} else if ( entry.type == 'remove' && entry.name == 'listItem' ) {\n\t\t\t_addListToFix( entry.position );\n\t\t} else if ( entry.type == 'attribute' && entry.attributeKey == 'listIndent' ) {\n\t\t\t_addListToFix( entry.range.start );\n\t\t} else if ( entry.type == 'attribute' && entry.attributeKey == 'listType' ) {\n\t\t\t_addListToFix( entry.range.start );\n\t\t}\n\t}\n\n\tfor ( const listHead of itemToListHead.values() ) {\n\t\t_fixListIndents( listHead );\n\t\t_fixListTypes( listHead );\n\t}\n\n\treturn applied;\n\n\tfunction _addListToFix( position ) {\n\t\tconst prev = position.nodeBefore;\n\n\t\tif ( !prev || !prev.is( 'listItem' ) ) {\n\t\t\tconst item = position.nodeAfter;\n\n\t\t\tif ( item && item.is( 'listItem' ) ) {\n\t\t\t\titemToListHead.set( item, item );\n\t\t\t}\n\t\t} else {\n\t\t\tlet listHead = prev;\n\n\t\t\tif ( itemToListHead.has( listHead ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twhile ( listHead.previousSibling && listHead.previousSibling.is( 'listItem' ) ) {\n\t\t\t\tlistHead = listHead.previousSibling;\n\n\t\t\t\tif ( itemToListHead.has( listHead ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\titemToListHead.set( position.nodeBefore, listHead );\n\t\t}\n\t}\n\n\tfunction _fixListIndents( item ) {\n\t\tlet maxIndent = 0;\n\t\tlet fixBy = null;\n\n\t\twhile ( item && item.is( 'listItem' ) ) {\n\t\t\tconst itemIndent = item.getAttribute( 'listIndent' );\n\n\t\t\tif ( itemIndent > maxIndent ) {\n\t\t\t\tlet newIndent;\n\n\t\t\t\tif ( fixBy === null ) {\n\t\t\t\t\tfixBy = itemIndent - maxIndent;\n\t\t\t\t\tnewIndent = maxIndent;\n\t\t\t\t} else {\n\t\t\t\t\tif ( fixBy > itemIndent ) {\n\t\t\t\t\t\tfixBy = itemIndent;\n\t\t\t\t\t}\n\n\t\t\t\t\tnewIndent = itemIndent - fixBy;\n\t\t\t\t}\n\n\t\t\t\twriter.setAttribute( 'listIndent', newIndent, item );\n\n\t\t\t\tapplied = true;\n\t\t\t} else {\n\t\t\t\tfixBy = null;\n\t\t\t\tmaxIndent = item.getAttribute( 'listIndent' ) + 1;\n\t\t\t}\n\n\t\t\titem = item.nextSibling;\n\t\t}\n\t}\n\n\tfunction _fixListTypes( item ) {\n\t\tlet typesStack = [];\n\t\tlet prev = null;\n\n\t\twhile ( item && item.is( 'listItem' ) ) {\n\t\t\tconst itemIndent = item.getAttribute( 'listIndent' );\n\n\t\t\tif ( prev && prev.getAttribute( 'listIndent' ) > itemIndent ) {\n\t\t\t\ttypesStack = typesStack.slice( 0, itemIndent + 1 );\n\t\t\t}\n\n\t\t\tif ( itemIndent != 0 ) {\n\t\t\t\tif ( typesStack[ itemIndent ] ) {\n\t\t\t\t\tconst type = typesStack[ itemIndent ];\n\n\t\t\t\t\tif ( item.getAttribute( 'listType' ) != type ) {\n\t\t\t\t\t\twriter.setAttribute( 'listType', type, item );\n\n\t\t\t\t\t\tapplied = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttypesStack[ itemIndent ] = item.getAttribute( 'listType' );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprev = item;\n\t\t\titem = item.nextSibling;\n\t\t}\n\t}\n}\n\n/**\n * A fixer for pasted content that includes list items.\n *\n * It fixes indentation of pasted list items so the pasted items match correctly to the context they are pasted into.\n *\n * Example:\n *\n *\t\t<listItem listType=\"bulleted\" listIndent=0>A</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=1>B^</listItem>\n *\t\t// At ^ paste: <listItem listType=\"bulleted\" listIndent=4>X</listItem>\n *\t\t// <listItem listType=\"bulleted\" listIndent=5>Y</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=2>C</listItem>\n *\n * Should become:\n *\n *\t\t<listItem listType=\"bulleted\" listIndent=0>A</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=1>BX</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=2>Y/listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=2>C</listItem>\n *\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Array} args Arguments of {@link module:engine/model/model~Model#insertContent}.\n */\nexport function modelIndentPasteFixer( evt, [ content, selectable ] ) {\n\t// Check whether inserted content starts from a `listItem`. If it does not, it means that there are some other\n\t// elements before it and there is no need to fix indents, because even if we insert that content into a list,\n\t// that list will be broken.\n\t// Note: we also need to handle singular elements because inserting item with indent 0 into 0,1,[],2\n\t// would create incorrect model.\n\tlet item = content.is( 'documentFragment' ) ? content.getChild( 0 ) : content;\n\n\tlet selection;\n\n\tif ( !selectable ) {\n\t\tselection = this.document.selection;\n\t} else {\n\t\tselection = this.createSelection( selectable );\n\t}\n\n\tif ( item && item.is( 'listItem' ) ) {\n\t\t// Get a reference list item. Inserted list items will be fixed according to that item.\n\t\tconst pos = selection.getFirstPosition();\n\t\tlet refItem = null;\n\n\t\tif ( pos.parent.is( 'listItem' ) ) {\n\t\t\trefItem = pos.parent;\n\t\t} else if ( pos.nodeBefore && pos.nodeBefore.is( 'listItem' ) ) {\n\t\t\trefItem = pos.nodeBefore;\n\t\t}\n\n\t\t// If there is `refItem` it means that we do insert list items into an existing list.\n\t\tif ( refItem ) {\n\t\t\t// First list item in `data` has indent equal to 0 (it is a first list item). It should have indent equal\n\t\t\t// to the indent of reference item. We have to fix the first item and all of it's children and following siblings.\n\t\t\t// Indent of all those items has to be adjusted to reference item.\n\t\t\tconst indentChange = refItem.getAttribute( 'listIndent' );\n\n\t\t\t// Fix only if there is anything to fix.\n\t\t\tif ( indentChange > 0 ) {\n\t\t\t\t// Adjust indent of all \"first\" list items in inserted data.\n\t\t\t\twhile ( item && item.is( 'listItem' ) ) {\n\t\t\t\t\titem._setAttribute( 'listIndent', item.getAttribute( 'listIndent' ) + indentChange );\n\n\t\t\t\t\titem = item.nextSibling;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Helper function that converts children of a given `<li>` view element into corresponding model elements.\n// The function maintains proper order of elements if model `listItem` is split during the conversion\n// due to block children conversion.\n//\n// @param {module:engine/model/element~Element} listItemModel List item model element to which converted children will be inserted.\n// @param {Iterable.<module:engine/view/node~Node>} viewChildren View elements which will be converted.\n// @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n// @returns {module:engine/model/position~Position} Position on which next elements should be inserted after children conversion.\nfunction viewToModelListItemChildrenConverter( listItemModel, viewChildren, conversionApi ) {\n\tconst { writer, schema } = conversionApi;\n\n\t// A position after the last inserted `listItem`.\n\tlet nextPosition = writer.createPositionAfter( listItemModel );\n\n\t// Check all children of the converted `<li>`. At this point we assume there are no \"whitespace\" view text nodes\n\t// in view list, between view list items. This should be handled by `<ul>` and `<ol>` converters.\n\tfor ( const child of viewChildren ) {\n\t\tif ( child.name == 'ul' || child.name == 'ol' ) {\n\t\t\t// If the children is a list, we will insert its conversion result after currently handled `listItem`.\n\t\t\t// Then, next insertion position will be set after all the new list items (and maybe other elements if\n\t\t\t// something split list item).\n\t\t\t//\n\t\t\t// If this is a list, we expect that some `listItem`s and possibly other blocks will be inserted, however `.modelCursor`\n\t\t\t// should be set after last `listItem` (or block). This is why it feels safe to use it as `nextPosition`\n\t\t\tnextPosition = conversionApi.convertItem( child, nextPosition ).modelCursor;\n\t\t} else {\n\t\t\t// If this is not a list, try inserting content at the end of the currently handled `listItem`.\n\t\t\tconst result = conversionApi.convertItem( child, writer.createPositionAt( listItemModel, 'end' ) );\n\n\t\t\t// It may end up that the current `listItem` becomes split (if that content cannot be inside `listItem`). For example:\n\t\t\t//\n\t\t\t// <li><p>Foo</p></li>\n\t\t\t//\n\t\t\t// will be converted to:\n\t\t\t//\n\t\t\t// <listItem></listItem><paragraph>Foo</paragraph><listItem></listItem>\n\t\t\t//\n\t\t\tconst convertedChild = result.modelRange.start.nodeAfter;\n\t\t\tconst wasSplit = convertedChild && convertedChild.is( 'element' ) && !schema.checkChild( listItemModel, convertedChild.name );\n\n\t\t\tif ( wasSplit ) {\n\t\t\t\t// As `lastListItem` got split, we need to update it to the second part of the split `listItem` element.\n\t\t\t\t//\n\t\t\t\t// `modelCursor` should be set to a position where the conversion should continue. There are multiple possible scenarios\n\t\t\t\t// that may happen. Usually, `modelCursor` (marked as `#` below) would point to the second list item after conversion:\n\t\t\t\t//\n\t\t\t\t//\t\t`<li><p>Foo</p></li>` -> `<listItem></listItem><paragraph>Foo</paragraph><listItem>#</listItem>`\n\t\t\t\t//\n\t\t\t\t// However, in some cases, like auto-paragraphing, the position is placed at the end of the block element:\n\t\t\t\t//\n\t\t\t\t//\t\t`<li><div>Foo</div></li>` -> `<listItem></listItem><paragraph>Foo#</paragraph><listItem></listItem>`\n\t\t\t\t//\n\t\t\t\t// or after an element if another element broken auto-paragraphed element:\n\t\t\t\t//\n\t\t\t\t//\t\t`<li><div><h2>Foo</h2></div></li>` -> `<listItem></listItem><heading1>Foo</heading1>#<listItem></listItem>`\n\t\t\t\t//\n\t\t\t\t// We need to check for such cases and use proper list item and position based on it.\n\t\t\t\t//\n\t\t\t\tif ( result.modelCursor.parent.is( 'listItem' ) ) {\n\t\t\t\t\t// (1).\n\t\t\t\t\tlistItemModel = result.modelCursor.parent;\n\t\t\t\t} else {\n\t\t\t\t\t// (2), (3).\n\t\t\t\t\tlistItemModel = findNextListItem( result.modelCursor );\n\t\t\t\t}\n\n\t\t\t\tnextPosition = writer.createPositionAfter( listItemModel );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nextPosition;\n}\n\n// Helper function that seeks for a next list item starting from given `startPosition`.\nfunction findNextListItem( startPosition ) {\n\tconst treeWalker = new TreeWalker( { startPosition } );\n\n\tlet value;\n\n\tdo {\n\t\tvalue = treeWalker.next();\n\t} while ( !value.value.item.is( 'listItem' ) );\n\n\treturn value.value.item;\n}\n\n// Helper function that takes all children of given `viewRemovedItem` and moves them in a correct place, according\n// to other given parameters.\nfunction hoistNestedLists( nextIndent, modelRemoveStartPosition, viewRemoveStartPosition, viewRemovedItem, conversionApi, model ) {\n\t// Find correct previous model list item element.\n\t// The element has to have either same or smaller indent than given reference indent.\n\t// This will be the model element which will get nested items (if it has smaller indent) or sibling items (if it has same indent).\n\t// Keep in mind that such element might not be found, if removed item was the first item.\n\tconst prevModelItem = getSiblingListItem( modelRemoveStartPosition.nodeBefore, {\n\t\tsameIndent: true,\n\t\tsmallerIndent: true,\n\t\tlistIndent: nextIndent,\n\t\tfoo: 'b'\n\t} );\n\n\tconst mapper = conversionApi.mapper;\n\tconst viewWriter = conversionApi.writer;\n\n\t// Indent of found element or `null` if the element has not been found.\n\tconst prevIndent = prevModelItem ? prevModelItem.getAttribute( 'listIndent' ) : null;\n\n\tlet insertPosition;\n\n\tif ( !prevModelItem ) {\n\t\t// If element has not been found, simply insert lists at the position where the removed item was:\n\t\t//\n\t\t// Lorem ipsum.\n\t\t// 1 -------- <--- this is removed, no previous list item, put nested items in place of removed item.\n\t\t// 1.1 -------- <--- this is reference indent.\n\t\t// 1.1.1 --------\n\t\t// 1.1.2 --------\n\t\t// 1.2 --------\n\t\t//\n\t\t// Becomes:\n\t\t//\n\t\t// Lorem ipsum.\n\t\t// 1.1 --------\n\t\t// 1.1.1 --------\n\t\t// 1.1.2 --------\n\t\t// 1.2 --------\n\t\tinsertPosition = viewRemoveStartPosition;\n\t} else if ( prevIndent == nextIndent ) {\n\t\t// If element has been found and has same indent as reference indent it means that nested items should\n\t\t// become siblings of found element:\n\t\t//\n\t\t// 1 --------\n\t\t// 1.1 --------\n\t\t// 1.2 -------- <--- this is `prevModelItem`.\n\t\t// 2 -------- <--- this is removed, previous list item has indent same as reference indent.\n\t\t// 2.1 -------- <--- this is reference indent, this and 2.2 should become siblings of 1.2.\n\t\t// 2.2 --------\n\t\t//\n\t\t// Becomes:\n\t\t//\n\t\t// 1 --------\n\t\t// 1.1 --------\n\t\t// 1.2 --------\n\t\t// 2.1 --------\n\t\t// 2.2 --------\n\t\tconst prevViewList = mapper.toViewElement( prevModelItem ).parent;\n\t\tinsertPosition = viewWriter.createPositionAfter( prevViewList );\n\t} else {\n\t\t// If element has been found and has smaller indent as reference indent it means that nested items\n\t\t// should become nested items of found item:\n\t\t//\n\t\t// 1 -------- <--- this is `prevModelItem`.\n\t\t// 1.1 -------- <--- this is removed, previous list item has indent smaller than reference indent.\n\t\t// 1.1.1 -------- <--- this is reference indent, this and 1.1.1 should become nested items of 1.\n\t\t// 1.1.2 --------\n\t\t// 1.2 --------\n\t\t//\n\t\t// Becomes:\n\t\t//\n\t\t// 1 --------\n\t\t// 1.1.1 --------\n\t\t// 1.1.2 --------\n\t\t// 1.2 --------\n\t\t//\n\t\t// Note: in this case 1.1.1 have indent 2 while 1 have indent 0. In model that should not be possible,\n\t\t// because following item may have indent bigger only by one. But this is fixed by postfixer.\n\t\tconst modelPosition = model.createPositionAt( prevModelItem, 'end' );\n\t\tinsertPosition = mapper.toViewPosition( modelPosition );\n\t}\n\n\tinsertPosition = positionAfterUiElements( insertPosition );\n\n\t// Handle multiple lists. This happens if list item has nested numbered and bulleted lists. Following lists\n\t// are inserted after the first list (no need to recalculate insertion position for them).\n\tfor ( const child of [ ...viewRemovedItem.getChildren() ] ) {\n\t\tif ( isList( child ) ) {\n\t\t\tinsertPosition = viewWriter.move( viewWriter.createRangeOn( child ), insertPosition ).end;\n\n\t\t\tmergeViewLists( viewWriter, child, child.nextSibling );\n\t\t\tmergeViewLists( viewWriter, child.previousSibling, child );\n\t\t}\n\t}\n}\n\n// Checks if view element is a list type (ul or ol).\n//\n// @param {module:engine/view/element~Element} viewElement\n// @returns {Boolean}\nfunction isList( viewElement ) {\n\treturn viewElement.is( 'ol' ) || viewElement.is( 'ul' );\n}\n\n// Calculates the indent value for a list item. Handles HTML compliant and non-compliant lists.\n//\n// Also, fixes non HTML compliant lists indents:\n//\n//\t\tbefore: fixed list:\n//\t\tOL OL\n//\t\t|-> LI (parent LIs: 0) |-> LI (indent: 0)\n//\t\t |-> OL |-> OL\n//\t\t |-> OL |\n//\t\t | |-> OL |\n//\t\t | |-> OL |\n//\t\t | |-> LI (parent LIs: 1) |-> LI (indent: 1)\n//\t\t |-> LI (parent LIs: 1) |-> LI (indent: 1)\n//\n//\t\tbefore: fixed list:\n//\t\tOL OL\n//\t\t|-> OL |\n//\t\t |-> OL |\n//\t\t |-> OL |\n//\t\t |-> LI (parent LIs: 0) |-> LI (indent: 0)\n//\n//\t\tbefore: fixed list:\n//\t\tOL OL\n//\t\t|-> LI (parent LIs: 0) |-> LI (indent: 0)\n//\t\t|-> OL |-> OL\n//\t\t |-> LI (parent LIs: 0) |-> LI (indent: 1)\n//\n// @param {module:engine/view/element~Element} listItem\n// @param {Object} conversionStore\n// @returns {Number}\nfunction getIndent( listItem ) {\n\tlet indent = 0;\n\n\tlet parent = listItem.parent;\n\n\twhile ( parent ) {\n\t\t// Each LI in the tree will result in an increased indent for HTML compliant lists.\n\t\tif ( parent.is( 'li' ) ) {\n\t\t\tindent++;\n\t\t} else {\n\t\t\t// If however the list is nested in other list we should check previous sibling of any of the list elements...\n\t\t\tconst previousSibling = parent.previousSibling;\n\n\t\t\t// ...because the we might need increase its indent:\n\t\t\t//\t\tbefore: fixed list:\n\t\t\t//\t\tOL OL\n\t\t\t//\t\t|-> LI (parent LIs: 0) |-> LI (indent: 0)\n\t\t\t//\t\t|-> OL |-> OL\n\t\t\t//\t\t |-> LI (parent LIs: 0) |-> LI (indent: 1)\n\t\t\tif ( previousSibling && previousSibling.is( 'li' ) ) {\n\t\t\t\tindent++;\n\t\t\t}\n\t\t}\n\n\t\tparent = parent.parent;\n\t}\n\n\treturn indent;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 list/listediting\n */\n\nimport ListCommand from './listcommand';\nimport IndentCommand from './indentcommand';\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\n\nimport {\n\tcleanList,\n\tcleanListItem,\n\tmodelViewInsertion,\n\tmodelViewChangeType,\n\tmodelViewMergeAfterChangeType,\n\tmodelViewMergeAfter,\n\tmodelViewRemove,\n\tmodelViewSplitOnInsert,\n\tmodelViewChangeIndent,\n\tmodelChangePostFixer,\n\tmodelIndentPasteFixer,\n\tviewModelConverter,\n\tmodelToViewPosition,\n\tviewToModelPosition\n} from './converters';\n\n/**\n * The engine of the list feature. It handles creating, editing and removing lists and list items.\n *\n * It registers the `'numberedList'`, `'bulletedList'`, `'indentList'` and `'outdentList'` commands.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ListEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ListEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Paragraph ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Schema.\n\t\t// Note: in case `$block` will ever be allowed in `listItem`, keep in mind that this feature\n\t\t// uses `Selection#getSelectedBlocks()` without any additional processing to obtain all selected list items.\n\t\t// If there are blocks allowed inside list item, algorithms using `getSelectedBlocks()` will have to be modified.\n\t\teditor.model.schema.register( 'listItem', {\n\t\t\tinheritAllFrom: '$block',\n\t\t\tallowAttributes: [ 'listType', 'listIndent' ]\n\t\t} );\n\n\t\t// Converters.\n\t\tconst data = editor.data;\n\t\tconst editing = editor.editing;\n\n\t\teditor.model.document.registerPostFixer( writer => modelChangePostFixer( editor.model, writer ) );\n\n\t\tediting.mapper.registerViewToModelLength( 'li', getViewListItemLength );\n\t\tdata.mapper.registerViewToModelLength( 'li', getViewListItemLength );\n\n\t\tediting.mapper.on( 'modelToViewPosition', modelToViewPosition( editing.view ) );\n\t\tediting.mapper.on( 'viewToModelPosition', viewToModelPosition( editor.model ) );\n\t\tdata.mapper.on( 'modelToViewPosition', modelToViewPosition( editing.view ) );\n\n\t\teditor.conversion.for( 'editingDowncast' )\n\t\t\t.add( dispatcher => {\n\t\t\t\tdispatcher.on( 'insert', modelViewSplitOnInsert, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'insert:listItem', modelViewInsertion( editor.model ) );\n\t\t\t\tdispatcher.on( 'attribute:listType:listItem', modelViewChangeType, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'attribute:listType:listItem', modelViewMergeAfterChangeType, { priority: 'low' } );\n\t\t\t\tdispatcher.on( 'attribute:listIndent:listItem', modelViewChangeIndent( editor.model ) );\n\t\t\t\tdispatcher.on( 'remove:listItem', modelViewRemove( editor.model ) );\n\t\t\t\tdispatcher.on( 'remove', modelViewMergeAfter, { priority: 'low' } );\n\t\t\t} );\n\n\t\teditor.conversion.for( 'dataDowncast' )\n\t\t\t.add( dispatcher => {\n\t\t\t\tdispatcher.on( 'insert', modelViewSplitOnInsert, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'insert:listItem', modelViewInsertion( editor.model ) );\n\t\t\t} );\n\n\t\teditor.conversion.for( 'upcast' )\n\t\t\t.add( dispatcher => {\n\t\t\t\tdispatcher.on( 'element:ul', cleanList, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'element:ol', cleanList, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'element:li', cleanListItem, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'element:li', viewModelConverter );\n\t\t\t} );\n\n\t\t// Fix indentation of pasted items.\n\t\teditor.model.on( 'insertContent', modelIndentPasteFixer, { priority: 'high' } );\n\n\t\t// Register commands for numbered and bulleted list.\n\t\teditor.commands.add( 'numberedList', new ListCommand( editor, 'numbered' ) );\n\t\teditor.commands.add( 'bulletedList', new ListCommand( editor, 'bulleted' ) );\n\n\t\t// Register commands for indenting.\n\t\teditor.commands.add( 'indentList', new IndentCommand( editor, 'forward' ) );\n\t\teditor.commands.add( 'outdentList', new IndentCommand( editor, 'backward' ) );\n\n\t\tconst viewDocument = editing.view.document;\n\n\t\t// Overwrite default Enter key behavior.\n\t\t// If Enter key is pressed with selection collapsed in empty list item, outdent it instead of breaking it.\n\t\tthis.listenTo( viewDocument, 'enter', ( evt, data ) => {\n\t\t\tconst doc = this.editor.model.document;\n\t\t\tconst positionParent = doc.selection.getLastPosition().parent;\n\n\t\t\tif ( doc.selection.isCollapsed && positionParent.name == 'listItem' && positionParent.isEmpty ) {\n\t\t\t\tthis.editor.execute( 'outdentList' );\n\n\t\t\t\tdata.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t} );\n\n\t\t// Overwrite default Backspace key behavior.\n\t\t// If Backspace key is pressed with selection collapsed on first position in first list item, outdent it. #83\n\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\t// Check conditions from those that require less computations like those immediately available.\n\t\t\tif ( data.direction !== 'backward' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selection = this.editor.model.document.selection;\n\n\t\t\tif ( !selection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst firstPosition = selection.getFirstPosition();\n\n\t\t\tif ( !firstPosition.isAtStart ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst positionParent = firstPosition.parent;\n\n\t\t\tif ( positionParent.name !== 'listItem' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst previousIsAListItem = positionParent.previousSibling && positionParent.previousSibling.name === 'listItem';\n\n\t\t\tif ( previousIsAListItem ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.editor.execute( 'outdentList' );\n\n\t\t\tdata.preventDefault();\n\t\t\tevt.stop();\n\t\t}, { priority: 'high' } );\n\n\t\tconst getCommandExecuter = commandName => {\n\t\t\treturn ( data, cancel ) => {\n\t\t\t\tconst command = this.editor.commands.get( commandName );\n\n\t\t\t\tif ( command.isEnabled ) {\n\t\t\t\t\tthis.editor.execute( commandName );\n\t\t\t\t\tcancel();\n\t\t\t\t}\n\t\t\t};\n\t\t};\n\n\t\teditor.keystrokes.set( 'Tab', getCommandExecuter( 'indentList' ) );\n\t\teditor.keystrokes.set( 'Shift+Tab', getCommandExecuter( 'outdentList' ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst commands = this.editor.commands;\n\n\t\tconst indent = commands.get( 'indent' );\n\t\tconst outdent = commands.get( 'outdent' );\n\n\t\tif ( indent ) {\n\t\t\tindent.registerChildCommand( commands.get( 'indentList' ) );\n\t\t}\n\n\t\tif ( outdent ) {\n\t\t\toutdent.registerChildCommand( commands.get( 'outdentList' ) );\n\t\t}\n\t}\n}\n\nfunction getViewListItemLength( element ) {\n\tlet length = 1;\n\n\tfor ( const child of element.getChildren() ) {\n\t\tif ( child.name == 'ul' || child.name == 'ol' ) {\n\t\t\tfor ( const item of child.getChildren() ) {\n\t\t\t\tlength += getViewListItemLength( item );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn length;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module list/listui\n */\nimport { createUIComponent } from './utils';\nimport numberedListIcon from '../theme/assets/icons/numberedlist.svg';\nimport bulletedListIcon from '../theme/assets/icons/bulletedlist.svg';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n/**\n * The list UI feature. It introduces the `'numberedList'` and `'bulletedList'` buttons that\n * allow to convert paragraphs to and from list items and indent or outdent them.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ListUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const t = this.editor.t;\n // Create two buttons and link them with numberedList and bulletedList commands.\n createUIComponent(this.editor, 'numberedList', t('w'), numberedListIcon);\n createUIComponent(this.editor, 'bulletedList', t('x'), bulletedListIcon);\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M7 5.75c0 .414.336.75.75.75h9.5a.75.75 0 100-1.5h-9.5a.75.75 0 00-.75.75zM3.5 3v5H2V3.7H1v-1h2.5V3zM.343 17.857l2.59-3.257H2.92a.6.6 0 10-1.04 0H.302a2 2 0 113.995 0h-.001c-.048.405-.16.734-.333.988-.175.254-.59.692-1.244 1.312H4.3v1h-4l.043-.043zM7 14.75a.75.75 0 01.75-.75h9.5a.75.75 0 110 1.5h-9.5a.75.75 0 01-.75-.75z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M7 5.75c0 .414.336.75.75.75h9.5a.75.75 0 100-1.5h-9.5a.75.75 0 00-.75.75zm-6 0C1 4.784 1.777 4 2.75 4c.966 0 1.75.777 1.75 1.75 0 .966-.777 1.75-1.75 1.75C1.784 7.5 1 6.723 1 5.75zm6 9c0 .414.336.75.75.75h9.5a.75.75 0 100-1.5h-9.5a.75.75 0 00-.75.75zm-6 0c0-.966.777-1.75 1.75-1.75.966 0 1.75.777 1.75 1.75 0 .966-.777 1.75-1.75 1.75-.966 0-1.75-.777-1.75-1.75z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 media-embed/converters\n */\n\n/**\n * Returns a function that converts the model \"url\" attribute to the view representation.\n *\n * Depending on the configuration, the view representation can be \"semantic\" (for the data pipeline):\n *\n *\t\t<figure class=\"media\">\n *\t\t\t<oembed url=\"foo\"></oembed>\n *\t\t</figure>\n *\n * or \"non-semantic\" (for the editing view pipeline):\n *\n *\t\t<figure class=\"media\">\n *\t\t\t<div data-oembed-url=\"foo\">[ non-semantic media preview for \"foo\" ]</div>\n *\t\t</figure>\n *\n * **Note:** Changing the model \"url\" attribute replaces the entire content of the\n * `<figure>` in the view.\n *\n * @param {module:media-embed/mediaregistry~MediaRegistry} registry The registry providing\n * the media and their content.\n * @param {Object} options\n * @param {String} [options.renderMediaPreview] When `true`, the converter will create the view in the non-semantic form.\n * @param {String} [options.renderForEditingView] When `true`, the converter will create a view specific for the\n * editing pipeline (e.g. including CSS classes, content placeholders).\n * @returns {Function}\n */\nexport function modelToViewUrlAttributeConverter( registry, options ) {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'attribute:url:media', converter );\n\t};\n\n\tfunction converter( evt, data, conversionApi ) {\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = data.attributeNewValue;\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst figure = conversionApi.mapper.toViewElement( data.item );\n\n\t\t// TODO: removing it and creating it from scratch is a hack. We can do better than that.\n\t\tviewWriter.remove( viewWriter.createRangeIn( figure ) );\n\n\t\tconst mediaViewElement = registry.getMediaViewElement( viewWriter, url, options );\n\n\t\tviewWriter.insert( viewWriter.createPositionAt( figure, 0 ), mediaViewElement );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 media-embed/utils\n */\n\nimport { isWidget, toWidget } from '@ckeditor/ckeditor5-widget/src/utils';\n\n/**\n * Converts a given {@link module:engine/view/element~Element} to a media embed widget:\n * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the media widget element.\n * * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.\n * @param {String} label The element's label.\n * @returns {module:engine/view/element~Element}\n */\nexport function toMediaWidget( viewElement, writer, label ) {\n\twriter.setCustomProperty( 'media', true, viewElement );\n\n\treturn toWidget( viewElement, writer, { label } );\n}\n\n/**\n * Returns a media widget editing view element if one is selected.\n *\n * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection\n * @returns {module:engine/view/element~Element|null}\n */\nexport function getSelectedMediaViewWidget( selection ) {\n\tconst viewElement = selection.getSelectedElement();\n\n\tif ( viewElement && isMediaWidget( viewElement ) ) {\n\t\treturn viewElement;\n\t}\n\n\treturn null;\n}\n\n/**\n * Checks if a given view element is a media widget.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @returns {Boolean}\n */\nexport function isMediaWidget( viewElement ) {\n\treturn !!viewElement.getCustomProperty( 'media' ) && isWidget( viewElement );\n}\n\n/**\n * Creates a view element representing the media. Either \"semantic\" one for the data pipeline:\n *\n *\t\t<figure class=\"media\">\n *\t\t\t<oembed url=\"foo\"></oembed>\n *\t\t</figure>\n *\n * or \"non-semantic\" (for the editing view pipeline):\n *\n *\t\t<figure class=\"media\">\n *\t\t\t<div data-oembed-url=\"foo\">[ non-semantic media preview for \"foo\" ]</div>\n *\t\t</figure>\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:media-embed/mediaregistry~MediaRegistry} registry\n * @param {String} url\n * @param {Object} options\n * @param {String} [options.useSemanticWrapper]\n * @param {String} [options.renderForEditingView]\n * @returns {module:engine/view/containerelement~ContainerElement}\n */\nexport function createMediaFigureElement( writer, registry, url, options ) {\n\tconst figure = writer.createContainerElement( 'figure', { class: 'media' } );\n\n\t// TODO: This is a hack. Without it, the figure in the data pipeline will contain because\n\t// its only child is the UIElement (wrapper).\n\t//\n\t// Note: The hack is a copy&paste from widget utils; it makes the figure act like it's a widget.\n\tfigure.getFillerOffset = getFillerOffset;\n\n\twriter.insert( writer.createPositionAt( figure, 0 ), registry.getMediaViewElement( writer, url, options ) );\n\n\treturn figure;\n}\n\n/**\n * Returns a selected media element in the model, if any.\n *\n * @param {module:engine/model/selection~Selection} selection\n * @returns {module:engine/model/element~Element|null}\n */\nexport function getSelectedMediaModelWidget( selection ) {\n\tconst selectedElement = selection.getSelectedElement();\n\n\tif ( selectedElement && selectedElement.is( 'media' ) ) {\n\t\treturn selectedElement;\n\t}\n\n\treturn null;\n}\n\n/**\n * Creates a media element and inserts it into the model.\n *\n * **Note**: This method will use {@link module:engine/model/model~Model#insertContent `model.insertContent()`} logic of inserting content\n * if no `insertPosition` is passed.\n *\n * @param {module:engine/model/model~Model} model\n * @param {String} url An URL of an embeddable media.\n * @param {module:engine/model/position~Position} [insertPosition] Position to insert media. If not specified,\n * the default behavior of {@link module:engine/model/model~Model#insertContent `model.insertContent()`} will\n * be applied.\n */\nexport function insertMedia( model, url, insertPosition ) {\n\tmodel.change( writer => {\n\t\tconst mediaElement = writer.createElement( 'media', { url } );\n\n\t\tmodel.insertContent( mediaElement, insertPosition );\n\n\t\twriter.setSelection( mediaElement, 'on' );\n\t} );\n}\n\nfunction getFillerOffset() {\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 media-embed/mediaembedcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { findOptimalInsertionPosition } from '@ckeditor/ckeditor5-widget/src/utils';\nimport { getSelectedMediaModelWidget, insertMedia } from './utils';\n\n/**\n * The insert media command.\n *\n * The command is registered by the {@link module:media-embed/mediaembedediting~MediaEmbedEditing} as `'mediaEmbed'`.\n *\n * To insert media at the current selection, execute the command and specify the URL:\n *\n *\t\teditor.execute( 'mediaEmbed', 'http://url.to.the/media' );\n *\n * @extends module:core/command~Command\n */\nexport default class MediaEmbedCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst schema = model.schema;\n\t\tconst position = selection.getFirstPosition();\n\t\tconst selectedMedia = getSelectedMediaModelWidget( selection );\n\n\t\tlet parent = position.parent;\n\n\t\tif ( parent != parent.root ) {\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\tthis.value = selectedMedia ? selectedMedia.getAttribute( 'url' ) : null;\n\t\tthis.isEnabled = schema.checkChild( parent, 'media' );\n\t}\n\n\t/**\n\t * Executes the command, which either:\n\t *\n\t * * updates the URL of the selected media,\n\t * * inserts the new media into the editor and puts the selection around it.\n\t *\n\t * @fires execute\n\t * @param {String} url The URL of the media.\n\t */\n\texecute( url ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst selectedMedia = getSelectedMediaModelWidget( selection );\n\n\t\tif ( selectedMedia ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setAttribute( 'url', url, selectedMedia );\n\t\t\t} );\n\t\t} else {\n\t\t\tconst insertPosition = findOptimalInsertionPosition( selection, model );\n\n\t\t\tinsertMedia( model, url, insertPosition );\n\t\t}\n\t}\n}\n\n","/**\n * @license Copyright (c) 2003-2020, 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 media-embed/mediaregistry\n */\n\n/* globals console */\n\nimport mediaPlaceholderIcon from '../theme/assets/icons/media-placeholder.svg';\nimport TooltipView from '@ckeditor/ckeditor5-ui/src/tooltip/tooltipview';\nimport IconView from '@ckeditor/ckeditor5-ui/src/icon/iconview';\nimport Template from '@ckeditor/ckeditor5-ui/src/template';\nimport { attachLinkToDocumentation } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nconst mediaPlaceholderIconViewBox = '0 0 64 42';\n\n/**\n * A bridge between the raw media content provider definitions and the editor view content.\n *\n * It helps translating media URLs to corresponding {@link module:engine/view/element~Element view elements}.\n *\n * Mostly used by the {@link module:media-embed/mediaembedediting~MediaEmbedEditing} plugin.\n */\nexport default class MediaRegistry {\n\t/**\n\t * Creates an instance of the {@link module:media-embed/mediaregistry~MediaRegistry} class.\n\t *\n\t * @param {module:utils/locale~Locale} locale The localization services instance.\n\t * @param {module:media-embed/mediaembed~MediaEmbedConfig} config The configuration of the media embed feature.\n\t */\n\tconstructor( locale, config ) {\n\t\tconst providers = config.providers;\n\t\tconst extraProviders = config.extraProviders || [];\n\t\tconst removedProviders = new Set( config.removeProviders );\n\t\tconst providerDefinitions = providers\n\t\t\t.concat( extraProviders )\n\t\t\t.filter( provider => {\n\t\t\t\tconst name = provider.name;\n\n\t\t\t\tif ( !name ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * One of the providers (or extra providers) specified in the media embed configuration\n\t\t\t\t\t * has no name and will not be used by the editor. In order to get this media\n\t\t\t\t\t * provider working, double check your editor configuration.\n\t\t\t\t\t *\n\t\t\t\t\t * @warning media-embed-no-provider-name\n\t\t\t\t\t */\n\t\t\t\t\tconsole.warn( attachLinkToDocumentation(\n\t\t\t\t\t\t'media-embed-no-provider-name: The configured media provider has no name and cannot be used.'\n\t\t\t\t\t), { provider } );\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\treturn !removedProviders.has( name );\n\t\t\t} );\n\n\t\t/**\n\t\t * The locale {@link module:utils/locale~Locale} instance.\n\t\t *\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = locale;\n\n\t\t/**\n\t\t * The media provider definitions available for the registry. Usually corresponding with the\n\t\t * {@link module:media-embed/mediaembed~MediaEmbedConfig media configuration}.\n\t\t *\n\t\t * @member {Array}\n\t\t */\n\t\tthis.providerDefinitions = providerDefinitions;\n\t}\n\n\t/**\n\t * Checks whether the passed URL is representing a certain media type allowed in the editor.\n\t *\n\t * @param {String} url The URL to be checked\n\t * @returns {Boolean}\n\t */\n\thasMedia( url ) {\n\t\treturn !!this._getMedia( url );\n\t}\n\n\t/**\n\t * For the given media URL string and options, it returns the {@link module:engine/view/element~Element view element}\n\t * representing that media.\n\t *\n\t * **Note:** If no URL is specified, an empty view element is returned.\n\t *\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer used to produce a view element.\n\t * @param {String} url The URL to be translated into a view element.\n\t * @param {Object} options\n\t * @param {String} [options.renderMediaPreview]\n\t * @param {String} [options.renderForEditingView]\n\t * @returns {module:engine/view/element~Element}\n\t */\n\tgetMediaViewElement( writer, url, options ) {\n\t\treturn this._getMedia( url ).getViewElement( writer, options );\n\t}\n\n\t/**\n\t * Returns a `Media` instance for the given URL.\n\t *\n\t * @protected\n\t * @param {String} url The URL of the media.\n\t * @returns {module:media-embed/mediaregistry~Media|null} The `Media` instance or `null` when there is none.\n\t */\n\t_getMedia( url ) {\n\t\tif ( !url ) {\n\t\t\treturn new Media( this.locale );\n\t\t}\n\n\t\turl = url.trim();\n\n\t\tfor ( const definition of this.providerDefinitions ) {\n\t\t\tconst previewRenderer = definition.html;\n\t\t\tlet pattern = definition.url;\n\n\t\t\tif ( !Array.isArray( pattern ) ) {\n\t\t\t\tpattern = [ pattern ];\n\t\t\t}\n\n\t\t\tfor ( const subPattern of pattern ) {\n\t\t\t\tconst match = this._getUrlMatches( url, subPattern );\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\treturn new Media( this.locale, url, match, previewRenderer );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Tries to match `url` to `pattern`.\n\t *\n\t * @private\n\t * @param {String} url The URL of the media.\n\t * @param {RegExp} pattern The pattern that should accept the media URL.\n\t * @returns {Array|null}\n\t */\n\t_getUrlMatches( url, pattern ) {\n\t\t// 1. Try to match without stripping the protocol and \"www\" subdomain.\n\t\tlet match = url.match( pattern );\n\n\t\tif ( match ) {\n\t\t\treturn match;\n\t\t}\n\n\t\t// 2. Try to match after stripping the protocol.\n\t\tlet rawUrl = url.replace( /^https?:\\/\\//, '' );\n\t\tmatch = rawUrl.match( pattern );\n\n\t\tif ( match ) {\n\t\t\treturn match;\n\t\t}\n\n\t\t// 3. Try to match after stripping the \"www\" subdomain.\n\t\trawUrl = rawUrl.replace( /^www\\./, '' );\n\t\tmatch = rawUrl.match( pattern );\n\n\t\tif ( match ) {\n\t\t\treturn match;\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\n/**\n * Represents media defined by the provider configuration.\n *\n * It can be rendered to the {@link module:engine/view/element~Element view element} and used in the editing or data pipeline.\n *\n * @private\n */\nclass Media {\n\tconstructor( locale, url, match, previewRenderer ) {\n\t\t/**\n\t\t * The URL this Media instance represents.\n\t\t *\n\t\t * @member {String}\n\t\t */\n\t\tthis.url = this._getValidUrl( url );\n\n\t\t/**\n\t\t * Shorthand for {@link module:utils/locale~Locale#t}.\n\t\t *\n\t\t * @see module:utils/locale~Locale#t\n\t\t * @method\n\t\t */\n\t\tthis._t = locale.t;\n\n\t\t/**\n\t\t * The output of the `RegExp.match` which validated the {@link #url} of this media.\n\t\t *\n\t\t * @member {Object}\n\t\t */\n\t\tthis._match = match;\n\n\t\t/**\n\t\t * The function returning the HTML string preview of this media.\n\t\t *\n\t\t * @member {Function}\n\t\t */\n\t\tthis._previewRenderer = previewRenderer;\n\t}\n\n\t/**\n\t * Returns the view element representation of the media.\n\t *\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer used to produce a view element.\n\t * @param {Object} options\n\t * @param {String} [options.renderMediaPreview]\n\t * @param {String} [options.renderForEditingView]\n\t * @returns {module:engine/view/element~Element}\n\t */\n\tgetViewElement( writer, options ) {\n\t\tconst attributes = {};\n\n\t\tif ( options.renderForEditingView || ( options.renderMediaPreview && this.url && this._previewRenderer ) ) {\n\t\t\tif ( this.url ) {\n\t\t\t\tattributes[ 'data-oembed-url' ] = this.url;\n\t\t\t}\n\n\t\t\tif ( options.renderForEditingView ) {\n\t\t\t\tattributes.class = 'ck-media__wrapper';\n\t\t\t}\n\n\t\t\tconst mediaHtml = this._getPreviewHtml( options );\n\n\t\t\treturn writer.createUIElement( 'div', attributes, function( domDocument ) {\n\t\t\t\tconst domElement = this.toDomElement( domDocument );\n\n\t\t\t\tdomElement.innerHTML = mediaHtml;\n\n\t\t\t\treturn domElement;\n\t\t\t} );\n\t\t} else {\n\t\t\tif ( this.url ) {\n\t\t\t\tattributes.url = this.url;\n\t\t\t}\n\n\t\t\treturn writer.createEmptyElement( 'oembed', attributes );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the HTML string of the media content preview.\n\t *\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer used to produce a view element.\n\t * @param {Object} options\n\t * @param {String} [options.renderForEditingView]\n\t * @returns {String}\n\t */\n\t_getPreviewHtml( options ) {\n\t\tif ( this._previewRenderer ) {\n\t\t\treturn this._previewRenderer( this._match );\n\t\t} else {\n\t\t\t// The placeholder only makes sense for editing view and media which have URLs.\n\t\t\t// Placeholder is never displayed in data and URL-less media have no content.\n\t\t\tif ( this.url && options.renderForEditingView ) {\n\t\t\t\treturn this._getPlaceholderHtml();\n\t\t\t}\n\n\t\t\treturn '';\n\t\t}\n\t}\n\n\t/**\n\t * Returns the placeholder HTML when the media has no content preview.\n\t *\n\t * @returns {String}\n\t */\n\t_getPlaceholderHtml() {\n\t\tconst tooltip = new TooltipView();\n\t\tconst icon = new IconView();\n\n\t\ttooltip.text = this._t( 'Open media in new tab' );\n\t\ticon.content = mediaPlaceholderIcon;\n\t\ticon.viewBox = mediaPlaceholderIconViewBox;\n\n\t\tconst placeholder = new Template( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck ck-reset_all ck-media__placeholder'\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: 'ck-media__placeholder__icon'\n\t\t\t\t\t},\n\t\t\t\t\tchildren: [ icon ]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttag: 'a',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: 'ck-media__placeholder__url',\n\t\t\t\t\t\ttarget: '_blank',\n\t\t\t\t\t\trel: 'noopener noreferrer',\n\t\t\t\t\t\thref: this.url\n\t\t\t\t\t},\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttag: 'span',\n\t\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\t\tclass: 'ck-media__placeholder__url__text'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren: [ this.url ]\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttooltip\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t} ).render();\n\n\t\treturn placeholder.outerHTML;\n\t}\n\n\t/**\n\t * Returns the full URL to the specified media.\n\t *\n\t * @param {String} url The URL of the media.\n\t * @returns {String|null}\n\t */\n\t_getValidUrl( url ) {\n\t\tif ( !url ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( url.match( /^https?/ ) ) {\n\t\t\treturn url;\n\t\t}\n\n\t\treturn 'https://' + url;\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 64 42\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M47.426 17V3.713L63.102 0v19.389h-.001l.001.272c0 1.595-2.032 3.43-4.538 4.098-2.506.668-4.538-.083-4.538-1.678 0-1.594 2.032-3.43 4.538-4.098.914-.244 2.032-.565 2.888-.603V4.516L49.076 7.447v9.556A1.014 1.014 0 0049 17h-1.574zM29.5 17h-8.343a7.073 7.073 0 10-4.657 4.06v3.781H3.3a2.803 2.803 0 01-2.8-2.804V8.63a2.803 2.803 0 012.8-2.805h4.082L8.58 2.768A1.994 1.994 0 0110.435 1.5h8.985c.773 0 1.477.448 1.805 1.149l1.488 3.177H26.7c1.546 0 2.8 1.256 2.8 2.805V17zm-11.637 0H17.5a1 1 0 00-1 1v.05A4.244 4.244 0 1117.863 17zm29.684 2c.97 0 .953-.048.953.889v20.743c0 .953.016.905-.953.905H19.453c-.97 0-.953.048-.953-.905V19.89c0-.937-.016-.889.97-.889h28.077zm-4.701 19.338V22.183H24.154v16.155h18.692zM20.6 21.375v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616V37.53H20.6zm24.233-16.155v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615V37.53h-1.615zM29.485 25.283a.4.4 0 01.593-.35l9.05 4.977a.4.4 0 010 .701l-9.05 4.978a.4.4 0 01-.593-.35v-9.956z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module media-embed/mediaembedediting\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { modelToViewUrlAttributeConverter } from './converters';\nimport MediaEmbedCommand from './mediaembedcommand';\nimport MediaRegistry from './mediaregistry';\nimport {\n toMediaWidget,\n createMediaFigureElement\n} from './utils';\nimport '../theme/mediaembedediting.css';\n/**\n * The media embed editing feature.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class MediaEmbedEditing extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'MediaEmbedEditing';\n }\n /**\n\t * @inheritDoc\n\t */\n constructor(editor) {\n super(editor);\n editor.config.define('mediaEmbed', {\n providers: [\n {\n name: 'dailymotion',\n url: /^dailymotion\\.com\\/video\\/(\\w+)/,\n html: match => {\n const id = match[1];\n return '<div style=\"position: relative; padding-bottom: 100%; height: 0; \">' + `<iframe src=\"https://www.dailymotion.com/embed/video/${ id }\" ` + 'style=\"position: absolute; width: 100%; height: 100%; top: 0; left: 0;\" ' + 'frameborder=\"0\" width=\"480\" height=\"270\" allowfullscreen allow=\"autoplay\">' + '</iframe>' + '</div>';\n }\n },\n {\n name: 'spotify',\n url: [\n /^open\\.spotify\\.com\\/(artist\\/\\w+)/,\n /^open\\.spotify\\.com\\/(album\\/\\w+)/,\n /^open\\.spotify\\.com\\/(track\\/\\w+)/\n ],\n html: match => {\n const id = match[1];\n return '<div style=\"position: relative; padding-bottom: 100%; height: 0; padding-bottom: 126%;\">' + `<iframe src=\"https://open.spotify.com/embed/${ id }\" ` + 'style=\"position: absolute; width: 100%; height: 100%; top: 0; left: 0;\" ' + 'frameborder=\"0\" allowtransparency=\"true\" allow=\"encrypted-media\">' + '</iframe>' + '</div>';\n }\n },\n {\n name: 'youtube',\n url: [\n /^(?:m\\.)?youtube\\.com\\/watch\\?v=([\\w-]+)/,\n /^(?:m\\.)?youtube\\.com\\/v\\/([\\w-]+)/,\n /^youtube\\.com\\/embed\\/([\\w-]+)/,\n /^youtu\\.be\\/([\\w-]+)/\n ],\n html: match => {\n const id = match[1];\n return '<div style=\"position: relative; padding-bottom: 100%; height: 0; padding-bottom: 56.2493%;\">' + `<iframe src=\"https://www.youtube.com/embed/${ id }\" ` + 'style=\"position: absolute; width: 100%; height: 100%; top: 0; left: 0;\" ' + 'frameborder=\"0\" allow=\"autoplay; encrypted-media\" allowfullscreen>' + '</iframe>' + '</div>';\n }\n },\n {\n name: 'vimeo',\n url: [\n /^vimeo\\.com\\/(\\d+)/,\n /^vimeo\\.com\\/[^/]+\\/[^/]+\\/video\\/(\\d+)/,\n /^vimeo\\.com\\/album\\/[^/]+\\/video\\/(\\d+)/,\n /^vimeo\\.com\\/channels\\/[^/]+\\/(\\d+)/,\n /^vimeo\\.com\\/groups\\/[^/]+\\/videos\\/(\\d+)/,\n /^vimeo\\.com\\/ondemand\\/[^/]+\\/(\\d+)/,\n /^player\\.vimeo\\.com\\/video\\/(\\d+)/\n ],\n html: match => {\n const id = match[1];\n return '<div style=\"position: relative; padding-bottom: 100%; height: 0; padding-bottom: 56.2493%;\">' + `<iframe src=\"https://player.vimeo.com/video/${ id }\" ` + 'style=\"position: absolute; width: 100%; height: 100%; top: 0; left: 0;\" ' + 'frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen>' + '</iframe>' + '</div>';\n }\n },\n {\n name: 'instagram',\n url: /^instagram\\.com\\/p\\/(\\w+)/\n },\n {\n name: 'twitter',\n url: /^twitter\\.com/\n },\n {\n name: 'googleMaps',\n url: /^google\\.com\\/maps/\n },\n {\n name: 'flickr',\n url: /^flickr\\.com/\n },\n {\n name: 'facebook',\n url: /^facebook\\.com/\n }\n ]\n });\n /**\n\t\t * The media registry managing the media providers in the editor.\n\t\t *\n\t\t * @member {module:media-embed/mediaregistry~MediaRegistry} #registry\n\t\t */\n this.registry = new MediaRegistry(editor.locale, editor.config.get('mediaEmbed'));\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const schema = editor.model.schema;\n const t = editor.t;\n const conversion = editor.conversion;\n const renderMediaPreview = editor.config.get('mediaEmbed.previewsInData');\n const registry = this.registry;\n editor.commands.add('mediaEmbed', new MediaEmbedCommand(editor));\n // Configure the schema.\n schema.register('media', {\n isObject: true,\n isBlock: true,\n allowWhere: '$block',\n allowAttributes: ['url']\n });\n // Model -> Data\n conversion.for('dataDowncast').elementToElement({\n model: 'media',\n view: (modelElement, viewWriter) => {\n const url = modelElement.getAttribute('url');\n return createMediaFigureElement(viewWriter, registry, url, { renderMediaPreview: url && renderMediaPreview });\n }\n });\n // Model -> Data (url -> data-oembed-url)\n conversion.for('dataDowncast').add(modelToViewUrlAttributeConverter(registry, { renderMediaPreview }));\n // Model -> View (element)\n conversion.for('editingDowncast').elementToElement({\n model: 'media',\n view: (modelElement, viewWriter) => {\n const url = modelElement.getAttribute('url');\n const figure = createMediaFigureElement(viewWriter, registry, url, { renderForEditingView: true });\n return toMediaWidget(figure, viewWriter, t('ah'));\n }\n });\n // Model -> View (url -> data-oembed-url)\n conversion.for('editingDowncast').add(modelToViewUrlAttributeConverter(registry, { renderForEditingView: true }));\n // View -> Model (data-oembed-url -> url)\n conversion.for('upcast') // Upcast semantic media.\n.elementToElement({\n view: {\n name: 'oembed',\n attributes: { url: true }\n },\n model: (viewMedia, modelWriter) => {\n const url = viewMedia.getAttribute('url');\n if (registry.hasMedia(url)) {\n return modelWriter.createElement('media', { url });\n }\n }\n }) // Upcast non-semantic media.\n.elementToElement({\n view: {\n name: 'div',\n attributes: { 'data-oembed-url': true }\n },\n model: (viewMedia, modelWriter) => {\n const url = viewMedia.getAttribute('data-oembed-url');\n if (registry.hasMedia(url)) {\n return modelWriter.createElement('media', { url });\n }\n }\n });\n }\n}","/**\n * @license Copyright (c) 2003-2020, 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 media-embed/automediaembed\n */\n\nimport MediaEmbedEditing from './mediaembedediting';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';\nimport LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange';\nimport LivePosition from '@ckeditor/ckeditor5-engine/src/model/liveposition';\nimport Undo from '@ckeditor/ckeditor5-undo/src/undo';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport { insertMedia } from './utils';\n\nconst URL_REGEXP = /^(?:http(s)?:\\/\\/)?[\\w.-]+(?:\\.[\\w.-]+)+[\\w\\-._~:/?#[\\]@!$&'()*+,;=]+$/;\n\n/**\n * The auto-media embed plugin. It recognizes media links in the pasted content and embeds\n * them shortly after they are injected into the document.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class AutoMediaEmbed extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Clipboard, Undo ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'AutoMediaEmbed';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The paste–to–embed `setTimeout` ID. Stored as a property to allow\n\t\t * cleaning of the timeout.\n\t\t *\n\t\t * @private\n\t\t * @member {Number} #_timeoutId\n\t\t */\n\t\tthis._timeoutId = null;\n\n\t\t/**\n\t\t * The position where the `<media>` element will be inserted after the timeout,\n\t\t * determined each time the new content is pasted into the document.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/liveposition~LivePosition} #_positionToInsert\n\t\t */\n\t\tthis._positionToInsert = null;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst modelDocument = editor.model.document;\n\n\t\t// We need to listen on `Clipboard#inputTransformation` because we need to save positions of selection.\n\t\t// After pasting, the content between those positions will be checked for a URL that could be transformed\n\t\t// into media.\n\t\tthis.listenTo( editor.plugins.get( Clipboard ), 'inputTransformation', () => {\n\t\t\tconst firstRange = modelDocument.selection.getFirstRange();\n\n\t\t\tconst leftLivePosition = LivePosition.fromPosition( firstRange.start );\n\t\t\tleftLivePosition.stickiness = 'toPrevious';\n\n\t\t\tconst rightLivePosition = LivePosition.fromPosition( firstRange.end );\n\t\t\trightLivePosition.stickiness = 'toNext';\n\n\t\t\tmodelDocument.once( 'change:data', () => {\n\t\t\t\tthis._embedMediaBetweenPositions( leftLivePosition, rightLivePosition );\n\n\t\t\t\tleftLivePosition.detach();\n\t\t\t\trightLivePosition.detach();\n\t\t\t}, { priority: 'high' } );\n\t\t} );\n\n\t\teditor.commands.get( 'undo' ).on( 'execute', () => {\n\t\t\tif ( this._timeoutId ) {\n\t\t\t\tglobal.window.clearTimeout( this._timeoutId );\n\t\t\t\tthis._positionToInsert.detach();\n\n\t\t\t\tthis._timeoutId = null;\n\t\t\t\tthis._positionToInsert = null;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Analyzes the part of the document between provided positions in search for a URL representing media.\n\t * When the URL is found, it is automatically converted into media.\n\t *\n\t * @protected\n\t * @param {module:engine/model/liveposition~LivePosition} leftPosition Left position of the selection.\n\t * @param {module:engine/model/liveposition~LivePosition} rightPosition Right position of the selection.\n\t */\n\t_embedMediaBetweenPositions( leftPosition, rightPosition ) {\n\t\tconst editor = this.editor;\n\t\tconst mediaRegistry = editor.plugins.get( MediaEmbedEditing ).registry;\n\t\t// TODO: Use marker instead of LiveRange & LivePositions.\n\t\tconst urlRange = new LiveRange( leftPosition, rightPosition );\n\t\tconst walker = urlRange.getWalker( { ignoreElementEnd: true } );\n\n\t\tlet url = '';\n\n\t\tfor ( const node of walker ) {\n\t\t\tif ( node.item.is( 'textProxy' ) ) {\n\t\t\t\turl += node.item.data;\n\t\t\t}\n\t\t}\n\n\t\turl = url.trim();\n\n\t\t// If the URL does not match to universal URL regexp, let's skip that.\n\t\tif ( !url.match( URL_REGEXP ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If the URL represents a media, let's use it.\n\t\tif ( !mediaRegistry.hasMedia( url ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst mediaEmbedCommand = editor.commands.get( 'mediaEmbed' );\n\n\t\t// Do not anything if media element cannot be inserted at the current position (#47).\n\t\tif ( !mediaEmbedCommand.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Position won't be available in the `setTimeout` function so let's clone it.\n\t\tthis._positionToInsert = LivePosition.fromPosition( leftPosition );\n\n\t\t// This action mustn't be executed if undo was called between pasting and auto-embedding.\n\t\tthis._timeoutId = global.window.setTimeout( () => {\n\t\t\teditor.model.change( writer => {\n\t\t\t\tthis._timeoutId = null;\n\n\t\t\t\twriter.remove( urlRange );\n\n\t\t\t\tlet insertionPosition;\n\n\t\t\t\t// Check if position where the media element should be inserted is still valid.\n\t\t\t\t// Otherwise leave it as undefined to use document.selection - default behavior of model.insertContent().\n\t\t\t\tif ( this._positionToInsert.root.rootName !== '$graveyard' ) {\n\t\t\t\t\tinsertionPosition = this._positionToInsert;\n\t\t\t\t}\n\n\t\t\t\tinsertMedia( editor.model, url, insertionPosition );\n\n\t\t\t\tthis._positionToInsert.detach();\n\t\t\t\tthis._positionToInsert = null;\n\t\t\t} );\n\t\t}, 100 );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module media-embed/ui/mediaformview\n */\nimport View from '@ckeditor/ckeditor5-ui/src/view';\nimport ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport LabeledInputView from '@ckeditor/ckeditor5-ui/src/labeledinput/labeledinputview';\nimport InputTextView from '@ckeditor/ckeditor5-ui/src/inputtext/inputtextview';\nimport submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport checkIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/check.svg';\nimport cancelIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/cancel.svg';\nimport '../../theme/mediaform.css';\n/**\n * The media form view controller class.\n *\n * See {@link module:media-embed/ui/mediaformview~MediaFormView}.\n *\n * @extends module:ui/view~View\n */\nexport default class MediaFormView extends View {\n /**\n\t * @param {Array.<Function>} validators Form validators used by {@link #isValid}.\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t */\n constructor(validators, locale) {\n super(locale);\n const t = locale.t;\n /**\n\t\t * Tracks information about DOM focus in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n this.focusTracker = new FocusTracker();\n /**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n this.keystrokes = new KeystrokeHandler();\n /**\n\t\t * The URL input view.\n\t\t *\n\t\t * @member {module:ui/labeledinput/labeledinputview~LabeledInputView}\n\t\t */\n this.urlInputView = this._createUrlInput();\n /**\n\t\t * The Save button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n this.saveButtonView = this._createButton(t('cf'), checkIcon, 'ck-button-save');\n this.saveButtonView.type = 'submit';\n /**\n\t\t * The Cancel button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n this.cancelButtonView = this._createButton(t('cg'), cancelIcon, 'ck-button-cancel', 'cancel');\n /**\n\t\t * A collection of views that can be focused in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n this._focusables = new ViewCollection();\n /**\n\t\t * Helps cycling over {@link #_focusables} in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n this._focusCycler = new FocusCycler({\n focusables: this._focusables,\n focusTracker: this.focusTracker,\n keystrokeHandler: this.keystrokes,\n actions: {\n // Navigate form fields backwards using the Shift + Tab keystroke.\n focusPrevious: 'shift + tab',\n // Navigate form fields forwards using the Tab key.\n focusNext: 'tab'\n }\n });\n /**\n\t\t * An array of form validators used by {@link #isValid}.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Array.<Function>}\n\t\t */\n this._validators = validators;\n this.setTemplate({\n tag: 'form',\n attributes: {\n class: [\n 'ck',\n 'ck-media-form'\n ],\n tabindex: '-1'\n },\n children: [\n this.urlInputView,\n this.saveButtonView,\n this.cancelButtonView\n ]\n }); /**\n\t\t * The default info text for the {@link #urlInputView}.\n\t\t *\n\t\t * @private\n\t\t * @member {String} #_urlInputViewInfoDefault\n\t\t */\n /**\n\t\t * The info text with an additional tip for the {@link #urlInputView},\n\t\t * displayed when the input has some value.\n\t\t *\n\t\t * @private\n\t\t * @member {String} #_urlInputViewInfoTip\n\t\t */\n }\n /**\n\t * @inheritDoc\n\t */\n render() {\n super.render();\n submitHandler({ view: this });\n const childViews = [\n this.urlInputView,\n this.saveButtonView,\n this.cancelButtonView\n ];\n childViews.forEach(v => {\n // Register the view as focusable.\n this._focusables.add(v);\n // Register the view in the focus tracker.\n this.focusTracker.add(v.element);\n });\n // Start listening for the keystrokes coming from #element.\n this.keystrokes.listenTo(this.element);\n const stopPropagation = data => data.stopPropagation();\n // Since the form is in the dropdown panel which is a child of the toolbar, the toolbar's\n // keystroke handler would take over the key management in the URL input. We need to prevent\n // this ASAP. Otherwise, the basic caret movement using the arrow keys will be impossible.\n this.keystrokes.set('arrowright', stopPropagation);\n this.keystrokes.set('arrowleft', stopPropagation);\n this.keystrokes.set('arrowup', stopPropagation);\n this.keystrokes.set('arrowdown', stopPropagation);\n // Intercept the \"selectstart\" event, which is blocked by default because of the default behavior\n // of the DropdownView#panelView.\n // TODO: blocking \"selectstart\" in the #panelView should be configurable per–drop–down instance.\n this.listenTo(this.urlInputView.element, 'selectstart', (evt, domEvt) => {\n domEvt.stopPropagation();\n }, { priority: 'high' });\n }\n /**\n\t * Focuses the fist {@link #_focusables} in the form.\n\t */\n focus() {\n this._focusCycler.focusFirst();\n }\n /**\n\t * The native DOM `value` of the {@link #urlInputView} element.\n\t *\n\t * **Note**: Do not confuse it with the {@link module:ui/inputtext/inputtextview~InputTextView#value}\n\t * which works one way only and may not represent the actual state of the component in the DOM.\n\t *\n\t * @type {Number}\n\t */\n get url() {\n return this.urlInputView.inputView.element.value.trim();\n }\n /**\n\t * Sets the native DOM `value` of the {@link #urlInputView} element.\n\t *\n\t * **Note**: Do not confuse it with the {@link module:ui/inputtext/inputtextview~InputTextView#value}\n\t * which works one way only and may not represent the actual state of the component in the DOM.\n\t *\n\t * @param {String} url\n\t */\n set url(url) {\n this.urlInputView.inputView.element.value = url.trim();\n }\n /**\n\t * Validates the form and returns `false` when some fields are invalid.\n\t *\n\t * @returns {Boolean}\n\t */\n isValid() {\n this.resetFormStatus();\n for (const validator of this._validators) {\n const errorText = validator(this);\n // One error per field is enough.\n if (errorText) {\n // Apply updated error.\n this.urlInputView.errorText = errorText;\n return false;\n }\n }\n return true;\n }\n /**\n\t * Cleans up the supplementary error and information text of the {@link #urlInputView}\n\t * bringing them back to the state when the form has been displayed for the first time.\n\t *\n\t * See {@link #isValid}.\n\t */\n resetFormStatus() {\n this.urlInputView.errorText = null;\n this.urlInputView.infoText = this._urlInputViewInfoDefault;\n }\n /**\n\t * Creates a labeled input view.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledinput/labeledinputview~LabeledInputView} Labeled input view instance.\n\t */\n _createUrlInput() {\n const t = this.locale.t;\n const labeledInput = new LabeledInputView(this.locale, InputTextView);\n const inputView = labeledInput.inputView;\n this._urlInputViewInfoDefault = t('ch');\n this._urlInputViewInfoTip = t('ci');\n labeledInput.label = t('cj');\n labeledInput.infoText = this._urlInputViewInfoDefault;\n inputView.placeholder = 'https://example.com';\n inputView.on('input', () => {\n // Display the tip text only when there's some value. Otherwise fall back to the default info text.\n labeledInput.infoText = inputView.element.value ? this._urlInputViewInfoTip : this._urlInputViewInfoDefault;\n });\n return labeledInput;\n }\n /**\n\t * Creates a button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @param {String} className The additional button CSS class name.\n\t * @param {String} [eventName] An event name that the `ButtonView#execute` event will be delegated to.\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n _createButton(label, icon, className, eventName) {\n const button = new ButtonView(this.locale);\n button.set({\n label,\n icon,\n tooltip: true\n });\n button.extendTemplate({ attributes: { class: className } });\n if (eventName) {\n button.delegate('execute').to(this, eventName);\n }\n return button;\n }\n} /**\n * Fired when the form view is submitted (when one of the children triggered the submit event),\n * e.g. click on {@link #saveButtonView}.\n *\n * @event submit\n */\n /**\n * Fired when the form view is canceled, e.g. click on {@link #cancelButtonView}.\n *\n * @event cancel\n */","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module media-embed/mediaembedui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { createDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils';\nimport MediaFormView from './ui/mediaformview';\nimport MediaEmbedEditing from './mediaembedediting';\nimport mediaIcon from '../theme/assets/icons/media.svg';\n/**\n * The media embed UI plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class MediaEmbedUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get requires() {\n return [MediaEmbedEditing];\n }\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'MediaEmbedUI';\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const command = editor.commands.get('mediaEmbed');\n const registry = editor.plugins.get(MediaEmbedEditing).registry;\n /**\n\t\t * The form view displayed inside the drop-down.\n\t\t *\n\t\t * @member {module:media-embed/ui/mediaformview~MediaFormView}\n\t\t */\n this.form = new MediaFormView(getFormValidators(editor.t, registry), editor.locale);\n // Setup `imageUpload` button.\n editor.ui.componentFactory.add('mediaEmbed', locale => {\n const dropdown = createDropdown(locale);\n this._setUpDropdown(dropdown, this.form, command, editor);\n this._setUpForm(this.form, dropdown, command);\n return dropdown;\n });\n }\n _setUpDropdown(dropdown, form, command) {\n const editor = this.editor;\n const t = editor.t;\n const button = dropdown.buttonView;\n dropdown.bind('isEnabled').to(command);\n dropdown.panelView.children.add(form);\n button.set({\n label: t('al'),\n icon: mediaIcon,\n tooltip: true\n });\n // Note: Use the low priority to make sure the following listener starts working after the\n // default action of the drop-down is executed (i.e. the panel showed up). Otherwise, the\n // invisible form/input cannot be focused/selected.\n button.on('open', () => {\n // Make sure that each time the panel shows up, the URL field remains in sync with the value of\n // the command. If the user typed in the input, then canceled (`urlInputView#value` stays\n // unaltered) and re-opened it without changing the value of the media command (e.g. because they\n // didn't change the selection), they would see the old value instead of the actual value of the\n // command.\n form.url = command.value || '';\n form.urlInputView.select();\n form.focus();\n }, { priority: 'low' });\n dropdown.on('submit', () => {\n if (form.isValid()) {\n editor.execute('mediaEmbed', form.url);\n closeUI();\n }\n });\n dropdown.on('change:isOpen', () => form.resetFormStatus());\n dropdown.on('cancel', () => closeUI());\n function closeUI() {\n editor.editing.view.focus();\n dropdown.isOpen = false;\n }\n }\n _setUpForm(form, dropdown, command) {\n form.delegate('submit', 'cancel').to(dropdown);\n form.urlInputView.bind('value').to(command, 'value');\n // Form elements should be read-only when corresponding commands are disabled.\n form.urlInputView.bind('isReadOnly').to(command, 'isEnabled', value => !value);\n form.saveButtonView.bind('isEnabled').to(command);\n }\n}\nfunction getFormValidators(t, registry) {\n return [\n form => {\n if (!form.url.length) {\n return t('am');\n }\n },\n form => {\n if (!registry.hasMedia(form.url)) {\n return t('an');\n }\n }\n ];\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M18.68 2.53c.6 0 .59-.03.59.55v12.84c0 .59.01.56-.59.56H1.29c-.6 0-.59.03-.59-.56V3.08c0-.58-.01-.55.6-.55h17.38zM15.77 14.5v-10H4.2v10h11.57zM2 4v1h1V4H2zm0 2v1h1V6H2zm0 2v1h1V8H2zm0 2v1h1v-1H2zm0 2v1h1v-1H2zm0 2v1h1v-1H2zM17 4v1h1V4h-1zm0 2v1h1V6h-1zm0 2v1h1V8h-1zm0 2v1h1v-1h-1zm0 2v1h1v-1h-1zm0 2v1h1v-1h-1zM7.5 6.677a.4.4 0 01.593-.351l5.133 2.824a.4.4 0 010 .7l-5.133 2.824a.4.4 0 01-.593-.35V6.676z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 paste-from-office/filters/list\n */\n\nimport Element from '@ckeditor/ckeditor5-engine/src/view/element';\nimport Matcher from '@ckeditor/ckeditor5-engine/src/view/matcher';\nimport UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';\n\n/**\n * Transforms Word specific list-like elements to the semantic HTML lists.\n *\n * Lists in Word are represented by block elements with special attributes like:\n *\n *\t\t<p class=MsoListParagraphCxSpFirst style='mso-list:l1 level1 lfo1'>...</p> // Paragraph based list.\n *\t\t<h1 style='mso-list:l0 level1 lfo1'>...</h1> // Heading 1 based list.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment The view structure which to transform.\n * @param {String} stylesString Styles from which list-like elements styling will be extracted.\n */\nexport function transformListItemLikeElementsIntoLists( documentFragment, stylesString ) {\n\tif ( !documentFragment.childCount ) {\n\t\treturn;\n\t}\n\n\tconst writer = new UpcastWriter();\n\tconst itemLikeElements = findAllItemLikeElements( documentFragment, writer );\n\n\tif ( !itemLikeElements.length ) {\n\t\treturn;\n\t}\n\n\tlet currentList = null;\n\n\titemLikeElements.forEach( ( itemLikeElement, i ) => {\n\t\tif ( !currentList || isNewListNeeded( itemLikeElements[ i - 1 ], itemLikeElement ) ) {\n\t\t\tconst listStyle = detectListStyle( itemLikeElement, stylesString );\n\n\t\t\tcurrentList = insertNewEmptyList( listStyle, itemLikeElement.element, writer );\n\t\t}\n\n\t\tconst listItem = transformElementIntoListItem( itemLikeElement.element, writer );\n\n\t\twriter.appendChild( listItem, currentList );\n\t} );\n}\n\n/**\n * Removes paragraph wrapping content inside a list item.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment\n * @param {module:engine/view/upcastwriter~UpcastWriter} writer\n */\nexport function unwrapParagraphInListItem( documentFragment, writer ) {\n\tfor ( const value of writer.createRangeIn( documentFragment ) ) {\n\t\tconst element = value.item;\n\n\t\tif ( element.is( 'li' ) ) {\n\t\t\t// Google Docs allows on single paragraph inside LI.\n\t\t\tconst firstChild = element.getChild( 0 );\n\n\t\t\tif ( firstChild.is( 'p' ) ) {\n\t\t\t\twriter.unwrapElement( firstChild );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Finds all list-like elements in a given document fragment.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment\n// in which to look for list-like nodes.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {Array.<Object>} Array of found list-like items. Each item is an object containing:\n//\n//\t\t* {module:engine/src/view/element~Element} element List-like element.\n//\t\t* {Number} id List item id parsed from `mso-list` style (see `getListItemData()` function).\n//\t\t* {Number} order List item creation order parsed from `mso-list` style (see `getListItemData()` function).\n//\t\t* {Number} indent List item indentation level parsed from `mso-list` style (see `getListItemData()` function).\nfunction findAllItemLikeElements( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\t// Matcher for finding list-like elements.\n\tconst itemLikeElementsMatcher = new Matcher( {\n\t\tname: /^p|h\\d+$/,\n\t\tstyles: {\n\t\t\t'mso-list': /.*/\n\t\t}\n\t} );\n\n\tconst itemLikeElements = [];\n\n\tfor ( const value of range ) {\n\t\tif ( value.type === 'elementStart' && itemLikeElementsMatcher.match( value.item ) ) {\n\t\t\tconst itemData = getListItemData( value.item );\n\n\t\t\titemLikeElements.push( {\n\t\t\t\telement: value.item,\n\t\t\t\tid: itemData.id,\n\t\t\t\torder: itemData.order,\n\t\t\t\tindent: itemData.indent\n\t\t\t} );\n\t\t}\n\t}\n\n\treturn itemLikeElements;\n}\n\n// Extracts list item style from the provided CSS.\n//\n// List item style is extracted from CSS stylesheet. Each list with its specific style attribute\n// value (`mso-list:l1 level1 lfo1`) has its dedicated properties in a CSS stylesheet defined with a selector like:\n//\n// \t\t@list l1:level1 { ... }\n//\n// It contains `mso-level-number-format` property which defines list numbering/bullet style. If this property\n// is not defined it means default `decimal` numbering.\n//\n// Here CSS string representation is used as `mso-level-number-format` property is an invalid CSS property\n// and will be removed during CSS parsing.\n//\n// @param {Object} listLikeItem List-like item for which list style will be searched for. Usually\n// a result of `findAllItemLikeElements()` function.\n// @param {String} stylesString CSS stylesheet.\n// @returns {Object} result\n// @returns {String} result.type List type, could be `ul` or `ol`.\n// @returns {String} result.style List style, for example: `decimal`, `lower-roman`, etc. It is extracted\n// directly from Word stylesheet without further processing and may be not compatible\n// with CSS `list-style-type` property accepted values.\nfunction detectListStyle( listLikeItem, stylesString ) {\n\tconst listStyleRegexp = new RegExp( `@list l${ listLikeItem.id }:level${ listLikeItem.indent }\\\\s*({[^}]*)`, 'gi' );\n\tconst listStyleTypeRegex = /mso-level-number-format:([^;]*);/gi;\n\n\tconst listStyleMatch = listStyleRegexp.exec( stylesString );\n\n\tlet listStyleType = 'decimal'; // Decimal is default one.\n\tif ( listStyleMatch && listStyleMatch[ 1 ] ) {\n\t\tconst listStyleTypeMatch = listStyleTypeRegex.exec( listStyleMatch[ 1 ] );\n\n\t\tif ( listStyleTypeMatch && listStyleTypeMatch[ 1 ] ) {\n\t\t\tlistStyleType = listStyleTypeMatch[ 1 ].trim();\n\t\t}\n\t}\n\n\treturn {\n\t\ttype: listStyleType !== 'bullet' && listStyleType !== 'image' ? 'ol' : 'ul',\n\t\tstyle: listStyleType\n\t};\n}\n\n// Creates empty list of a given type and inserts it after a specified element.\n//\n// @param {Object} listStyle List style object which determines the type of newly created list.\n// Usually a result of `detectListStyle()` function.\n// @param {module:engine/view/element~Element} element Element before which list is inserted.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {module:engine/view/element~Element} Newly created list element.\nfunction insertNewEmptyList( listStyle, element, writer ) {\n\tconst list = new Element( listStyle.type );\n\tconst position = element.parent.getChildIndex( element );\n\n\twriter.insertChild( position, list, element.parent );\n\n\treturn list;\n}\n\n// Transforms given element into a semantic list item. As the function operates on a provided\n// {module:engine/src/view/element~Element element} it will modify the view structure to which this element belongs.\n//\n// @param {module:engine/view/element~Element} element Element which will be transformed into list item.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {module:engine/view/element~Element} New element to which the given one was transformed. It is\n// inserted in place of the old element (the reference to the old element is lost due to renaming).\nfunction transformElementIntoListItem( element, writer ) {\n\tremoveBulletElement( element, writer );\n\n\treturn writer.rename( 'li', element );\n}\n\n// Extracts list item information from Word specific list-like element style:\n//\n//\t\t`style=\"mso-list:l1 level1 lfo1\"`\n//\n// where:\n//\n//\t\t* `l1` is a list id (however it does not mean this is a continuous list - see #43),\n//\t\t* `level1` is a list item indentation level,\n//\t\t* `lfo1` is a list insertion order in a document.\n//\n// @param {module:engine/view/element~Element} element Element from which style data is extracted.\n// @returns {Object} result\n// @returns {Number} result.id Parent list id.\n// @returns {Number} result.order List item creation order.\n// @returns {Number} result.indent List item indentation level.\nfunction getListItemData( element ) {\n\tconst data = {};\n\tconst listStyle = element.getStyle( 'mso-list' );\n\n\tif ( listStyle ) {\n\t\tconst idMatch = listStyle.match( /(^|\\s+)l(\\d+)/i );\n\t\tconst orderMatch = listStyle.match( /\\s*lfo(\\d+)/i );\n\t\tconst indentMatch = listStyle.match( /\\s*level(\\d+)/i );\n\n\t\tif ( idMatch && orderMatch && indentMatch ) {\n\t\t\tdata.id = idMatch[ 2 ];\n\t\t\tdata.order = orderMatch[ 1 ];\n\t\t\tdata.indent = indentMatch[ 1 ];\n\t\t}\n\t}\n\n\treturn data;\n}\n\n// Removes span with a numbering/bullet from a given element.\n//\n// @param {module:engine/view/element~Element} element\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction removeBulletElement( element, writer ) {\n\t// Matcher for finding `span` elements holding lists numbering/bullets.\n\tconst bulletMatcher = new Matcher( {\n\t\tname: 'span',\n\t\tstyles: {\n\t\t\t'mso-list': 'Ignore'\n\t\t}\n\t} );\n\n\tconst range = writer.createRangeIn( element );\n\n\tfor ( const value of range ) {\n\t\tif ( value.type === 'elementStart' && bulletMatcher.match( value.item ) ) {\n\t\t\twriter.remove( value.item );\n\t\t}\n\t}\n}\n\n// Whether previous and current item belongs to the same list. It is determined based on `item.id`\n// (extracted from `mso-list` style, see #getListItemData) and previous sibling of the current item.\n//\n// @param {Object} previousItem\n// @param {Object} currentItem\n// @returns {Boolean}\nfunction isNewListNeeded( previousItem, currentItem ) {\n\tif ( previousItem.id !== currentItem.id ) {\n\t\treturn true;\n\t}\n\n\tconst previousSibling = currentItem.element.previousSibling;\n\n\tif ( !previousSibling ) {\n\t\treturn true;\n\t}\n\n\t// Even with the same id the list does not have to be continuous (#43).\n\treturn !isList( previousSibling );\n}\n\nfunction isList( element ) {\n\treturn element.is( 'ol' ) || element.is( 'ul' );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 paste-from-office/normalizers/googledocsnormalizer\n */\n\nimport removeBoldWrapper from '../filters/removeboldwrapper';\nimport { unwrapParagraphInListItem } from '../filters/list';\nimport UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';\n\nconst googleDocsMatch = /id=(\"|')docs-internal-guid-[-0-9a-f]+(\"|')/i;\n\n/**\n * Normalizer for the content pasted from Google Docs.\n *\n * @implements module:paste-from-office/normalizer~Normalizer\n */\nexport default class GoogleDocsNormalizer {\n\t/**\n\t * @inheritDoc\n\t */\n\tisActive( htmlString ) {\n\t\treturn googleDocsMatch.test( htmlString );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute( data ) {\n\t\tconst writer = new UpcastWriter();\n\n\t\tremoveBoldWrapper( data.content, writer );\n\t\tunwrapParagraphInListItem( data.content, writer );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 paste-from-office/filters/removeboldwrapper\n */\n\n/**\n * Removes `<b>` tag wrapper added by Google Docs to a copied content.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment element `data.content` obtained from clipboard\n * @param {module:engine/view/upcastwriter~UpcastWriter} writer\n */\nexport default function removeBoldWrapper( documentFragment, writer ) {\n\tfor ( const child of documentFragment.getChildren() ) {\n\t\tif ( child.is( 'b' ) && child.getStyle( 'font-weight' ) === 'normal' ) {\n\t\t\tconst childIndex = documentFragment.getChildIndex( child );\n\n\t\t\twriter.remove( child );\n\t\t\twriter.insertChild( childIndex, child.getChildren(), documentFragment );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 paste-from-office/filters/space\n */\n\n/**\n * Replaces last space preceding elements closing tag with ` `. Such operation prevents spaces from being removed\n * during further DOM/View processing (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).\n * This method also takes into account Word specific `<o:p></o:p>` empty tags.\n * Additionally multiline sequences of spaces and new lines between tags are removed (see #39 and #40).\n *\n * @param {String} htmlString HTML string in which spacing should be normalized.\n * @returns {String} Input HTML with spaces normalized.\n */\nexport function normalizeSpacing( htmlString ) {\n\t// Run normalizeSafariSpaceSpans() two times to cover nested spans.\n\treturn normalizeSafariSpaceSpans( normalizeSafariSpaceSpans( htmlString ) )\n\t\t// Remove all \\r\\n from \"spacerun spans\" so the last replace line doesn't strip all whitespaces.\n\t\t.replace( /(<span\\s+style=['\"]mso-spacerun:yes['\"]>[\\s]*?)[\\r\\n]+(\\s*<\\/span>)/g, '$1$2' )\n\t\t.replace( /<span\\s+style=['\"]mso-spacerun:yes['\"]><\\/span>/g, '' )\n\t\t.replace( / <\\//g, '\\u00A0</' )\n\t\t.replace( / <o:p><\\/o:p>/g, '\\u00A0<o:p></o:p>' )\n\t\t// Remove <o:p> block filler from empty paragraph. Safari uses \\u00A0 instead of .\n\t\t.replace( /<o:p>( |\\u00A0)<\\/o:p>/g, '' )\n\t\t// Remove all whitespaces when they contain any \\r or \\n.\n\t\t.replace( />(\\s*[\\r\\n]\\s*)</g, '><' );\n}\n\n/**\n * Normalizes spacing in special Word `spacerun spans` (`<span style='mso-spacerun:yes'>\\s+</span>`) by replacing\n * all spaces with ` ` pairs. This prevents spaces from being removed during further DOM/View processing\n * (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).\n *\n * @param {Document} htmlDocument Native `Document` object in which spacing should be normalized.\n */\nexport function normalizeSpacerunSpans( htmlDocument ) {\n\thtmlDocument.querySelectorAll( 'span[style*=spacerun]' ).forEach( el => {\n\t\t// Use `el.childNodes[ 0 ].data.length` instead of `el.innerText.length`. For `el.innerText.length` which\n\t\t// contains spaces mixed with ` ` Edge browser returns incorrect length.\n\t\tconst innerTextLength = ( el.childNodes &&\n\t\t\tel.childNodes[ 0 ] &&\n\t\t\tel.childNodes[ 0 ].data &&\n\t\t\tel.childNodes[ 0 ].data.length ) || 0;\n\n\t\tel.innerHTML = Array( innerTextLength + 1 ).join( '\\u00A0 ' ).substr( 0, innerTextLength );\n\t} );\n}\n\n// Normalizes specific spacing generated by Safari when content pasted from Word (`<span class=\"Apple-converted-space\"> </span>`)\n// by replacing all spaces sequences longer than 1 space with ` ` pairs. This prevents spaces from being removed during\n// further DOM/View processing (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).\n//\n// This function is similar to {@link module:clipboard/utils/normalizeclipboarddata normalizeClipboardData util} but uses\n// regular spaces / sequence for replacement.\n//\n// @param {String} htmlString HTML string in which spacing should be normalized\n// @returns {String} Input HTML with spaces normalized.\nfunction normalizeSafariSpaceSpans( htmlString ) {\n\treturn htmlString.replace( /<span(?: class=\"Apple-converted-space\"|)>(\\s+)<\\/span>/g, ( fullMatch, spaces ) => {\n\t\treturn spaces.length === 1 ? ' ' : Array( spaces.length + 1 ).join( '\\u00A0 ' ).substr( 0, spaces.length );\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 paste-from-office/filters/parse\n */\n\n/* globals DOMParser */\n\nimport DomConverter from '@ckeditor/ckeditor5-engine/src/view/domconverter';\n\nimport { normalizeSpacing, normalizeSpacerunSpans } from './space';\n\n/**\n * Parses provided HTML extracting contents of `<body>` and `<style>` tags.\n *\n * @param {String} htmlString HTML string to be parsed.\n * @returns {Object} result\n * @returns {module:engine/view/documentfragment~DocumentFragment} result.body Parsed body\n * content as a traversable structure.\n * @returns {String} result.bodyString Entire body content as a string.\n * @returns {Array.<CSSStyleSheet>} result.styles Array of native `CSSStyleSheet` objects, each representing\n * separate `style` tag from the source HTML.\n * @returns {String} result.stylesString All `style` tags contents combined in the order of occurrence into one string.\n */\nexport function parseHtml( htmlString ) {\n\tconst domParser = new DOMParser();\n\n\t// Remove Word specific \"if comments\" so content inside is not omitted by the parser.\n\thtmlString = htmlString.replace( /<!--\\[if gte vml 1]>/g, '' );\n\n\tconst normalizedHtml = normalizeSpacing( cleanContentAfterBody( htmlString ) );\n\n\t// Parse htmlString as native Document object.\n\tconst htmlDocument = domParser.parseFromString( normalizedHtml, 'text/html' );\n\n\tnormalizeSpacerunSpans( htmlDocument );\n\n\t// Get `innerHTML` first as transforming to View modifies the source document.\n\tconst bodyString = htmlDocument.body.innerHTML;\n\n\t// Transform document.body to View.\n\tconst bodyView = documentToView( htmlDocument );\n\n\t// Extract stylesheets.\n\tconst stylesObject = extractStyles( htmlDocument );\n\n\treturn {\n\t\tbody: bodyView,\n\t\tbodyString,\n\t\tstyles: stylesObject.styles,\n\t\tstylesString: stylesObject.stylesString\n\t};\n}\n\n// Transforms native `Document` object into {@link module:engine/view/documentfragment~DocumentFragment}.\n//\n// @param {Document} htmlDocument Native `Document` object to be transformed.\n// @returns {module:engine/view/documentfragment~DocumentFragment}\nfunction documentToView( htmlDocument ) {\n\tconst domConverter = new DomConverter( { blockFillerMode: 'nbsp' } );\n\tconst fragment = htmlDocument.createDocumentFragment();\n\tconst nodes = htmlDocument.body.childNodes;\n\n\twhile ( nodes.length > 0 ) {\n\t\tfragment.appendChild( nodes[ 0 ] );\n\t}\n\n\treturn domConverter.domToView( fragment );\n}\n\n// Extracts both `CSSStyleSheet` and string representation from all `style` elements available in a provided `htmlDocument`.\n//\n// @param {Document} htmlDocument Native `Document` object from which styles will be extracted.\n// @returns {Object} result\n// @returns {Array.<CSSStyleSheet>} result.styles Array of native `CSSStyleSheet` object, each representing\n// separate `style` tag from the source object.\n// @returns {String} result.stylesString All `style` tags contents combined in the order of occurrence as one string.\nfunction extractStyles( htmlDocument ) {\n\tconst styles = [];\n\tconst stylesString = [];\n\tconst styleTags = Array.from( htmlDocument.getElementsByTagName( 'style' ) );\n\n\tfor ( const style of styleTags ) {\n\t\tif ( style.sheet && style.sheet.cssRules && style.sheet.cssRules.length ) {\n\t\t\tstyles.push( style.sheet );\n\t\t\tstylesString.push( style.innerHTML );\n\t\t}\n\t}\n\n\treturn {\n\t\tstyles,\n\t\tstylesString: stylesString.join( ' ' )\n\t};\n}\n\n// Removes leftover content from between closing </body> and closing </html> tag:\n//\n// \t\t<html><body><p>Foo Bar</p></body><span>Fo</span></html> -> <html><body><p>Foo Bar</p></body></html>\n//\n// This function is used as specific browsers (Edge) add some random content after `body` tag when pasting from Word.\n// @param {String} htmlString The HTML string to be cleaned.\n// @returns {String} The HTML string with leftover content removed.\nfunction cleanContentAfterBody( htmlString ) {\n\tconst regexp = /<\\/body>(.*?)(<\\/html>|$)/;\n\tconst match = htmlString.match( regexp );\n\n\tif ( match && match[ 1 ] ) {\n\t\thtmlString = htmlString.slice( 0, match.index ) + htmlString.slice( match.index ).replace( match[ 1 ], '' );\n\t}\n\n\treturn htmlString;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 paste-from-office/filters/image\n */\n\n/* globals btoa */\n\nimport ViewMatcher from '@ckeditor/ckeditor5-engine/src/view/matcher';\nimport UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';\n\n/**\n * Replaces source attribute of all `<img>` elements representing regular\n * images (not the Word shapes) with inlined base64 image representation extracted from RTF or Blob data.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment on which transform images.\n * @param {String} rtfData The RTF data from which images representation will be used.\n */\nexport function replaceImagesSourceWithBase64( documentFragment, rtfData ) {\n\tif ( !documentFragment.childCount ) {\n\t\treturn;\n\t}\n\n\tconst upcastWriter = new UpcastWriter();\n\tconst shapesIds = findAllShapesIds( documentFragment, upcastWriter );\n\n\tremoveAllImgElementsRepresentingShapes( shapesIds, documentFragment, upcastWriter );\n\tremoveAllShapeElements( documentFragment, upcastWriter );\n\n\tconst images = findAllImageElementsWithLocalSource( documentFragment, upcastWriter );\n\n\tif ( images.length ) {\n\t\treplaceImagesFileSourceWithInlineRepresentation( images, extractImageDataFromRtf( rtfData ), upcastWriter );\n\t}\n}\n\n/**\n * Converts given HEX string to base64 representation.\n *\n * @protected\n * @param {String} hexString The HEX string to be converted.\n * @returns {String} Base64 representation of a given HEX string.\n */\nexport function _convertHexToBase64( hexString ) {\n\treturn btoa( hexString.match( /\\w{2}/g ).map( char => {\n\t\treturn String.fromCharCode( parseInt( char, 16 ) );\n\t} ).join( '' ) );\n}\n\n// Finds all shapes (`<v:*>...</v:*>`) ids. Shapes can represent images (canvas)\n// or Word shapes (which does not have RTF or Blob representation).\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment\n// from which to extract shape ids.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {Array.<String>} Array of shape ids.\nfunction findAllShapesIds( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst shapeElementsMatcher = new ViewMatcher( {\n\t\tname: /v:(.+)/\n\t} );\n\n\tconst shapesIds = [];\n\n\tfor ( const value of range ) {\n\t\tconst el = value.item;\n\t\tconst prevSiblingName = el.previousSibling && el.previousSibling.name || null;\n\n\t\t// If shape element have 'o:gfxdata' attribute and is not directly before `<v:shapetype>` element it means it represent Word shape.\n\t\tif ( shapeElementsMatcher.match( el ) && el.getAttribute( 'o:gfxdata' ) && prevSiblingName !== 'v:shapetype' ) {\n\t\t\tshapesIds.push( value.item.getAttribute( 'id' ) );\n\t\t}\n\t}\n\n\treturn shapesIds;\n}\n\n// Removes all `<img>` elements which represents Word shapes and not regular images.\n//\n// @param {Array.<String>} shapesIds Shape ids which will be checked against `<img>` elements.\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment from which to remove `<img>` elements.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction removeAllImgElementsRepresentingShapes( shapesIds, documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst imageElementsMatcher = new ViewMatcher( {\n\t\tname: 'img'\n\t} );\n\n\tconst imgs = [];\n\n\tfor ( const value of range ) {\n\t\tif ( imageElementsMatcher.match( value.item ) ) {\n\t\t\tconst el = value.item;\n\t\t\tconst shapes = el.getAttribute( 'v:shapes' ) ? el.getAttribute( 'v:shapes' ).split( ' ' ) : [];\n\n\t\t\tif ( shapes.length && shapes.every( shape => shapesIds.indexOf( shape ) > -1 ) ) {\n\t\t\t\timgs.push( el );\n\t\t\t// Shapes may also have empty source while content is paste in some browsers (Safari).\n\t\t\t} else if ( !el.getAttribute( 'src' ) ) {\n\t\t\t\timgs.push( el );\n\t\t\t}\n\t\t}\n\t}\n\n\tfor ( const img of imgs ) {\n\t\twriter.remove( img );\n\t}\n}\n\n// Removes all shape elements (`<v:*>...</v:*>`) so they do not pollute the output structure.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment from which to remove shape elements.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction removeAllShapeElements( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst shapeElementsMatcher = new ViewMatcher( {\n\t\tname: /v:(.+)/\n\t} );\n\n\tconst shapes = [];\n\n\tfor ( const value of range ) {\n\t\tif ( shapeElementsMatcher.match( value.item ) ) {\n\t\t\tshapes.push( value.item );\n\t\t}\n\t}\n\n\tfor ( const shape of shapes ) {\n\t\twriter.remove( shape );\n\t}\n}\n\n// Finds all `<img>` elements in a given document fragment which have source pointing to local `file://` resource.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment in which to look for `<img>` elements.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {Object} result All found images grouped by source type.\n// @returns {Array.<module:engine/view/element~Element>} result.file Array of found `<img>` elements with `file://` source.\n// @returns {Array.<module:engine/view/element~Element>} result.blob Array of found `<img>` elements with `blob:` source.\nfunction findAllImageElementsWithLocalSource( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst imageElementsMatcher = new ViewMatcher( {\n\t\tname: 'img'\n\t} );\n\n\tconst imgs = [];\n\n\tfor ( const value of range ) {\n\t\tif ( imageElementsMatcher.match( value.item ) ) {\n\t\t\tif ( value.item.getAttribute( 'src' ).startsWith( 'file://' ) ) {\n\t\t\t\timgs.push( value.item );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn imgs;\n}\n\n// Extracts all images HEX representations from a given RTF data.\n//\n// @param {String} rtfData The RTF data from which to extract images HEX representation.\n// @returns {Array.<Object>} Array of found HEX representations. Each array item is an object containing:\n//\n// \t\t* {String} hex Image representation in HEX format.\n// \t\t* {string} type Type of image, `image/png` or `image/jpeg`.\nfunction extractImageDataFromRtf( rtfData ) {\n\tif ( !rtfData ) {\n\t\treturn [];\n\t}\n\n\tconst regexPictureHeader = /{\\\\pict[\\s\\S]+?\\\\bliptag-?\\d+(\\\\blipupi-?\\d+)?({\\\\\\*\\\\blipuid\\s?[\\da-fA-F]+)?[\\s}]*?/;\n\tconst regexPicture = new RegExp( '(?:(' + regexPictureHeader.source + '))([\\\\da-fA-F\\\\s]+)\\\\}', 'g' );\n\tconst images = rtfData.match( regexPicture );\n\tconst result = [];\n\n\tif ( images ) {\n\t\tfor ( const image of images ) {\n\t\t\tlet imageType = false;\n\n\t\t\tif ( image.includes( '\\\\pngblip' ) ) {\n\t\t\t\timageType = 'image/png';\n\t\t\t} else if ( image.includes( '\\\\jpegblip' ) ) {\n\t\t\t\timageType = 'image/jpeg';\n\t\t\t}\n\n\t\t\tif ( imageType ) {\n\t\t\t\tresult.push( {\n\t\t\t\t\thex: image.replace( regexPictureHeader, '' ).replace( /[^\\da-fA-F]/g, '' ),\n\t\t\t\t\ttype: imageType\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n// Replaces `src` attribute value of all given images with the corresponding base64 image representation.\n//\n// @param {Array.<module:engine/view/element~Element>} imageElements Array of image elements which will have its source replaced.\n// @param {Array.<Object>} imagesHexSources Array of images hex sources (usually the result of `extractImageDataFromRtf()` function).\n// The array should be the same length as `imageElements` parameter.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction replaceImagesFileSourceWithInlineRepresentation( imageElements, imagesHexSources, writer ) {\n\t// Assume there is an equal amount of image elements and images HEX sources so they can be matched accordingly based on existing order.\n\tif ( imageElements.length === imagesHexSources.length ) {\n\t\tfor ( let i = 0; i < imageElements.length; i++ ) {\n\t\t\tconst newSrc = `data:${ imagesHexSources[ i ].type };base64,${ _convertHexToBase64( imagesHexSources[ i ].hex ) }`;\n\t\t\twriter.setAttribute( 'src', newSrc, imageElements[ i ] );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 paste-from-office/normalizers/mswordnormalizer\n */\n\nimport { parseHtml } from '../filters/parse';\nimport { transformListItemLikeElementsIntoLists } from '../filters/list';\nimport { replaceImagesSourceWithBase64 } from '../filters/image';\n\nconst msWordMatch1 = /<meta\\s*name=\"?generator\"?\\s*content=\"?microsoft\\s*word\\s*\\d+\"?\\/?>/i;\nconst msWordMatch2 = /xmlns:o=\"urn:schemas-microsoft-com/i;\n\n/**\n * Normalizer for the content pasted from Microsoft Word.\n *\n * @implements module:paste-from-office/normalizer~Normalizer\n */\nexport default class MSWordNormalizer {\n\t/**\n\t * @inheritDoc\n\t */\n\tisActive( htmlString ) {\n\t\treturn msWordMatch1.test( htmlString ) || msWordMatch2.test( htmlString );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute( data ) {\n\t\tconst { body, stylesString } = parseHtml( data.dataTransfer.getData( 'text/html' ) );\n\n\t\ttransformListItemLikeElementsIntoLists( body, stylesString );\n\t\treplaceImagesSourceWithBase64( body, data.dataTransfer.getData( 'text/rtf' ) );\n\n\t\tdata.content = body;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/commands/utils\n */\n\nimport { isObject } from 'lodash-es';\n\n/**\n * Returns the parent element of the given name. Returns undefined if the position is not inside the desired parent.\n *\n * @param {String} parentName The name of the parent element to find.\n * @param {module:engine/model/position~Position|module:engine/model/position~Position} position The position to start searching.\n * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n */\nexport function findAncestor( parentName, position ) {\n\tlet parent = position.parent;\n\n\twhile ( parent ) {\n\t\tif ( parent.name === parentName ) {\n\t\t\treturn parent;\n\t\t}\n\n\t\tparent = parent.parent;\n\t}\n}\n\n/**\n * A common method to update the numeric value. If a value is the default one, it will be unset.\n *\n * @param {String} key An attribute key.\n * @param {*} value The new attribute value.\n * @param {module:engine/model/item~Item} item A model item on which the attribute will be set.\n * @param {module:engine/model/writer~Writer} writer\n * @param {*} defaultValue The default attribute value. If a value is lower or equal, it will be unset.\n */\nexport function updateNumericAttribute( key, value, item, writer, defaultValue = 1 ) {\n\tif ( value > defaultValue ) {\n\t\twriter.setAttribute( key, value, item );\n\t} else {\n\t\twriter.removeAttribute( key, item );\n\t}\n}\n\n/**\n * A common method to create an empty table cell. It creates a proper model structure as a table cell must have at least one block inside.\n *\n * @param {module:engine/model/writer~Writer} writer The model writer.\n * @param {module:engine/model/position~Position} insertPosition The position at which the table cell should be inserted.\n * @param {Object} attributes The element attributes.\n */\nexport function createEmptyTableCell( writer, insertPosition, attributes = {} ) {\n\tconst tableCell = writer.createElement( 'tableCell', attributes );\n\twriter.insertElement( 'paragraph', tableCell );\n\twriter.insert( tableCell, insertPosition );\n}\n\n/**\n * Returns a string if all four values of box sides are equal.\n *\n * If a string is passed, it is treated as a single value (pass-through).\n *\n *\t\t// Returns 'foo':\n *\t\tgetSingleValue( { top: 'foo', right: 'foo', bottom: 'foo', left: 'foo' } );\n *\t\tgetSingleValue( 'foo' );\n *\n *\t\t// Returns undefined:\n *\t\tgetSingleValue( { top: 'foo', right: 'foo', bottom: 'bar', left: 'foo' } );\n *\t\tgetSingleValue( { top: 'foo', right: 'foo' } );\n *\n * @param objectOrString\n * @returns {module:engine/view/stylesmap~BoxSides|String}\n */\nexport function getSingleValue( objectOrString ) {\n\tif ( !objectOrString || !isObject( objectOrString ) ) {\n\t\treturn objectOrString;\n\t}\n\n\tconst { top, right, bottom, left } = objectOrString;\n\n\tif ( top == right && right == bottom && bottom == left ) {\n\t\treturn top;\n\t}\n}\n\n/**\n * Adds a unit to a value if the value is a number or a string representing a number.\n *\n * **Note**: It does nothing to non-numeric values.\n *\n *\t\tgetSingleValue( 25, 'px' );\t\t// '25px'\n *\t\tgetSingleValue( 25, 'em' );\t\t// '25em'\n *\t\tgetSingleValue( '25em', 'px' );\t// '25em'\n *\t\tgetSingleValue( 'foo', 'px' );\t// 'foo'\n *\n * @param {*} value\n * @param {String} defaultUnit A default unit added to a numeric value.\n * @returns {String|*}\n */\nexport function addDefaultUnitToNumericValue( value, defaultUnit ) {\n\tconst numericValue = parseFloat( value );\n\n\tif ( Number.isNaN( numericValue ) ) {\n\t\treturn value;\n\t}\n\n\tif ( String( numericValue ) !== String( value ) ) {\n\t\treturn value;\n\t}\n\n\treturn `${ numericValue }${ defaultUnit }`;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/converters/upcasttable\n */\n\nimport { createEmptyTableCell } from '../commands/utils';\n\n/**\n * View table element to model table element conversion helper.\n *\n * This conversion helper converts the table element as well as table rows.\n *\n * @returns {Function} Conversion helper.\n */\nexport default function upcastTable() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element:table', ( evt, data, conversionApi ) => {\n\t\t\tconst viewTable = data.viewItem;\n\n\t\t\t// When element was already consumed then skip it.\n\t\t\tif ( !conversionApi.consumable.test( viewTable, { name: true } ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { rows, headingRows, headingColumns } = scanTable( viewTable );\n\n\t\t\t// Only set attributes if values is greater then 0.\n\t\t\tconst attributes = {};\n\n\t\t\tif ( headingColumns ) {\n\t\t\t\tattributes.headingColumns = headingColumns;\n\t\t\t}\n\n\t\t\tif ( headingRows ) {\n\t\t\t\tattributes.headingRows = headingRows;\n\t\t\t}\n\n\t\t\tconst table = conversionApi.writer.createElement( 'table', attributes );\n\n\t\t\t// Insert element on allowed position.\n\t\t\tconst splitResult = conversionApi.splitToAllowedParent( table, data.modelCursor );\n\n\t\t\t// When there is no split result it means that we can't insert element to model tree, so let's skip it.\n\t\t\tif ( !splitResult ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconversionApi.writer.insert( table, splitResult.position );\n\t\t\tconversionApi.consumable.consume( viewTable, { name: true } );\n\n\t\t\tif ( rows.length ) {\n\t\t\t\t// Upcast table rows in proper order (heading rows first).\n\t\t\t\trows.forEach( row => conversionApi.convertItem( row, conversionApi.writer.createPositionAt( table, 'end' ) ) );\n\t\t\t} else {\n\t\t\t\t// Create one row and one table cell for empty table.\n\t\t\t\tconst row = conversionApi.writer.createElement( 'tableRow' );\n\t\t\t\tconversionApi.writer.insert( row, conversionApi.writer.createPositionAt( table, 'end' ) );\n\n\t\t\t\tcreateEmptyTableCell( conversionApi.writer, conversionApi.writer.createPositionAt( row, 'end' ) );\n\t\t\t}\n\n\t\t\t// Set conversion result range.\n\t\t\tdata.modelRange = conversionApi.writer.createRange(\n\t\t\t\t// Range should start before inserted element\n\t\t\t\tconversionApi.writer.createPositionBefore( table ),\n\t\t\t\t// Should end after but we need to take into consideration that children could split our\n\t\t\t\t// element, so we need to move range after parent of the last converted child.\n\t\t\t\t// before: <allowed>[]</allowed>\n\t\t\t\t// after: <allowed>[<converted><child></child></converted><child></child><converted>]</converted></allowed>\n\t\t\t\tconversionApi.writer.createPositionAfter( table )\n\t\t\t);\n\n\t\t\t// Now we need to check where the modelCursor should be.\n\t\t\t// If we had to split parent to insert our element then we want to continue conversion inside split parent.\n\t\t\t//\n\t\t\t// before: <allowed><notAllowed>[]</notAllowed></allowed>\n\t\t\t// after: <allowed><notAllowed></notAllowed><converted></converted><notAllowed>[]</notAllowed></allowed>\n\t\t\tif ( splitResult.cursorParent ) {\n\t\t\t\tdata.modelCursor = conversionApi.writer.createPositionAt( splitResult.cursorParent, 0 );\n\n\t\t\t\t// Otherwise just continue after inserted element.\n\t\t\t} else {\n\t\t\t\tdata.modelCursor = data.modelRange.end;\n\t\t\t}\n\t\t} );\n\t};\n}\n\nexport function upcastTableCell( elementName ) {\n\treturn dispatcher => {\n\t\tdispatcher.on( `element:${ elementName }`, ( evt, data, conversionApi ) => {\n\t\t\tconst viewTableCell = data.viewItem;\n\n\t\t\t// When element was already consumed then skip it.\n\t\t\tif ( !conversionApi.consumable.test( viewTableCell, { name: true } ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst tableCell = conversionApi.writer.createElement( 'tableCell' );\n\n\t\t\t// Insert element on allowed position.\n\t\t\tconst splitResult = conversionApi.splitToAllowedParent( tableCell, data.modelCursor );\n\n\t\t\t// When there is no split result it means that we can't insert element to model tree, so let's skip it.\n\t\t\tif ( !splitResult ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconversionApi.writer.insert( tableCell, splitResult.position );\n\t\t\tconversionApi.consumable.consume( viewTableCell, { name: true } );\n\n\t\t\tconst modelCursor = conversionApi.writer.createPositionAt( tableCell, 0 );\n\t\t\tconversionApi.convertChildren( viewTableCell, modelCursor );\n\n\t\t\t// Ensure a paragraph in the model for empty table cells.\n\t\t\tif ( !tableCell.childCount ) {\n\t\t\t\tconversionApi.writer.insertElement( 'paragraph', modelCursor );\n\t\t\t}\n\n\t\t\t// Set conversion result range.\n\t\t\tdata.modelRange = conversionApi.writer.createRange(\n\t\t\t\t// Range should start before inserted element\n\t\t\t\tconversionApi.writer.createPositionBefore( tableCell ),\n\t\t\t\t// Should end after but we need to take into consideration that children could split our\n\t\t\t\t// element, so we need to move range after parent of the last converted child.\n\t\t\t\t// before: <allowed>[]</allowed>\n\t\t\t\t// after: <allowed>[<converted><child></child></converted><child></child><converted>]</converted></allowed>\n\t\t\t\tconversionApi.writer.createPositionAfter( tableCell )\n\t\t\t);\n\n\t\t\t// Continue after inserted element.\n\t\t\tdata.modelCursor = data.modelRange.end;\n\t\t} );\n\t};\n}\n\n// Scans table rows and extracts required metadata from the table:\n//\n// headingRows - The number of rows that go as table headers.\n// headingColumns - The maximum number of row headings.\n// rows - Sorted `<tr>` elements as they should go into the model - ie. if `<thead>` is inserted after `<tbody>` in the view.\n//\n// @param {module:engine/view/element~Element} viewTable\n// @returns {{headingRows, headingColumns, rows}}\nfunction scanTable( viewTable ) {\n\tconst tableMeta = {\n\t\theadingRows: 0,\n\t\theadingColumns: 0\n\t};\n\n\t// The `<tbody>` and `<thead>` sections in the DOM do not have to be in order `<thead>` -> `<tbody>` and there might be more than one\n\t// of them.\n\t// As the model does not have these sections, rows from different sections must be sorted.\n\t// For example, below is a valid HTML table:\n\t//\n\t//\t\t<table>\n\t//\t\t\t<tbody><tr><td>2</td></tr></tbody>\n\t//\t\t\t<thead><tr><td>1</td></tr></thead>\n\t//\t\t\t<tbody><tr><td>3</td></tr></tbody>\n\t//\t\t</table>\n\t//\n\t// But browsers will render rows in order as: 1 as heading and 2 and 3 as the body.\n\tconst headRows = [];\n\tconst bodyRows = [];\n\n\t// Currently the editor does not support more then one <thead> section.\n\t// Only the first <thead> from the view will be used as heading rows and others will be converted to body rows.\n\tlet firstTheadElement;\n\n\tfor ( const tableChild of Array.from( viewTable.getChildren() ) ) {\n\t\t// Only <thead>, <tbody> & <tfoot> from allowed table children can have <tr>s.\n\t\t// The else is for future purposes (mainly <caption>).\n\t\tif ( tableChild.name === 'tbody' || tableChild.name === 'thead' || tableChild.name === 'tfoot' ) {\n\t\t\t// Save the first <thead> in the table as table header - all other ones will be converted to table body rows.\n\t\t\tif ( tableChild.name === 'thead' && !firstTheadElement ) {\n\t\t\t\tfirstTheadElement = tableChild;\n\t\t\t}\n\n\t\t\t// There might be some extra empty text nodes between the `tr`s.\n\t\t\t// Make sure further code operates on `tr`s only. (#145)\n\t\t\tconst trs = Array.from( tableChild.getChildren() ).filter( el => el.is( 'element', 'tr' ) );\n\n\t\t\tfor ( const tr of trs ) {\n\t\t\t\t// This <tr> is a child of a first <thead> element.\n\t\t\t\tif ( tr.parent.name === 'thead' && tr.parent === firstTheadElement ) {\n\t\t\t\t\ttableMeta.headingRows++;\n\t\t\t\t\theadRows.push( tr );\n\t\t\t\t} else {\n\t\t\t\t\tbodyRows.push( tr );\n\t\t\t\t\t// For other rows check how many column headings this row has.\n\n\t\t\t\t\tconst headingCols = scanRowForHeadingColumns( tr, tableMeta, firstTheadElement );\n\n\t\t\t\t\tif ( headingCols > tableMeta.headingColumns ) {\n\t\t\t\t\t\ttableMeta.headingColumns = headingCols;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\ttableMeta.rows = [ ...headRows, ...bodyRows ];\n\n\treturn tableMeta;\n}\n\n// Scans a `<tr>` element and its children for metadata:\n// - For heading row:\n// - Adds this row to either the heading or the body rows.\n// - Updates the number of heading rows.\n// - For body rows:\n// - Calculates the number of column headings.\n//\n// @param {module:engine/view/element~Element} tr\n// @returns {Number}\nfunction scanRowForHeadingColumns( tr ) {\n\tlet headingColumns = 0;\n\tlet index = 0;\n\n\t// Filter out empty text nodes from tr children.\n\tconst children = Array.from( tr.getChildren() )\n\t\t.filter( child => child.name === 'th' || child.name === 'td' );\n\n\t// Count starting adjacent <th> elements of a <tr>.\n\twhile ( index < children.length && children[ index ].name === 'th' ) {\n\t\tconst th = children[ index ];\n\n\t\t// Adjust columns calculation by the number of spanned columns.\n\t\tconst colspan = parseInt( th.getAttribute( 'colspan' ) || 1 );\n\n\t\theadingColumns = headingColumns + colspan;\n\t\tindex++;\n\t}\n\n\treturn headingColumns;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/tablewalker\n */\n\n/**\n * The table iterator class. It allows to iterate over table cells. For each cell the iterator yields\n * {@link module:table/tablewalker~TableWalkerValue} with proper table cell attributes.\n */\nexport default class TableWalker {\n\t/**\n\t * Creates an instance of the table walker.\n\t *\n\t * The table walker iterates internally by traversing the table from row index = 0 and column index = 0.\n\t * It walks row by row and column by column in order to output values defined in the constructor.\n\t * By default it will output only the locations that are occupied by a cell. To include also spanned rows and columns,\n\t * pass the `includeSpanned` option to the constructor.\n\t *\n\t * The most important values of the iterator are column and row indexes of a cell.\n\t *\n\t * See {@link module:table/tablewalker~TableWalkerValue} what values are returned by the table walker.\n\t *\n\t * To iterate over a given row:\n\t *\n\t *\t\tconst tableWalker = new TableWalker( table, { startRow: 1, endRow: 2 } );\n\t *\n\t *\t\tfor ( const cellInfo of tableWalker ) {\n\t *\t\t\tconsole.log( 'A cell at row ' + cellInfo.row + ' and column ' + cellInfo.column );\n\t *\t\t}\n\t *\n\t * For instance the code above for the following table:\n\t *\n\t *\t\t+----+----+----+----+----+----+\n\t *\t\t| 00 | 02 | 03 | 04 | 05 |\n\t *\t\t| +----+----+----+----+\n\t *\t\t| | 12 | 14 | 15 |\n\t *\t\t| +----+----+----+ +\n\t *\t\t| | 22 | |\n\t *\t\t|----+----+----+----+----+ +\n\t *\t\t| 30 | 31 | 32 | 33 | 34 | |\n\t *\t\t+----+----+----+----+----+----+\n\t *\n\t * will log in the console:\n\t *\n\t *\t\t'A cell at row 1 and column 2'\n\t *\t\t'A cell at row 1 and column 4'\n\t *\t\t'A cell at row 1 and column 5'\n\t *\t\t'A cell at row 2 and column 2'\n\t *\n\t * To also iterate over spanned cells:\n\t *\n\t *\t\tconst tableWalker = new TableWalker( table, { startRow: 1, endRow: 1, includeSpanned: true } );\n\t *\n\t *\t\tfor ( const value of tableWalker ) {\n\t *\t\t\tconsole.log( 'Cell at ' + value.row + ' x ' + value.column + ' : ' + ( value.isSpanned ? 'is spanned' : 'has data' ) );\n\t *\t\t}\n\t *\n\t * will log in the console for the table from the previous example:\n\t *\n\t *\t\t'Cell at 1 x 0 : is spanned'\n\t *\t\t'Cell at 1 x 1 : is spanned'\n\t *\t\t'Cell at 1 x 2 : has data'\n\t *\t\t'Cell at 1 x 3 : is spanned'\n\t *\t\t'Cell at 1 x 4 : has data'\n\t *\t\t'Cell at 1 x 5 : has data'\n\t *\n\t * @constructor\n\t * @param {module:engine/model/element~Element} table A table over which the walker iterates.\n\t * @param {Object} [options={}] An object with configuration.\n\t * @param {Number} [options.column] A column index for which this iterator will output cells.\n\t * @param {Number} [options.startRow=0] A row index from which this iterator should start.\n\t * @param {Number} [options.endRow] A row index at which this iterator should end.\n\t * @param {Boolean} [options.includeSpanned=false] Also return values for spanned cells.\n\t */\n\tconstructor( table, options = {} ) {\n\t\t/**\n\t\t * The walker's table element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element}\n\t\t */\n\t\tthis.table = table;\n\n\t\t/**\n\t\t * A row index from which this iterator will start.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.startRow = options.startRow || 0;\n\n\t\t/**\n\t\t * A row index at which this iterator will end.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.endRow = typeof options.endRow == 'number' ? options.endRow : undefined;\n\n\t\t/**\n\t\t * Enables output of spanned cells that are normally not yielded.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.includeSpanned = !!options.includeSpanned;\n\n\t\t/**\n\t\t * If set, the table walker will only output cells of a given column or cells that overlap it.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.column = typeof options.column == 'number' ? options.column : undefined;\n\n\t\t/**\n\t\t * Row indexes to skip from the iteration.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set<Number>}\n\t\t * @private\n\t\t */\n\t\tthis._skipRows = new Set();\n\n\t\t/**\n\t\t * The current row index.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._row = 0;\n\n\t\t/**\n\t\t * The current column index.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._column = 0;\n\n\t\t/**\n\t\t * The cell index in a parent row. For spanned cells when {@link #includeSpanned} is set to `true`,\n\t\t * this represents the index of the next table cell.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._cellIndex = 0;\n\n\t\t/**\n\t\t * Holds a map of spanned cells in a table.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Map<Number, Map.<Number, module:engine/model/element~Element>>}\n\t\t * @private\n\t\t */\n\t\tthis._spannedCells = new Map();\n\n\t\tthis._nextCellAtColumn = -1;\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<module:table/tablewalker~TableWalkerValue>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the next table walker's value.\n\t *\n\t * @returns {module:table/tablewalker~TableWalkerValue} The next table walker's value.\n\t */\n\tnext() {\n\t\tconst row = this.table.getChild( this._row );\n\n\t\t// Iterator is done when there's no row (table ended) or the row is after `endRow` limit.\n\t\tif ( !row || this._isOverEndRow() ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\tlet cell, skipCurrentValue, outValue;\n\n\t\tif ( this._isSpanned( this._row, this._column ) ) {\n\t\t\tcell = this._getSpanned( this._row, this._column );\n\n\t\t\tskipCurrentValue = !this.includeSpanned || this._shouldSkipRow() || this._shouldSkipColumn();\n\t\t\toutValue = this._formatOutValue( cell, this._column, true );\n\t\t} else {\n\t\t\tcell = row.getChild( this._cellIndex );\n\n\t\t\tif ( !cell ) {\n\t\t\t\t// If there are no more cells left in row advance to the next row.\n\t\t\t\tthis._row++;\n\t\t\t\tthis._column = 0;\n\t\t\t\tthis._cellIndex = 0;\n\t\t\t\tthis._nextCellAtColumn = -1;\n\n\t\t\t\treturn this.next();\n\t\t\t}\n\n\t\t\tconst colspan = parseInt( cell.getAttribute( 'colspan' ) || 1 );\n\t\t\tconst rowspan = parseInt( cell.getAttribute( 'rowspan' ) || 1 );\n\n\t\t\t// Record this cell spans if it's not 1x1 cell.\n\t\t\tif ( colspan > 1 || rowspan > 1 ) {\n\t\t\t\tthis._recordSpans( this._row, this._column, rowspan, colspan, cell );\n\t\t\t}\n\n\t\t\tthis._nextCellAtColumn = this._column + colspan;\n\n\t\t\tskipCurrentValue = this._shouldSkipRow() || this._shouldSkipColumn();\n\t\t\toutValue = this._formatOutValue( cell, this._column, false, rowspan, colspan );\n\t\t}\n\n\t\t// Advance to the next column before returning value.\n\t\tthis._column++;\n\n\t\tif ( this._column == this._nextCellAtColumn ) {\n\t\t\tthis._cellIndex++;\n\t\t}\n\n\t\t// The current value will be returned only if current row and column are not skipped.\n\t\treturn skipCurrentValue ? this.next() : outValue;\n\t}\n\n\t/**\n\t * Marks a row to skip in the next iteration. It will also skip cells from the current row if there are any cells from the current row\n\t * to output.\n\t *\n\t * @param {Number} row The row index to skip.\n\t */\n\tskipRow( row ) {\n\t\tthis._skipRows.add( row );\n\t}\n\n\t/**\n\t * Checks if the current row is over {@link #endRow}.\n\t *\n\t * @private\n\t * @returns {Boolean}\n\t */\n\t_isOverEndRow() {\n\t\t// If {@link #endRow) is defined skip all rows above it.\n\t\treturn this.endRow !== undefined && this._row > this.endRow;\n\t}\n\n\t/**\n\t * A common method for formatting the iterator's output value.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} cell The table cell to output.\n\t * @param {Number} column The column index (use the cached value).\n\t * @param {Boolean} isSpanned Whether the value is returned for a spanned cell location or an actual cell.\n\t * @param {Number} rowspan The rowspan of the current cell.\n\t * @param {Number} colspan The colspan of the current cell.\n\t * @returns {{done: Boolean, value: {cell: *, row: Number, column: *, rowspan: *, colspan: *, cellIndex: Number}}}\n\t */\n\t_formatOutValue( cell, column, isSpanned, rowspan = 1, colspan = 1 ) {\n\t\treturn {\n\t\t\tdone: false,\n\t\t\tvalue: {\n\t\t\t\tcell,\n\t\t\t\trow: this._row,\n\t\t\t\tcolumn,\n\t\t\t\tisSpanned,\n\t\t\t\trowspan,\n\t\t\t\tcolspan,\n\t\t\t\tcellIndex: this._cellIndex\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Checks if the current row should be skipped.\n\t *\n\t * @private\n\t * @returns {Boolean}\n\t */\n\t_shouldSkipRow() {\n\t\tconst rowIsBelowStartRow = this._row < this.startRow;\n\t\tconst rowIsMarkedAsSkipped = this._skipRows.has( this._row );\n\n\t\treturn rowIsBelowStartRow || rowIsMarkedAsSkipped;\n\t}\n\n\t/**\n\t * Checks if the current column should be skipped.\n\t *\n\t * @private\n\t * @returns {Boolean}\n\t */\n\t_shouldSkipColumn() {\n\t\tif ( this.column === undefined ) {\n\t\t\t// The {@link #column} is not defined so output all columns.\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.column != this._column;\n\t}\n\n\t/**\n\t * Checks if the current cell location (row x column) is spanned by another cell.\n\t *\n\t * @private\n\t * @param {Number} row The row index of a cell location to check.\n\t * @param {Number} column The column index of a cell location to check.\n\t * @returns {Boolean}\n\t */\n\t_isSpanned( row, column ) {\n\t\tif ( !this._spannedCells.has( row ) ) {\n\t\t\t// No spans for given row.\n\t\t\treturn false;\n\t\t}\n\n\t\tconst rowSpans = this._spannedCells.get( row );\n\n\t\t// If spans for given rows has entry for column it means that this location if spanned by other cell.\n\t\treturn rowSpans.has( column );\n\t}\n\n\t/**\n\t * Returns the cell element that is spanned over the `row` x `column` location.\n\t *\n\t * @private\n\t * @param {Number} row The row index of the cell location.\n\t * @param {Number} column The column index of the cell location.\n\t * @returns {module:engine/model/element~Element}\n\t */\n\t_getSpanned( row, column ) {\n\t\treturn this._spannedCells.get( row ).get( column );\n\t}\n\n\t/**\n\t * Updates spanned cells map relative to the current cell location and its span dimensions.\n\t *\n\t * @private\n\t * @param {Number} row The row index of a cell.\n\t * @param {Number} column The column index of a cell.\n\t * @param {Number} rowspan Cell height.\n\t * @param {Number} colspan Cell width.\n\t * @param {module:engine/model/element~Element} cell A cell that is spanned.\n\t */\n\t_recordSpans( row, column, rowspan, colspan, cell ) {\n\t\t// This will update all cell locations after current column - ie a cell has colspan set.\n\t\tfor ( let columnToUpdate = column + 1; columnToUpdate <= column + colspan - 1; columnToUpdate++ ) {\n\t\t\tthis._markSpannedCell( row, columnToUpdate, cell );\n\t\t}\n\n\t\t// This will update all rows below current up to row's height.\n\t\tfor ( let rowToUpdate = row + 1; rowToUpdate < row + rowspan; rowToUpdate++ ) {\n\t\t\tfor ( let columnToUpdate = column; columnToUpdate <= column + colspan - 1; columnToUpdate++ ) {\n\t\t\t\tthis._markSpannedCell( rowToUpdate, columnToUpdate, cell );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Marks the cell location as spanned by another cell.\n\t *\n\t * @private\n\t * @param {Number} row The row index of the cell location.\n\t * @param {Number} column The column index of the cell location.\n\t * @param {module:engine/model/element~Element} cell A cell that is spanned.\n\t */\n\t_markSpannedCell( row, column, cell ) {\n\t\tif ( !this._spannedCells.has( row ) ) {\n\t\t\tthis._spannedCells.set( row, new Map() );\n\t\t}\n\n\t\tconst rowSpans = this._spannedCells.get( row );\n\n\t\trowSpans.set( column, cell );\n\t}\n}\n\n/**\n * An object returned by {@link module:table/tablewalker~TableWalker} when traversing table cells.\n *\n * @typedef {Object} module:table/tablewalker~TableWalkerValue\n * @property {module:engine/model/element~Element} cell The current table cell.\n * @property {Number} row The row index of a cell.\n * @property {Number} column The column index of a cell. Column index is adjusted to widths and heights of previous cells.\n * @param {Boolean} isSpanned Whether the value is returned for a spanned cell location or an actual cell.\n * @property {Number} colspan The `colspan` attribute of a cell. If the model attribute is not present, it is set to `1`. For spanned\n * table locations, it is set to `1`.\n * @property {Number} rowspan The `rowspan` attribute of a cell. If the model attribute is not present, it is set to `1`. For spanned\n * table locations, it is set to `1`.\n * @property {Number} cellIndex The index of the current cell in the parent row.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 table/utils\n */\n\nimport { isWidget, toWidget } from '@ckeditor/ckeditor5-widget/src/utils';\nimport { findAncestor } from './commands/utils';\n\n/**\n * Converts a given {@link module:engine/view/element~Element} to a table widget:\n * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the table widget element.\n * * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.\n * @param {String} label The element's label. It will be concatenated with the table `alt` attribute if one is present.\n * @returns {module:engine/view/element~Element}\n */\nexport function toTableWidget( viewElement, writer ) {\n\twriter.setCustomProperty( 'table', true, viewElement );\n\n\treturn toWidget( viewElement, writer, { hasSelectionHandle: true } );\n}\n\n/**\n * Checks if a given view element is a table widget.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @returns {Boolean}\n */\nexport function isTableWidget( viewElement ) {\n\treturn !!viewElement.getCustomProperty( 'table' ) && isWidget( viewElement );\n}\n\n/**\n * Returns a table widget editing view element if one is selected.\n *\n * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection\n * @returns {module:engine/view/element~Element|null}\n */\nexport function getSelectedTableWidget( selection ) {\n\tconst viewElement = selection.getSelectedElement();\n\n\tif ( viewElement && isTableWidget( viewElement ) ) {\n\t\treturn viewElement;\n\t}\n\n\treturn null;\n}\n\n/**\n * Returns a table widget editing view element if one is among the selection's ancestors.\n *\n * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection\n * @returns {module:engine/view/element~Element|null}\n */\nexport function getTableWidgetAncestor( selection ) {\n\tconst parentTable = findAncestor( 'table', selection.getFirstPosition() );\n\n\tif ( parentTable && isTableWidget( parentTable.parent ) ) {\n\t\treturn parentTable.parent;\n\t}\n\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/converters/downcast\n */\n\nimport TableWalker from './../tablewalker';\nimport { toWidgetEditable } from '@ckeditor/ckeditor5-widget/src/utils';\nimport { toTableWidget } from '../utils';\n\n/**\n * Model table element to view table element conversion helper.\n *\n * This conversion helper creates the whole table element with child elements.\n *\n * @param {Object} options\n * @param {Boolean} options.asWidget If set to `true`, the downcast conversion will produce a widget.\n * @returns {Function} Conversion helper.\n */\nexport function downcastInsertTable( options = {} ) {\n\treturn dispatcher => dispatcher.on( 'insert:table', ( evt, data, conversionApi ) => {\n\t\tconst table = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( table, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Consume attributes if present to not fire attribute change downcast\n\t\tconversionApi.consumable.consume( table, 'attribute:headingRows:table' );\n\t\tconversionApi.consumable.consume( table, 'attribute:headingColumns:table' );\n\n\t\tconst asWidget = options && options.asWidget;\n\n\t\tconst figureElement = conversionApi.writer.createContainerElement( 'figure', { class: 'table' } );\n\t\tconst tableElement = conversionApi.writer.createContainerElement( 'table' );\n\t\tconversionApi.writer.insert( conversionApi.writer.createPositionAt( figureElement, 0 ), tableElement );\n\n\t\tlet tableWidget;\n\n\t\tif ( asWidget ) {\n\t\t\ttableWidget = toTableWidget( figureElement, conversionApi.writer );\n\t\t}\n\n\t\tconst tableWalker = new TableWalker( table );\n\n\t\tconst tableAttributes = {\n\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t};\n\n\t\t// Cache for created table rows.\n\t\tconst viewRows = new Map();\n\n\t\tfor ( const tableWalkerValue of tableWalker ) {\n\t\t\tconst { row, cell } = tableWalkerValue;\n\n\t\t\tconst tableSection = getOrCreateTableSection( getSectionName( row, tableAttributes ), tableElement, conversionApi );\n\t\t\tconst tableRow = table.getChild( row );\n\n\t\t\tconst trElement = viewRows.get( row ) || createTr( tableRow, row, tableSection, conversionApi );\n\t\t\tviewRows.set( row, trElement );\n\n\t\t\t// Consume table cell - it will be always consumed as we convert whole table at once.\n\t\t\tconversionApi.consumable.consume( cell, 'insert' );\n\n\t\t\tconst insertPosition = conversionApi.writer.createPositionAt( trElement, 'end' );\n\n\t\t\tcreateViewTableCellElement( tableWalkerValue, tableAttributes, insertPosition, conversionApi, options );\n\t\t}\n\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\n\t\tconversionApi.mapper.bindElements( table, asWidget ? tableWidget : figureElement );\n\t\tconversionApi.writer.insert( viewPosition, asWidget ? tableWidget : figureElement );\n\t} );\n}\n\n/**\n * Model row element to view `<tr>` element conversion helper.\n *\n * This conversion helper creates the whole `<tr>` element with child elements.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastInsertRow( options = {} ) {\n\treturn dispatcher => dispatcher.on( 'insert:tableRow', ( evt, data, conversionApi ) => {\n\t\tconst tableRow = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( tableRow, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst table = tableRow.parent;\n\n\t\tconst figureElement = conversionApi.mapper.toViewElement( table );\n\t\tconst tableElement = getViewTable( figureElement );\n\n\t\tconst row = table.getChildIndex( tableRow );\n\n\t\tconst tableWalker = new TableWalker( table, { startRow: row, endRow: row } );\n\n\t\tconst tableAttributes = {\n\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t};\n\n\t\t// Cache for created table rows.\n\t\tconst viewRows = new Map();\n\n\t\tfor ( const tableWalkerValue of tableWalker ) {\n\t\t\tconst tableSection = getOrCreateTableSection( getSectionName( row, tableAttributes ), tableElement, conversionApi );\n\n\t\t\tconst trElement = viewRows.get( row ) || createTr( tableRow, row, tableSection, conversionApi );\n\t\t\tviewRows.set( row, trElement );\n\n\t\t\t// Consume table cell - it will be always consumed as we convert whole row at once.\n\t\t\tconversionApi.consumable.consume( tableWalkerValue.cell, 'insert' );\n\n\t\t\tconst insertPosition = conversionApi.writer.createPositionAt( trElement, 'end' );\n\n\t\t\tcreateViewTableCellElement( tableWalkerValue, tableAttributes, insertPosition, conversionApi, options );\n\t\t}\n\t} );\n}\n\n/**\n * Model table cell element to view `<td>` or `<th>` element conversion helper.\n *\n * This conversion helper will create proper `<th>` elements for table cells that are in the heading section (heading row or column)\n * and `<td>` otherwise.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastInsertCell( options = {} ) {\n\treturn dispatcher => dispatcher.on( 'insert:tableCell', ( evt, data, conversionApi ) => {\n\t\tconst tableCell = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( tableCell, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\t\tconst rowIndex = table.getChildIndex( tableRow );\n\n\t\tconst tableWalker = new TableWalker( table, { startRow: rowIndex, endRow: rowIndex } );\n\n\t\tconst tableAttributes = {\n\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t};\n\n\t\t// We need to iterate over a table in order to get proper row & column values from a walker\n\t\tfor ( const tableWalkerValue of tableWalker ) {\n\t\t\tif ( tableWalkerValue.cell === tableCell ) {\n\t\t\t\tconst trElement = conversionApi.mapper.toViewElement( tableRow );\n\t\t\t\tconst insertPosition = conversionApi.writer.createPositionAt( trElement, tableRow.getChildIndex( tableCell ) );\n\n\t\t\t\tcreateViewTableCellElement( tableWalkerValue, tableAttributes, insertPosition, conversionApi, options );\n\n\t\t\t\t// No need to iterate further.\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t} );\n}\n\n/**\n * Conversion helper that acts on heading row table attribute change.\n *\n * This converter will:\n *\n * * Rename `<td>` to `<th>` elements or vice versa depending on headings.\n * * Create `<thead>` or `<tbody>` elements if needed.\n * * Remove empty `<thead>` or `<tbody>` if needed.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastTableHeadingRowsChange( options = {} ) {\n\tconst asWidget = !!options.asWidget;\n\n\treturn dispatcher => dispatcher.on( 'attribute:headingRows:table', ( evt, data, conversionApi ) => {\n\t\tconst table = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst figureElement = conversionApi.mapper.toViewElement( table );\n\t\tconst viewTable = getViewTable( figureElement );\n\n\t\tconst oldRows = data.attributeOldValue;\n\t\tconst newRows = data.attributeNewValue;\n\n\t\t// The head section has grown so move rows from <tbody> to <thead>.\n\t\tif ( newRows > oldRows ) {\n\t\t\t// Filter out only those rows that are in wrong section.\n\t\t\tconst rowsToMove = Array.from( table.getChildren() ).filter( ( { index } ) => isBetween( index, oldRows - 1, newRows ) );\n\n\t\t\tconst viewTableHead = getOrCreateTableSection( 'thead', viewTable, conversionApi );\n\t\t\tmoveViewRowsToTableSection( rowsToMove, viewTableHead, conversionApi, 'end' );\n\n\t\t\t// Rename all table cells from moved rows to 'th' as they lands in <thead>.\n\t\t\tfor ( const tableRow of rowsToMove ) {\n\t\t\t\tfor ( const tableCell of tableRow.getChildren() ) {\n\t\t\t\t\trenameViewTableCell( tableCell, 'th', conversionApi, asWidget );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Cleanup: this will remove any empty section from the view which may happen when moving all rows from a table section.\n\t\t\tremoveTableSectionIfEmpty( 'tbody', viewTable, conversionApi );\n\t\t}\n\t\t// The head section has shrunk so move rows from <thead> to <tbody>.\n\t\telse {\n\t\t\t// Filter out only those rows that are in wrong section.\n\t\t\tconst rowsToMove = Array.from( table.getChildren() )\n\t\t\t\t.filter( ( { index } ) => isBetween( index, newRows - 1, oldRows ) )\n\t\t\t\t.reverse(); // The rows will be moved from <thead> to <tbody> in reverse order at the beginning of a <tbody>.\n\n\t\t\tconst viewTableBody = getOrCreateTableSection( 'tbody', viewTable, conversionApi );\n\t\t\tmoveViewRowsToTableSection( rowsToMove, viewTableBody, conversionApi, 0 );\n\n\t\t\t// Check if cells moved from <thead> to <tbody> requires renaming to <td> as this depends on current heading columns attribute.\n\t\t\tconst tableWalker = new TableWalker( table, { startRow: newRows ? newRows - 1 : newRows, endRow: oldRows - 1 } );\n\n\t\t\tconst tableAttributes = {\n\t\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t\t};\n\n\t\t\tfor ( const tableWalkerValue of tableWalker ) {\n\t\t\t\trenameViewTableCellIfRequired( tableWalkerValue, tableAttributes, conversionApi, asWidget );\n\t\t\t}\n\n\t\t\t// Cleanup: this will remove any empty section from the view which may happen when moving all rows from a table section.\n\t\t\tremoveTableSectionIfEmpty( 'thead', viewTable, conversionApi );\n\t\t}\n\n\t\tfunction isBetween( index, lower, upper ) {\n\t\t\treturn index > lower && index < upper;\n\t\t}\n\t} );\n}\n\n/**\n * Conversion helper that acts on heading column table attribute change.\n *\n * Depending on changed attributes this converter will rename `<td` to `<th>` elements or vice versa depending on the cell column index.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastTableHeadingColumnsChange( options = {} ) {\n\tconst asWidget = !!options.asWidget;\n\n\treturn dispatcher => dispatcher.on( 'attribute:headingColumns:table', ( evt, data, conversionApi ) => {\n\t\tconst table = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst tableAttributes = {\n\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t};\n\n\t\tconst oldColumns = data.attributeOldValue;\n\t\tconst newColumns = data.attributeNewValue;\n\n\t\tconst lastColumnToCheck = ( oldColumns > newColumns ? oldColumns : newColumns ) - 1;\n\n\t\tfor ( const tableWalkerValue of new TableWalker( table ) ) {\n\t\t\t// Skip cells that were not in heading section before and after the change.\n\t\t\tif ( tableWalkerValue.column > lastColumnToCheck ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\trenameViewTableCellIfRequired( tableWalkerValue, tableAttributes, conversionApi, asWidget );\n\t\t}\n\t} );\n}\n\n/**\n * Conversion helper that acts on a removed row.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastRemoveRow() {\n\treturn dispatcher => dispatcher.on( 'remove:tableRow', ( evt, data, conversionApi ) => {\n\t\t// Prevent default remove converter.\n\t\tevt.stop();\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst mapper = conversionApi.mapper;\n\n\t\tconst viewStart = mapper.toViewPosition( data.position ).getLastMatchingPosition( value => !value.item.is( 'tr' ) );\n\t\tconst viewItem = viewStart.nodeAfter;\n\t\tconst tableSection = viewItem.parent;\n\n\t\t// Remove associated <tr> from the view.\n\t\tconst removeRange = viewWriter.createRangeOn( viewItem );\n\t\tconst removed = viewWriter.remove( removeRange );\n\n\t\tfor ( const child of viewWriter.createRangeIn( removed ).getItems() ) {\n\t\t\tmapper.unbindViewElement( child );\n\t\t}\n\n\t\t// Check if table section has any children left - if not remove it from the view.\n\t\tif ( !tableSection.childCount ) {\n\t\t\t// No need to unbind anything as table section is not represented in the model.\n\t\t\tviewWriter.remove( viewWriter.createRangeOn( tableSection ) );\n\t\t}\n\t}, { priority: 'higher' } );\n}\n\n// Renames an existing table cell in the view to a given element name.\n//\n// **Note** This method will not do anything if a view table cell has not been converted yet.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @param {String} desiredCellElementName\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @param {Boolean} asWidget\nfunction renameViewTableCell( tableCell, desiredCellElementName, conversionApi, asWidget ) {\n\tconst viewWriter = conversionApi.writer;\n\tconst viewCell = conversionApi.mapper.toViewElement( tableCell );\n\n\t// View cell might be not yet converted - skip it as it will be properly created by cell converter later on.\n\tif ( !viewCell ) {\n\t\treturn;\n\t}\n\n\tlet renamedCell;\n\n\tif ( asWidget ) {\n\t\tconst editable = viewWriter.createEditableElement( desiredCellElementName, viewCell.getAttributes() );\n\t\trenamedCell = toWidgetEditable( editable, viewWriter );\n\n\t\tviewWriter.insert( viewWriter.createPositionAfter( viewCell ), renamedCell );\n\t\tviewWriter.move( viewWriter.createRangeIn( viewCell ), viewWriter.createPositionAt( renamedCell, 0 ) );\n\t\tviewWriter.remove( viewWriter.createRangeOn( viewCell ) );\n\t} else {\n\t\trenamedCell = viewWriter.rename( desiredCellElementName, viewCell );\n\t}\n\n\tconversionApi.mapper.unbindViewElement( viewCell );\n\tconversionApi.mapper.bindElements( tableCell, renamedCell );\n}\n\n// Renames a table cell element in the view according to its location in the table.\n//\n// @param {module:table/tablewalker~TableWalkerValue} tableWalkerValue\n// @param {{headingColumns, headingRows}} tableAttributes\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @param {Boolean} asWidget\nfunction renameViewTableCellIfRequired( tableWalkerValue, tableAttributes, conversionApi, asWidget ) {\n\tconst { cell } = tableWalkerValue;\n\n\t// Check whether current columnIndex is overlapped by table cells from previous rows.\n\tconst desiredCellElementName = getCellElementName( tableWalkerValue, tableAttributes );\n\n\tconst viewCell = conversionApi.mapper.toViewElement( cell );\n\n\t// If in single change we're converting attribute changes and inserting cell the table cell might not be inserted into view\n\t// because of child conversion is done after parent.\n\tif ( viewCell && viewCell.name !== desiredCellElementName ) {\n\t\trenameViewTableCell( cell, desiredCellElementName, conversionApi, asWidget );\n\t}\n}\n\n// Creates a table cell element in the view.\n//\n// @param {module:table/tablewalker~TableWalkerValue} tableWalkerValue\n// @param {module:engine/view/position~Position} insertPosition\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction createViewTableCellElement( tableWalkerValue, tableAttributes, insertPosition, conversionApi, options ) {\n\tconst asWidget = options && options.asWidget;\n\tconst cellElementName = getCellElementName( tableWalkerValue, tableAttributes );\n\n\tconst cellElement = asWidget ?\n\t\ttoWidgetEditable( conversionApi.writer.createEditableElement( cellElementName ), conversionApi.writer ) :\n\t\tconversionApi.writer.createContainerElement( cellElementName );\n\n\tconst tableCell = tableWalkerValue.cell;\n\n\tconst firstChild = tableCell.getChild( 0 );\n\tconst isSingleParagraph = tableCell.childCount === 1 && firstChild.name === 'paragraph';\n\n\tconversionApi.writer.insert( insertPosition, cellElement );\n\n\tif ( isSingleParagraph && !hasAnyAttribute( firstChild ) ) {\n\t\tconst innerParagraph = tableCell.getChild( 0 );\n\t\tconst paragraphInsertPosition = conversionApi.writer.createPositionAt( cellElement, 'end' );\n\n\t\tconversionApi.consumable.consume( innerParagraph, 'insert' );\n\n\t\tif ( options.asWidget ) {\n\t\t\t// Use display:inline-block to force Chrome/Safari to limit text mutations to this element.\n\t\t\t// See #6062.\n\t\t\tconst fakeParagraph = conversionApi.writer.createContainerElement( 'span', { style: 'display:inline-block' } );\n\n\t\t\tconversionApi.mapper.bindElements( innerParagraph, fakeParagraph );\n\t\t\tconversionApi.writer.insert( paragraphInsertPosition, fakeParagraph );\n\n\t\t\tconversionApi.mapper.bindElements( tableCell, cellElement );\n\t\t} else {\n\t\t\tconversionApi.mapper.bindElements( tableCell, cellElement );\n\t\t\tconversionApi.mapper.bindElements( innerParagraph, cellElement );\n\t\t}\n\t} else {\n\t\tconversionApi.mapper.bindElements( tableCell, cellElement );\n\t}\n}\n\n// Creates a `<tr>` view element.\n//\n// @param {module:engine/view/element~Element} tableRow\n// @param {Number} rowIndex\n// @param {module:engine/view/element~Element} tableSection\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @returns {module:engine/view/element~Element}\nfunction createTr( tableRow, rowIndex, tableSection, conversionApi ) {\n\t// Will always consume since we're converting <tableRow> element from a parent <table>.\n\tconversionApi.consumable.consume( tableRow, 'insert' );\n\n\tconst trElement = conversionApi.writer.createContainerElement( 'tr' );\n\tconversionApi.mapper.bindElements( tableRow, trElement );\n\n\tconst headingRows = tableRow.parent.getAttribute( 'headingRows' ) || 0;\n\tconst offset = headingRows > 0 && rowIndex >= headingRows ? rowIndex - headingRows : rowIndex;\n\n\tconst position = conversionApi.writer.createPositionAt( tableSection, offset );\n\tconversionApi.writer.insert( position, trElement );\n\n\treturn trElement;\n}\n\n// Returns `th` for heading cells and `td` for other cells for the current table walker value.\n//\n// @param {module:table/tablewalker~TableWalkerValue} tableWalkerValue\n// @param {{headingColumns, headingRows}} tableAttributes\n// @returns {String}\nfunction getCellElementName( tableWalkerValue, tableAttributes ) {\n\tconst { row, column } = tableWalkerValue;\n\tconst { headingColumns, headingRows } = tableAttributes;\n\n\t// Column heading are all tableCells in the first `columnHeading` rows.\n\tconst isColumnHeading = headingRows && headingRows > row;\n\n\t// So a whole row gets <th> element.\n\tif ( isColumnHeading ) {\n\t\treturn 'th';\n\t}\n\n\t// Row heading are tableCells which columnIndex is lower then headingColumns.\n\tconst isRowHeading = headingColumns && headingColumns > column;\n\n\treturn isRowHeading ? 'th' : 'td';\n}\n\n// Returns the table section name for the current table walker value.\n//\n// @param {Number} row\n// @param {{headingColumns, headingRows}} tableAttributes\n// @returns {String}\nfunction getSectionName( row, tableAttributes ) {\n\treturn row < tableAttributes.headingRows ? 'thead' : 'tbody';\n}\n\n// Creates or returns an existing `<tbody>` or `<thead>` element with caching.\n//\n// @param {String} sectionName\n// @param {module:engine/view/element~Element} viewTable\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @param {Object} cachedTableSection An object that stores cached elements.\n// @returns {module:engine/view/containerelement~ContainerElement}\nfunction getOrCreateTableSection( sectionName, viewTable, conversionApi ) {\n\tconst viewTableSection = getExistingTableSectionElement( sectionName, viewTable );\n\n\treturn viewTableSection ? viewTableSection : createTableSection( sectionName, viewTable, conversionApi );\n}\n\n// Finds an existing `<tbody>` or `<thead>` element or returns undefined.\n//\n// @param {String} sectionName\n// @param {module:engine/view/element~Element} tableElement\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction getExistingTableSectionElement( sectionName, tableElement ) {\n\tfor ( const tableSection of tableElement.getChildren() ) {\n\t\tif ( tableSection.name == sectionName ) {\n\t\t\treturn tableSection;\n\t\t}\n\t}\n}\n\n// Creates a table section at the end of the table.\n//\n// @param {String} sectionName\n// @param {module:engine/view/element~Element} tableElement\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @returns {module:engine/view/containerelement~ContainerElement}\nfunction createTableSection( sectionName, tableElement, conversionApi ) {\n\tconst tableChildElement = conversionApi.writer.createContainerElement( sectionName );\n\n\tconst insertPosition = conversionApi.writer.createPositionAt( tableElement, sectionName == 'tbody' ? 'end' : 0 );\n\n\tconversionApi.writer.insert( insertPosition, tableChildElement );\n\n\treturn tableChildElement;\n}\n\n// Removes an existing `<tbody>` or `<thead>` element if it is empty.\n//\n// @param {String} sectionName\n// @param {module:engine/view/element~Element} tableElement\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction removeTableSectionIfEmpty( sectionName, tableElement, conversionApi ) {\n\tconst tableSection = getExistingTableSectionElement( sectionName, tableElement );\n\n\tif ( tableSection && tableSection.childCount === 0 ) {\n\t\tconversionApi.writer.remove( conversionApi.writer.createRangeOn( tableSection ) );\n\t}\n}\n\n// Moves view table rows associated with passed model rows to the provided table section element.\n//\n// **Note**: This method will skip not converted table rows.\n//\n// @param {Array.<module:engine/model/element~Element>} rowsToMove\n// @param {module:engine/view/element~Element} viewTableSection\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @param {Number|'end'|'before'|'after'} offset Offset or one of the flags.\nfunction moveViewRowsToTableSection( rowsToMove, viewTableSection, conversionApi, offset ) {\n\tfor ( const tableRow of rowsToMove ) {\n\t\tconst viewTableRow = conversionApi.mapper.toViewElement( tableRow );\n\n\t\t// View table row might be not yet converted - skip it as it will be properly created by cell converter later on.\n\t\tif ( viewTableRow ) {\n\t\t\tconversionApi.writer.move(\n\t\t\t\tconversionApi.writer.createRangeOn( viewTableRow ),\n\t\t\t\tconversionApi.writer.createPositionAt( viewTableSection, offset )\n\t\t\t);\n\t\t}\n\t}\n}\n\n// Finds a '<table>' element inside the `<figure>` widget.\n//\n// @param {module:engine/view/element~Element} viewFigure\nfunction getViewTable( viewFigure ) {\n\tfor ( const child of viewFigure.getChildren() ) {\n\t\tif ( child.name === 'table' ) {\n\t\t\treturn child;\n\t\t}\n\t}\n}\n\n// Checks if an element has any attributes set.\n//\n// @param {module:engine/model/element~Element element\n// @returns {Boolean}\nfunction hasAnyAttribute( element ) {\n\treturn !![ ...element.getAttributeKeys() ].length;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/commands/inserttablecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { findOptimalInsertionPosition } from '@ckeditor/ckeditor5-widget/src/utils';\n\n/**\n * The insert table command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'insertTable'` editor command.\n *\n * To insert a table at the current selection, execute the command and specify the dimensions:\n *\n *\t\teditor.execute( 'insertTable', { rows: 20, columns: 5 } );\n *\n * @extends module:core/command~Command\n */\nexport default class InsertTableCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst schema = model.schema;\n\n\t\tconst validParent = getInsertTableParent( selection.getFirstPosition() );\n\n\t\tthis.isEnabled = schema.checkChild( validParent, 'table' );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * Inserts a table with the given number of rows and columns into the editor.\n\t *\n\t * @param {Object} options\n\t * @param {Number} [options.rows=2] The number of rows to create in the inserted table.\n\t * @param {Number} [options.columns=2] The number of columns to create in the inserted table.\n\t * @fires execute\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\tconst rows = parseInt( options.rows ) || 2;\n\t\tconst columns = parseInt( options.columns ) || 2;\n\n\t\tconst insertPosition = findOptimalInsertionPosition( selection, model );\n\n\t\tmodel.change( writer => {\n\t\t\tconst table = tableUtils.createTable( writer, rows, columns );\n\n\t\t\tmodel.insertContent( table, insertPosition );\n\n\t\t\twriter.setSelection( writer.createPositionAt( table.getNodeByPath( [ 0, 0, 0 ] ), 0 ) );\n\t\t} );\n\t}\n}\n\n// Returns valid parent to insert table\n//\n// @param {module:engine/model/position} position\nfunction getInsertTableParent( position ) {\n\tconst parent = position.parent;\n\n\treturn parent === parent.root ? parent : parent.parent;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/commands/insertrowcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { findAncestor } from './utils';\n\n/**\n * The insert row command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'insertTableRowBelow'` and\n * `'insertTableRowAbove'` editor commands.\n *\n * To insert a row below the selected cell, execute the following command:\n *\n *\t\teditor.execute( 'insertTableRowBelow' );\n *\n * To insert a row above the selected cell, execute the following command:\n *\n *\t\teditor.execute( 'insertTableRowAbove' );\n *\n * @extends module:core/command~Command\n */\nexport default class InsertRowCommand extends Command {\n\t/**\n\t * Creates a new `InsertRowCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor on which this command will be used.\n\t * @param {Object} options\n\t * @param {String} [options.order=\"below\"] The order of insertion relative to the row in which the caret is located.\n\t * Possible values: `\"above\"` and `\"below\"`.\n\t */\n\tconstructor( editor, options = {} ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The order of insertion relative to the row in which the caret is located.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} module:table/commands/insertrowcommand~InsertRowCommand#order\n\t\t */\n\t\tthis.order = options.order || 'below';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selection = this.editor.model.document.selection;\n\n\t\tconst tableParent = findAncestor( 'table', selection.getFirstPosition() );\n\n\t\tthis.isEnabled = !!tableParent;\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * Depending on the command's {@link #order} value, it inserts a row `'below'` or `'above'` the row in which selection is set.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst tableUtils = editor.plugins.get( 'TableUtils' );\n\n\t\tconst tableCell = findAncestor( 'tableCell', selection.getFirstPosition() );\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst row = table.getChildIndex( tableRow );\n\t\tconst insertAt = this.order === 'below' ? row + 1 : row;\n\n\t\ttableUtils.insertRows( table, { rows: 1, at: insertAt } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/commands/insertcolumncommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { findAncestor } from './utils';\n\n/**\n * The insert column command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'insertTableColumnLeft'` and\n * `'insertTableColumnRight'` editor commands.\n *\n * To insert a column to the left of the selected cell, execute the following command:\n *\n *\t\teditor.execute( 'insertTableColumnLeft' );\n *\n * To insert a column to the right of the selected cell, execute the following command:\n *\n *\t\teditor.execute( 'insertTableColumnRight' );\n *\n * @extends module:core/command~Command\n */\nexport default class InsertColumnCommand extends Command {\n\t/**\n\t * Creates a new `InsertColumnCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor on which this command will be used.\n\t * @param {Object} options\n\t * @param {String} [options.order=\"right\"] The order of insertion relative to the column in which the caret is located.\n\t * Possible values: `\"left\"` and `\"right\"`.\n\t */\n\tconstructor( editor, options = {} ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The order of insertion relative to the column in which the caret is located.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} module:table/commands/insertcolumncommand~InsertColumnCommand#order\n\t\t */\n\t\tthis.order = options.order || 'right';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selection = this.editor.model.document.selection;\n\n\t\tconst tableParent = findAncestor( 'table', selection.getFirstPosition() );\n\n\t\tthis.isEnabled = !!tableParent;\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * Depending on the command's {@link #order} value, it inserts a column to the `'left'` or `'right'` of the column\n\t * in which the selection is set.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst tableUtils = editor.plugins.get( 'TableUtils' );\n\n\t\tconst firstPosition = selection.getFirstPosition();\n\n\t\tconst tableCell = findAncestor( 'tableCell', firstPosition );\n\t\tconst table = tableCell.parent.parent;\n\n\t\tconst { column } = tableUtils.getCellLocation( tableCell );\n\t\tconst insertAt = this.order === 'right' ? column + 1 : column;\n\n\t\ttableUtils.insertColumns( table, { columns: 1, at: insertAt } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/commands/splitcellcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { findAncestor } from './utils';\n\n/**\n * The split cell command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'splitTableCellVertically'`\n * and `'splitTableCellHorizontally'` editor commands.\n *\n * You can split any cell vertically or horizontally by executing this command. For example, to split the selected table cell vertically:\n *\n *\t\teditor.execute( 'splitTableCellVertically' );\n *\n * @extends module:core/command~Command\n */\nexport default class SplitCellCommand extends Command {\n\t/**\n\t * Creates a new `SplitCellCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor on which this command will be used.\n\t * @param {Object} options\n\t * @param {String} options.direction Indicates whether the command should split cells `'horizontally'` or `'vertically'`.\n\t */\n\tconstructor( editor, options = {} ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The direction that indicates which cell will be split.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} #direction\n\t\t */\n\t\tthis.direction = options.direction || 'horizontally';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tconst tableCell = findAncestor( 'tableCell', doc.selection.getFirstPosition() );\n\n\t\tthis.isEnabled = !!tableCell;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\t\tconst selection = document.selection;\n\n\t\tconst firstPosition = selection.getFirstPosition();\n\t\tconst tableCell = findAncestor( 'tableCell', firstPosition );\n\n\t\tconst isHorizontally = this.direction === 'horizontally';\n\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\tif ( isHorizontally ) {\n\t\t\ttableUtils.splitCellHorizontally( tableCell, 2 );\n\t\t} else {\n\t\t\ttableUtils.splitCellVertically( tableCell, 2 );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/commands/mergecellcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport TableWalker from '../tablewalker';\nimport { findAncestor, updateNumericAttribute } from './utils';\n\n/**\n * The merge cell command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'mergeTableCellRight'`, `'mergeTableCellLeft'`,\n * `'mergeTableCellUp'` and `'mergeTableCellDown'` editor commands.\n *\n * To merge a table cell at the current selection with another cell, execute the command corresponding with the preferred direction.\n *\n * For example, to merge with a cell to the right:\n *\n *\t\teditor.execute( 'mergeTableCellRight' );\n *\n * **Note**: If a table cell has a different [`rowspan`](https://www.w3.org/TR/html50/tabular-data.html#attr-tdth-rowspan)\n * (for `'mergeTableCellRight'` and `'mergeTableCellLeft'`) or [`colspan`](https://www.w3.org/TR/html50/tabular-data.html#attr-tdth-colspan)\n * (for `'mergeTableCellUp'` and `'mergeTableCellDown'`), the command will be disabled.\n *\n * @extends module:core/command~Command\n */\nexport default class MergeCellCommand extends Command {\n\t/**\n\t * Creates a new `MergeCellCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor on which this command will be used.\n\t * @param {Object} options\n\t * @param {String} options.direction Indicates which cell to merge with the currently selected one.\n\t * Possible values are: `'left'`, `'right'`, `'up'` and `'down'`.\n\t */\n\tconstructor( editor, options ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The direction that indicates which cell will be merged with the currently selected one.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} #direction\n\t\t */\n\t\tthis.direction = options.direction;\n\n\t\t/**\n\t\t * Whether the merge is horizontal (left/right) or vertical (up/down).\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isHorizontal\n\t\t */\n\t\tthis.isHorizontal = this.direction == 'right' || this.direction == 'left';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst cellToMerge = this._getMergeableCell();\n\n\t\tthis.value = cellToMerge;\n\t\tthis.isEnabled = !!cellToMerge;\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * Depending on the command's {@link #direction} value, it will merge the cell that is to the `'left'`, `'right'`, `'up'` or `'down'`.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst tableCell = findAncestor( 'tableCell', doc.selection.getFirstPosition() );\n\t\tconst cellToMerge = this.value;\n\t\tconst direction = this.direction;\n\n\t\tmodel.change( writer => {\n\t\t\tconst isMergeNext = direction == 'right' || direction == 'down';\n\n\t\t\t// The merge mechanism is always the same so sort cells to be merged.\n\t\t\tconst cellToExpand = isMergeNext ? tableCell : cellToMerge;\n\t\t\tconst cellToRemove = isMergeNext ? cellToMerge : tableCell;\n\n\t\t\t// Cache the parent of cell to remove for later check.\n\t\t\tconst removedTableCellRow = cellToRemove.parent;\n\n\t\t\tmergeTableCells( cellToRemove, cellToExpand, writer );\n\n\t\t\tconst spanAttribute = this.isHorizontal ? 'colspan' : 'rowspan';\n\t\t\tconst cellSpan = parseInt( tableCell.getAttribute( spanAttribute ) || 1 );\n\t\t\tconst cellToMergeSpan = parseInt( cellToMerge.getAttribute( spanAttribute ) || 1 );\n\n\t\t\t// Update table cell span attribute and merge set selection on merged contents.\n\t\t\twriter.setAttribute( spanAttribute, cellSpan + cellToMergeSpan, cellToExpand );\n\t\t\twriter.setSelection( writer.createRangeIn( cellToExpand ) );\n\n\t\t\t// Remove empty row after merging.\n\t\t\tif ( !removedTableCellRow.childCount ) {\n\t\t\t\tremoveEmptyRow( removedTableCellRow, writer );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns a cell that can be merged with the current cell depending on the command's direction.\n\t *\n\t * @returns {module:engine/model/element~Element|undefined}\n\t * @private\n\t */\n\t_getMergeableCell() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst tableCell = findAncestor( 'tableCell', doc.selection.getFirstPosition() );\n\n\t\tif ( !tableCell ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\t// First get the cell on proper direction.\n\t\tconst cellToMerge = this.isHorizontal ?\n\t\t\tgetHorizontalCell( tableCell, this.direction, tableUtils ) :\n\t\t\tgetVerticalCell( tableCell, this.direction );\n\n\t\tif ( !cellToMerge ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If found check if the span perpendicular to merge direction is equal on both cells.\n\t\tconst spanAttribute = this.isHorizontal ? 'rowspan' : 'colspan';\n\t\tconst span = parseInt( tableCell.getAttribute( spanAttribute ) || 1 );\n\n\t\tconst cellToMergeSpan = parseInt( cellToMerge.getAttribute( spanAttribute ) || 1 );\n\n\t\tif ( cellToMergeSpan === span ) {\n\t\t\treturn cellToMerge;\n\t\t}\n\t}\n}\n\n// Returns the cell that can be merged horizontally.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @param {String} direction\n// @returns {module:engine/model/node~Node|null}\nfunction getHorizontalCell( tableCell, direction, tableUtils ) {\n\tconst tableRow = tableCell.parent;\n\tconst table = tableRow.parent;\n\tconst horizontalCell = direction == 'right' ? tableCell.nextSibling : tableCell.previousSibling;\n\tconst headingColumns = table.getAttribute( 'headingColumns' ) || 0;\n\n\tif ( !horizontalCell ) {\n\t\treturn;\n\t}\n\n\t// Sort cells:\n\tconst cellOnLeft = direction == 'right' ? tableCell : horizontalCell;\n\tconst cellOnRight = direction == 'right' ? horizontalCell : tableCell;\n\n\t// Get their column indexes:\n\tconst { column: leftCellColumn } = tableUtils.getCellLocation( cellOnLeft );\n\tconst { column: rightCellColumn } = tableUtils.getCellLocation( cellOnRight );\n\n\tconst leftCellSpan = parseInt( cellOnLeft.getAttribute( 'colspan' ) || 1 );\n\tconst rightCellSpan = parseInt( cellOnRight.getAttribute( 'colspan' ) || 1 );\n\n\t// We cannot merge cells if the result will extend over heading section.\n\tconst isMergeWithBodyCell = direction == 'right' && ( rightCellColumn + rightCellSpan > headingColumns );\n\tconst isMergeWithHeadCell = direction == 'left' && ( leftCellColumn + leftCellSpan > headingColumns - 1 );\n\n\tif ( headingColumns && ( isMergeWithBodyCell || isMergeWithHeadCell ) ) {\n\t\treturn;\n\t}\n\n\t// The cell on the right must have index that is distant to the cell on the left by the left cell's width (colspan).\n\tconst cellsAreTouching = leftCellColumn + leftCellSpan === rightCellColumn;\n\n\t// If the right cell's column index is different it means that there are rowspanned cells between them.\n\treturn cellsAreTouching ? horizontalCell : undefined;\n}\n\n// Returns the cell that can be merged vertically.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @param {String} direction\n// @returns {module:engine/model/node~Node|null}\nfunction getVerticalCell( tableCell, direction ) {\n\tconst tableRow = tableCell.parent;\n\tconst table = tableRow.parent;\n\n\tconst rowIndex = table.getChildIndex( tableRow );\n\n\t// Don't search for mergeable cell if direction points out of the table.\n\tif ( ( direction == 'down' && rowIndex === table.childCount - 1 ) || ( direction == 'up' && rowIndex === 0 ) ) {\n\t\treturn;\n\t}\n\n\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\tconst isMergeWithBodyCell = direction == 'down' && ( rowIndex + rowspan ) === headingRows;\n\tconst isMergeWithHeadCell = direction == 'up' && rowIndex === headingRows;\n\n\t// Don't search for mergeable cell if direction points out of the current table section.\n\tif ( headingRows && ( isMergeWithBodyCell || isMergeWithHeadCell ) ) {\n\t\treturn;\n\t}\n\n\tconst currentCellRowSpan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\tconst rowOfCellToMerge = direction == 'down' ? rowIndex + currentCellRowSpan : rowIndex;\n\n\tconst tableMap = [ ...new TableWalker( table, { endRow: rowOfCellToMerge } ) ];\n\n\tconst currentCellData = tableMap.find( value => value.cell === tableCell );\n\tconst mergeColumn = currentCellData.column;\n\n\tconst cellToMergeData = tableMap.find( ( { row, rowspan, column } ) => {\n\t\tif ( column !== mergeColumn ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( direction == 'down' ) {\n\t\t\t// If merging a cell below the mergeRow is already calculated.\n\t\t\treturn row === rowOfCellToMerge;\n\t\t} else {\n\t\t\t// If merging a cell above calculate if it spans to mergeRow.\n\t\t\treturn rowOfCellToMerge === row + rowspan;\n\t\t}\n\t} );\n\n\treturn cellToMergeData && cellToMergeData.cell;\n}\n\n// Properly removes an empty row from a table. It will update the `rowspan` attribute of cells that overlap the removed row.\n//\n// @param {module:engine/model/element~Element} removedTableCellRow\n// @param {module:engine/model/writer~Writer} writer\nfunction removeEmptyRow( removedTableCellRow, writer ) {\n\tconst table = removedTableCellRow.parent;\n\n\tconst removedRowIndex = table.getChildIndex( removedTableCellRow );\n\n\tfor ( const { cell, row, rowspan } of new TableWalker( table, { endRow: removedRowIndex } ) ) {\n\t\tconst overlapsRemovedRow = row + rowspan - 1 >= removedRowIndex;\n\n\t\tif ( overlapsRemovedRow ) {\n\t\t\tupdateNumericAttribute( 'rowspan', rowspan - 1, cell, writer );\n\t\t}\n\t}\n\n\twriter.remove( removedTableCellRow );\n}\n\n// Merges two table cells. It will ensure that after merging cells with an empty paragraph, the resulting table cell will only have one\n// paragraph. If one of the merged table cell is empty, the merged table cell will have the contents of the non-empty table cell.\n// If both are empty, the merged table cell will have only one empty paragraph.\n//\n// @param {module:engine/model/element~Element} cellToRemove\n// @param {module:engine/model/element~Element} cellToExpand\n// @param {module:engine/model/writer~Writer} writer\nfunction mergeTableCells( cellToRemove, cellToExpand, writer ) {\n\tif ( !isEmpty( cellToRemove ) ) {\n\t\tif ( isEmpty( cellToExpand ) ) {\n\t\t\twriter.remove( writer.createRangeIn( cellToExpand ) );\n\t\t}\n\n\t\twriter.move( writer.createRangeIn( cellToRemove ), writer.createPositionAt( cellToExpand, 'end' ) );\n\t}\n\n\t// Remove merged table cell.\n\twriter.remove( cellToRemove );\n}\n\n// Checks if the passed table cell contains an empty paragraph.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @returns {Boolean}\nfunction isEmpty( tableCell ) {\n\treturn tableCell.childCount == 1 && tableCell.getChild( 0 ).is( 'paragraph' ) && tableCell.getChild( 0 ).isEmpty;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/commands/removerowcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport TableWalker from '../tablewalker';\nimport { findAncestor, updateNumericAttribute } from './utils';\n\n/**\n * The remove row command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'removeTableRow'` editor command.\n *\n * To remove the row containing the selected cell, execute the command:\n *\n *\t\teditor.execute( 'removeTableRow' );\n *\n * @extends module:core/command~Command\n */\nexport default class RemoveRowCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tconst tableCell = findAncestor( 'tableCell', doc.selection.getFirstPosition() );\n\n\t\tthis.isEnabled = !!tableCell && tableCell.parent.parent.childCount > 1;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\n\t\tconst firstPosition = selection.getFirstPosition();\n\t\tconst tableCell = findAncestor( 'tableCell', firstPosition );\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst currentRow = table.getChildIndex( tableRow );\n\t\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( headingRows && currentRow <= headingRows ) {\n\t\t\t\tupdateNumericAttribute( 'headingRows', headingRows - 1, table, writer, 0 );\n\t\t\t}\n\n\t\t\tconst tableMap = [ ...new TableWalker( table, { endRow: currentRow } ) ];\n\n\t\t\tconst cellsToMove = new Map();\n\n\t\t\t// Get cells from removed row that are spanned over multiple rows.\n\t\t\ttableMap\n\t\t\t\t.filter( ( { row, rowspan } ) => row === currentRow && rowspan > 1 )\n\t\t\t\t.forEach( ( { column, cell, rowspan } ) => cellsToMove.set( column, { cell, rowspanToSet: rowspan - 1 } ) );\n\n\t\t\t// Reduce rowspan on cells that are above removed row and overlaps removed row.\n\t\t\ttableMap\n\t\t\t\t.filter( ( { row, rowspan } ) => row <= currentRow - 1 && row + rowspan > currentRow )\n\t\t\t\t.forEach( ( { cell, rowspan } ) => updateNumericAttribute( 'rowspan', rowspan - 1, cell, writer ) );\n\n\t\t\t// Move cells to another row.\n\t\t\tconst targetRow = currentRow + 1;\n\t\t\tconst tableWalker = new TableWalker( table, { includeSpanned: true, startRow: targetRow, endRow: targetRow } );\n\n\t\t\tlet previousCell;\n\n\t\t\tfor ( const { row, column, cell } of [ ...tableWalker ] ) {\n\t\t\t\tif ( cellsToMove.has( column ) ) {\n\t\t\t\t\tconst { cell: cellToMove, rowspanToSet } = cellsToMove.get( column );\n\t\t\t\t\tconst targetPosition = previousCell ?\n\t\t\t\t\t\twriter.createPositionAfter( previousCell ) :\n\t\t\t\t\t\twriter.createPositionAt( table.getChild( row ), 0 );\n\n\t\t\t\t\twriter.move( writer.createRangeOn( cellToMove ), targetPosition );\n\t\t\t\t\tupdateNumericAttribute( 'rowspan', rowspanToSet, cellToMove, writer );\n\n\t\t\t\t\tpreviousCell = cellToMove;\n\t\t\t\t} else {\n\t\t\t\t\tpreviousCell = cell;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\twriter.remove( tableRow );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/commands/removecolumncommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport TableWalker from '../tablewalker';\nimport { findAncestor, updateNumericAttribute } from './utils';\n\n/**\n * The remove column command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'removeTableColumn'` editor command.\n *\n * To remove the column containing the selected cell, execute the command:\n *\n *\t\teditor.execute( 'removeTableColumn' );\n *\n * @extends module:core/command~Command\n */\nexport default class RemoveColumnCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst tableUtils = editor.plugins.get( 'TableUtils' );\n\n\t\tconst tableCell = findAncestor( 'tableCell', selection.getFirstPosition() );\n\n\t\tthis.isEnabled = !!tableCell && tableUtils.getColumns( tableCell.parent.parent ) > 1;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\n\t\tconst firstPosition = selection.getFirstPosition();\n\n\t\tconst tableCell = findAncestor( 'tableCell', firstPosition );\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst headingColumns = table.getAttribute( 'headingColumns' ) || 0;\n\t\tconst row = table.getChildIndex( tableRow );\n\n\t\t// Cache the table before removing or updating colspans.\n\t\tconst tableMap = [ ...new TableWalker( table ) ];\n\n\t\t// Get column index of removed column.\n\t\tconst cellData = tableMap.find( value => value.cell === tableCell );\n\t\tconst removedColumn = cellData.column;\n\n\t\tmodel.change( writer => {\n\t\t\t// Update heading columns attribute if removing a row from head section.\n\t\t\tif ( headingColumns && row <= headingColumns ) {\n\t\t\t\twriter.setAttribute( 'headingColumns', headingColumns - 1, table );\n\t\t\t}\n\n\t\t\tfor ( const { cell, column, colspan } of tableMap ) {\n\t\t\t\t// If colspaned cell overlaps removed column decrease it's span.\n\t\t\t\tif ( column <= removedColumn && colspan > 1 && column + colspan > removedColumn ) {\n\t\t\t\t\tupdateNumericAttribute( 'colspan', colspan - 1, cell, writer );\n\t\t\t\t} else if ( column === removedColumn ) {\n\t\t\t\t\t// The cell in removed column has colspan of 1.\n\t\t\t\t\twriter.remove( cell );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/commands/setheaderrowcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport { createEmptyTableCell, findAncestor, updateNumericAttribute } from './utils';\nimport TableWalker from '../tablewalker';\n\n/**\n * The header row command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'setTableColumnHeader'` editor command.\n *\n * You can make the row containing the selected cell a [header](https://www.w3.org/TR/html50/tabular-data.html#the-th-element) by executing:\n *\n *\t\teditor.execute( 'setTableRowHeader' );\n *\n * **Note:** All preceding rows will also become headers. If the current row is already a header, executing this command\n * will make it a regular row back again (including the following rows).\n *\n * @extends module:core/command~Command\n */\nexport default class SetHeaderRowCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\n\t\tconst position = selection.getFirstPosition();\n\t\tconst tableCell = findAncestor( 'tableCell', position );\n\t\tconst isInTable = !!tableCell;\n\n\t\tthis.isEnabled = isInTable;\n\n\t\t/**\n\t\t * Flag indicating whether the command is active. The command is active when the\n\t\t * {@link module:engine/model/selection~Selection} is in a header row.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #value\n\t\t */\n\t\tthis.value = isInTable && this._isInHeading( tableCell, tableCell.parent.parent );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * When the selection is in a non-header row, the command will set the `headingRows` table attribute to cover that row.\n\t *\n\t * When the selection is already in a header row, it will set `headingRows` so the heading section will end before that row.\n\t *\n\t * @fires execute\n\t * @param {Object} options\n\t * @param {Boolean} [options.forceValue] If set, the command will set (`true`) or unset (`false`) the header rows according to\n\t * the `forceValue` parameter instead of the current model state.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\n\t\tconst position = selection.getFirstPosition();\n\t\tconst tableCell = findAncestor( 'tableCell', position );\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst currentHeadingRows = table.getAttribute( 'headingRows' ) || 0;\n\t\tconst selectionRow = tableRow.index;\n\n\t\tif ( options.forceValue === this.value ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst headingRowsToSet = this.value ? selectionRow : selectionRow + 1;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( headingRowsToSet ) {\n\t\t\t\t// Changing heading rows requires to check if any of a heading cell is overlapping vertically the table head.\n\t\t\t\t// Any table cell that has a rowspan attribute > 1 will not exceed the table head so we need to fix it in rows below.\n\t\t\t\tconst cellsToSplit = getOverlappingCells( table, headingRowsToSet, currentHeadingRows );\n\n\t\t\t\tfor ( const cell of cellsToSplit ) {\n\t\t\t\t\tsplitHorizontally( cell, headingRowsToSet, writer );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdateNumericAttribute( 'headingRows', headingRowsToSet, table, writer, 0 );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks if a table cell is in the heading section.\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @param {module:engine/model/element~Element} table\n\t * @returns {Boolean}\n\t * @private\n\t */\n\t_isInHeading( tableCell, table ) {\n\t\tconst headingRows = parseInt( table.getAttribute( 'headingRows' ) || 0 );\n\n\t\treturn !!headingRows && tableCell.parent.index < headingRows;\n\t}\n}\n\n// Returns cells that span beyond the new heading section.\n//\n// @param {module:engine/model/element~Element} table The table to check.\n// @param {Number} headingRowsToSet New heading rows attribute.\n// @param {Number} currentHeadingRows Current heading rows attribute.\n// @returns {Array.<module:engine/model/element~Element>}\nfunction getOverlappingCells( table, headingRowsToSet, currentHeadingRows ) {\n\tconst cellsToSplit = [];\n\n\tconst startAnalysisRow = headingRowsToSet > currentHeadingRows ? currentHeadingRows : 0;\n\t// We're analyzing only when headingRowsToSet > 0.\n\tconst endAnalysisRow = headingRowsToSet - 1;\n\n\tconst tableWalker = new TableWalker( table, { startRow: startAnalysisRow, endRow: endAnalysisRow } );\n\n\tfor ( const { row, rowspan, cell } of tableWalker ) {\n\t\tif ( rowspan > 1 && row + rowspan > headingRowsToSet ) {\n\t\t\tcellsToSplit.push( cell );\n\t\t}\n\t}\n\n\treturn cellsToSplit;\n}\n\n// Splits the table cell horizontally.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @param {Number} headingRows\n// @param {module:engine/model/writer~Writer} writer\nfunction splitHorizontally( tableCell, headingRows, writer ) {\n\tconst tableRow = tableCell.parent;\n\tconst table = tableRow.parent;\n\tconst rowIndex = tableRow.index;\n\n\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) );\n\tconst newRowspan = headingRows - rowIndex;\n\n\tconst attributes = {};\n\n\tconst spanToSet = rowspan - newRowspan;\n\n\tif ( spanToSet > 1 ) {\n\t\tattributes.rowspan = spanToSet;\n\t}\n\n\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\tif ( colspan > 1 ) {\n\t\tattributes.colspan = colspan;\n\t}\n\n\tconst startRow = table.getChildIndex( tableRow );\n\tconst endRow = startRow + newRowspan;\n\tconst tableMap = [ ...new TableWalker( table, { startRow, endRow, includeSpanned: true } ) ];\n\n\tlet columnIndex;\n\n\tfor ( const { row, column, cell, cellIndex } of tableMap ) {\n\t\tif ( cell === tableCell && columnIndex === undefined ) {\n\t\t\tcolumnIndex = column;\n\t\t}\n\n\t\tif ( columnIndex !== undefined && columnIndex === column && row === endRow ) {\n\t\t\tconst tableRow = table.getChild( row );\n\t\t\tconst tableCellPosition = writer.createPositionAt( tableRow, cellIndex );\n\n\t\t\tcreateEmptyTableCell( writer, tableCellPosition, attributes );\n\t\t}\n\t}\n\n\t// Update the rowspan attribute after updating table.\n\tupdateNumericAttribute( 'rowspan', newRowspan, tableCell, writer );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/commands/setheadercolumncommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport { findAncestor, updateNumericAttribute } from './utils';\n\n/**\n * The header column command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'setTableColumnHeader'` editor command.\n *\n * You can make the column containing the selected cell a [header](https://www.w3.org/TR/html50/tabular-data.html#the-th-element)\n * by executing:\n *\n *\t\teditor.execute( 'setTableColumnHeader' );\n *\n * **Note:** All preceding columns will also become headers. If the current column is already a header, executing this command\n * will make it a regular column back again (including the following columns).\n *\n * @extends module:core/command~Command\n */\nexport default class SetHeaderColumnCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\n\t\tconst position = selection.getFirstPosition();\n\t\tconst tableCell = findAncestor( 'tableCell', position );\n\n\t\tconst isInTable = !!tableCell;\n\n\t\tthis.isEnabled = isInTable;\n\n\t\t/**\n\t\t * Flag indicating whether the command is active. The command is active when the\n\t\t * {@link module:engine/model/selection~Selection} is in a header column.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #value\n\t\t */\n\t\tthis.value = isInTable && this._isInHeading( tableCell, tableCell.parent.parent );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * When the selection is in a non-header column, the command will set the `headingColumns` table attribute to cover that column.\n\t *\n\t * When the selection is already in a header column, it will set `headingColumns` so the heading section will end before that column.\n\t *\n\t * @fires execute\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.forceValue] If set, the command will set (`true`) or unset (`false`) the header columns according to\n\t * the `forceValue` parameter instead of the current model state.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\tconst position = selection.getFirstPosition();\n\t\tconst tableCell = findAncestor( 'tableCell', position );\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst { column: selectionColumn } = tableUtils.getCellLocation( tableCell );\n\n\t\tif ( options.forceValue === this.value ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst headingColumnsToSet = this.value ? selectionColumn : selectionColumn + 1;\n\n\t\tmodel.change( writer => {\n\t\t\tupdateNumericAttribute( 'headingColumns', headingColumnsToSet, table, writer, 0 );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks if a table cell is in the heading section.\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @param {module:engine/model/element~Element} table\n\t * @returns {Boolean}\n\t * @private\n\t */\n\t_isInHeading( tableCell, table ) {\n\t\tconst headingColumns = parseInt( table.getAttribute( 'headingColumns' ) || 0 );\n\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\tconst { column } = tableUtils.getCellLocation( tableCell );\n\n\t\treturn !!headingColumns && column < headingColumns;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/tableutils\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport TableWalker from './tablewalker';\nimport { createEmptyTableCell, updateNumericAttribute } from './commands/utils';\n\n/**\n * The table utilities plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableUtils extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableUtils';\n\t}\n\n\t/**\n\t * Returns the table cell location as an object with table row and table column indexes.\n\t *\n\t * For instance, in the table below:\n\t *\n\t *\t\t 0 1 2 3\n\t *\t\t +---+---+---+---+\n\t *\t\t0 | a | b | c |\n\t *\t\t + + +---+\n\t *\t\t1 | | | d |\n\t *\t\t +---+---+ +---+\n\t *\t\t2 | e | | f |\n\t *\t\t +---+---+---+---+\n\t *\n\t * the method will return:\n\t *\n\t *\t\tconst cellA = table.getNodeByPath( [ 0, 0 ] );\n\t *\t\teditor.plugins.get( 'TableUtils' ).getCellLocation( cellA );\n\t *\t\t// will return { row: 0, column: 0 }\n\t *\n\t *\t\tconst cellD = table.getNodeByPath( [ 1, 0 ] );\n\t *\t\teditor.plugins.get( 'TableUtils' ).getCellLocation( cellD );\n\t *\t\t// will return { row: 1, column: 3 }\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @returns {Object} Returns a `{row, column}` object.\n\t */\n\tgetCellLocation( tableCell ) {\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst rowIndex = table.getChildIndex( tableRow );\n\n\t\tconst tableWalker = new TableWalker( table, { startRow: rowIndex, endRow: rowIndex } );\n\n\t\tfor ( const { cell, row, column } of tableWalker ) {\n\t\t\tif ( cell === tableCell ) {\n\t\t\t\treturn { row, column };\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates an empty table with a proper structure. The table needs to be inserted into the model,\n\t * for example, by using the {@link module:engine/model/model~Model#insertContent} function.\n\t *\n\t *\t\tmodel.change( ( writer ) => {\n\t *\t\t\t// Create a table of 2 rows and 7 columns:\n\t *\t\t\tconst table = tableUtils.createTable( writer, 2, 7);\n\t *\n\t *\t\t\t// Insert a table to the model at the best position taking the current selection:\n\t *\t\t\tmodel.insertContent( table );\n\t *\t\t}\n\t *\n\t * @param {module:engine/model/writer~Writer} writer The model writer.\n\t * @param {Number} rows The number of rows to create.\n\t * @param {Number} columns The number of columns to create.\n\t * @returns {module:engine/model/element~Element} The created table element.\n\t */\n\tcreateTable( writer, rows, columns ) {\n\t\tconst table = writer.createElement( 'table' );\n\n\t\tcreateEmptyRows( writer, table, 0, rows, columns );\n\n\t\treturn table;\n\t}\n\n\t/**\n\t * Inserts rows into a table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).insertRows( table, { at: 1, rows: 2 } );\n\t *\n\t * Assuming the table on the left, the above code will transform it to the table on the right:\n\t *\n\t *\t\trow index\n\t *\t\t 0 +---+---+---+ `at` = 1, +---+---+---+ 0\n\t *\t\t | a | b | c | `rows` = 2, | a | b | c |\n\t *\t\t 1 + +---+---+ <-- insert here + +---+---+ 1\n\t *\t\t | | d | e | | | | |\n\t *\t\t 2 + +---+---+ will give: + +---+---+ 2\n\t *\t\t | | f | g | | | | |\n\t *\t\t 3 +---+---+---+ + +---+---+ 3\n\t *\t\t | | d | e |\n\t *\t\t +---+---+---+ 4\n\t *\t\t + + f | g |\n\t *\t\t +---+---+---+ 5\n\t *\n\t * @param {module:engine/model/element~Element} table The table model element where the rows will be inserted.\n\t * @param {Object} options\n\t * @param {Number} [options.at=0] The row index at which the rows will be inserted.\n\t * @param {Number} [options.rows=1] The number of rows to insert.\n\t */\n\tinsertRows( table, options = {} ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst insertAt = options.at || 0;\n\t\tconst rowsToInsert = options.rows || 1;\n\n\t\tmodel.change( writer => {\n\t\t\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\t\t\t// Inserting rows inside heading section requires to update `headingRows` attribute as the heading section will grow.\n\t\t\tif ( headingRows > insertAt ) {\n\t\t\t\twriter.setAttribute( 'headingRows', headingRows + rowsToInsert, table );\n\t\t\t}\n\n\t\t\t// Inserting at the end and at the beginning of a table doesn't require to calculate anything special.\n\t\t\tif ( insertAt === 0 || insertAt === table.childCount ) {\n\t\t\t\tcreateEmptyRows( writer, table, insertAt, rowsToInsert, this.getColumns( table ) );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Iterate over all rows above inserted rows in order to check for rowspanned cells.\n\t\t\tconst tableIterator = new TableWalker( table, { endRow: insertAt } );\n\n\t\t\t// Will hold number of cells needed to insert in created rows.\n\t\t\t// The number might be different then table cell width when there are rowspanned cells.\n\t\t\tlet cellsToInsert = 0;\n\n\t\t\tfor ( const { row, rowspan, colspan, cell } of tableIterator ) {\n\t\t\t\tconst isBeforeInsertedRow = row < insertAt;\n\t\t\t\tconst overlapsInsertedRow = row + rowspan > insertAt;\n\n\t\t\t\tif ( isBeforeInsertedRow && overlapsInsertedRow ) {\n\t\t\t\t\t// This cell overlaps inserted rows so we need to expand it further.\n\t\t\t\t\twriter.setAttribute( 'rowspan', rowspan + rowsToInsert, cell );\n\t\t\t\t}\n\n\t\t\t\t// Calculate how many cells to insert based on the width of cells in a row at insert position.\n\t\t\t\t// It might be lower then table width as some cells might overlaps inserted row.\n\t\t\t\t// In the table above the cell 'a' overlaps inserted row so only two empty cells are need to be created.\n\t\t\t\tif ( row === insertAt ) {\n\t\t\t\t\tcellsToInsert += colspan;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcreateEmptyRows( writer, table, insertAt, rowsToInsert, cellsToInsert );\n\t\t} );\n\t}\n\n\t/**\n\t * Inserts columns into a table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).insertColumns( table, { at: 1, columns: 2 } );\n\t *\n\t * Assuming the table on the left, the above code will transform it to the table on the right:\n\t *\n\t *\t\t0 1 2 3 0 1 2 3 4 5\n\t *\t\t+---+---+---+ +---+---+---+---+---+\n\t *\t\t| a | b | | a | b |\n\t *\t\t+ +---+ + +---+\n\t *\t\t| | c | | | c |\n\t *\t\t+---+---+---+ will give: +---+---+---+---+---+\n\t *\t\t| d | e | f | | d | | | e | f |\n\t *\t\t+---+ +---+ +---+---+---+ +---+\n\t *\t\t| g | | h | | g | | | | h |\n\t *\t\t+---+---+---+ +---+---+---+---+---+\n\t *\t\t| i | | i |\n\t *\t\t+---+---+---+ +---+---+---+---+---+\n\t *\t\t ^---- insert here, `at` = 1, `columns` = 2\n\t *\n\t * @param {module:engine/model/element~Element} table The table model element where the columns will be inserted.\n\t * @param {Object} options\n\t * @param {Number} [options.at=0] The column index at which the columns will be inserted.\n\t * @param {Number} [options.columns=1] The number of columns to insert.\n\t */\n\tinsertColumns( table, options = {} ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst insertAt = options.at || 0;\n\t\tconst columnsToInsert = options.columns || 1;\n\n\t\tmodel.change( writer => {\n\t\t\tconst headingColumns = table.getAttribute( 'headingColumns' );\n\n\t\t\t// Inserting columns inside heading section requires to update `headingColumns` attribute as the heading section will grow.\n\t\t\tif ( insertAt < headingColumns ) {\n\t\t\t\twriter.setAttribute( 'headingColumns', headingColumns + columnsToInsert, table );\n\t\t\t}\n\n\t\t\tconst tableColumns = this.getColumns( table );\n\n\t\t\t// Inserting at the end and at the beginning of a table doesn't require to calculate anything special.\n\t\t\tif ( insertAt === 0 || tableColumns === insertAt ) {\n\t\t\t\tfor ( const tableRow of table.getChildren() ) {\n\t\t\t\t\tcreateCells( columnsToInsert, writer, writer.createPositionAt( tableRow, insertAt ? 'end' : 0 ) );\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst tableWalker = new TableWalker( table, { column: insertAt, includeSpanned: true } );\n\n\t\t\tfor ( const { row, cell, cellIndex } of tableWalker ) {\n\t\t\t\t// When iterating over column the table walker outputs either:\n\t\t\t\t// - cells at given column index (cell \"e\" from method docs),\n\t\t\t\t// - spanned columns (spanned cell from row between cells \"g\" and \"h\" - spanned by \"e\", only if `includeSpanned: true`),\n\t\t\t\t// - or a cell from the same row which spans over this column (cell \"a\").\n\n\t\t\t\tconst rowspan = parseInt( cell.getAttribute( 'rowspan' ) || 1 );\n\t\t\t\tconst colspan = parseInt( cell.getAttribute( 'colspan' ) || 1 );\n\n\t\t\t\tif ( cell.index !== insertAt && colspan > 1 ) {\n\t\t\t\t\t// If column is different than `insertAt`, it is a cell that spans over an inserted column (cell \"a\" & \"i\").\n\t\t\t\t\t// For such cells expand them by a number of columns inserted.\n\t\t\t\t\twriter.setAttribute( 'colspan', colspan + columnsToInsert, cell );\n\n\t\t\t\t\t// The `includeSpanned` option will output the \"empty\"/spanned column so skip this row already.\n\t\t\t\t\ttableWalker.skipRow( row );\n\n\t\t\t\t\t// This cell will overlap cells in rows below so skip them also (because of `includeSpanned` option) - (cell \"a\")\n\t\t\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t\t\tfor ( let i = row + 1; i < row + rowspan; i++ ) {\n\t\t\t\t\t\t\ttableWalker.skipRow( i );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// It's either cell at this column index or spanned cell by a rowspanned cell from row above.\n\t\t\t\t\t// In table above it's cell \"e\" and a spanned position from row below (empty cell between cells \"g\" and \"h\")\n\t\t\t\t\tconst insertPosition = writer.createPositionAt( table.getChild( row ), cellIndex );\n\n\t\t\t\t\tcreateCells( columnsToInsert, writer, insertPosition );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Divides a table cell vertically into several ones.\n\t *\n\t * The cell will be visually split into more cells by updating colspans of other cells in a column\n\t * and inserting cells (columns) after that cell.\n\t *\n\t * In the table below, if cell \"a\" is split into 3 cells:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+\n\t *\n\t * it will result in the table below:\n\t *\n\t *\t\t+---+---+---+---+---+\n\t *\t\t| a | | | b | c |\n\t *\t\t+---+---+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+---+---+\n\t *\n\t * So cell \"d\" will get its `colspan` updated to `3` and 2 cells will be added (2 columns will be created).\n\t *\n\t * Splitting a cell that already has a `colspan` attribute set will distribute the cell `colspan` evenly and the remainder\n\t * will be left to the original cell:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a |\n\t *\t\t+---+---+---+\n\t *\t\t| b | c | d |\n\t *\t\t+---+---+---+\n\t *\n\t * Splitting cell \"a\" with `colspan=3` into 2 cells will create 1 cell with a `colspan=a` and cell \"a\" that will have `colspan=2`:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | |\n\t *\t\t+---+---+---+\n\t *\t\t| b | c | d |\n\t *\t\t+---+---+---+\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @param {Number} numberOfCells\n\t */\n\tsplitCellVertically( tableCell, numberOfCells = 2 ) {\n\t\tconst model = this.editor.model;\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\t\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\t\tmodel.change( writer => {\n\t\t\t// First check - the cell spans over multiple rows so before doing anything else just split this cell.\n\t\t\tif ( colspan > 1 ) {\n\t\t\t\t// Get spans of new (inserted) cells and span to update of split cell.\n\t\t\t\tconst { newCellsSpan, updatedSpan } = breakSpanEvenly( colspan, numberOfCells );\n\n\t\t\t\tupdateNumericAttribute( 'colspan', updatedSpan, tableCell, writer );\n\n\t\t\t\t// Each inserted cell will have the same attributes:\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Do not store default value in the model.\n\t\t\t\tif ( newCellsSpan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.colspan = newCellsSpan;\n\t\t\t\t}\n\n\t\t\t\t// Copy rowspan of split cell.\n\t\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.rowspan = rowspan;\n\t\t\t\t}\n\n\t\t\t\tconst cellsToInsert = colspan > numberOfCells ? numberOfCells - 1 : colspan - 1;\n\t\t\t\tcreateCells( cellsToInsert, writer, writer.createPositionAfter( tableCell ), newCellsAttributes );\n\t\t\t}\n\n\t\t\t// Second check - the cell has colspan of 1 or we need to create more cells then the currently one spans over.\n\t\t\tif ( colspan < numberOfCells ) {\n\t\t\t\tconst cellsToInsert = numberOfCells - colspan;\n\n\t\t\t\t// First step: expand cells on the same column as split cell.\n\t\t\t\tconst tableMap = [ ...new TableWalker( table ) ];\n\n\t\t\t\t// Get the column index of split cell.\n\t\t\t\tconst { column: splitCellColumn } = tableMap.find( ( { cell } ) => cell === tableCell );\n\n\t\t\t\t// Find cells which needs to be expanded vertically - those on the same column or those that spans over split cell's column.\n\t\t\t\tconst cellsToUpdate = tableMap.filter( ( { cell, colspan, column } ) => {\n\t\t\t\t\tconst isOnSameColumn = cell !== tableCell && column === splitCellColumn;\n\t\t\t\t\tconst spansOverColumn = ( column < splitCellColumn && column + colspan > splitCellColumn );\n\n\t\t\t\t\treturn isOnSameColumn || spansOverColumn;\n\t\t\t\t} );\n\n\t\t\t\t// Expand cells vertically.\n\t\t\t\tfor ( const { cell, colspan } of cellsToUpdate ) {\n\t\t\t\t\twriter.setAttribute( 'colspan', colspan + cellsToInsert, cell );\n\t\t\t\t}\n\n\t\t\t\t// Second step: create columns after split cell.\n\n\t\t\t\t// Each inserted cell will have the same attributes:\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Do not store default value in the model.\n\n\t\t\t\t// Copy rowspan of split cell.\n\t\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.rowspan = rowspan;\n\t\t\t\t}\n\n\t\t\t\tcreateCells( cellsToInsert, writer, writer.createPositionAfter( tableCell ), newCellsAttributes );\n\n\t\t\t\tconst headingColumns = table.getAttribute( 'headingColumns' ) || 0;\n\n\t\t\t\t// Update heading section if split cell is in heading section.\n\t\t\t\tif ( headingColumns > splitCellColumn ) {\n\t\t\t\t\tupdateNumericAttribute( 'headingColumns', headingColumns + cellsToInsert, table, writer );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Divides a table cell horizontally into several ones.\n\t *\n\t * The cell will be visually split into more cells by updating rowspans of other cells in the row and inserting rows with a single cell\n\t * below.\n\t *\n\t * If in the table below cell \"b\" is split into 3 cells:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+\n\t *\n\t * It will result in the table below:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+ +---+ +\n\t *\t\t| | | |\n\t *\t\t+ +---+ +\n\t *\t\t| | | |\n\t *\t\t+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+\n\t *\n\t * So cells \"a\" and \"b\" will get their `rowspan` updated to `3` and 2 rows with a single cell will be added.\n\t *\n\t * Splitting a cell that already has a `rowspan` attribute set will distribute the cell `rowspan` evenly and the remainder\n\t * will be left to the original cell:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+ +---+---+\n\t *\t\t| | d | e |\n\t *\t\t+ +---+---+\n\t *\t\t| | f | g |\n\t *\t\t+ +---+---+\n\t *\t\t| | h | i |\n\t *\t\t+---+---+---+\n\t *\n\t * Splitting cell \"a\" with `rowspan=4` into 3 cells will create 2 cells with a `rowspan=1` and cell \"a\" will have `rowspan=2`:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+ +---+---+\n\t *\t\t| | d | e |\n\t *\t\t+---+---+---+\n\t *\t\t| | f | g |\n\t *\t\t+---+---+---+\n\t *\t\t| | h | i |\n\t *\t\t+---+---+---+\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @param {Number} numberOfCells\n\t */\n\tsplitCellHorizontally( tableCell, numberOfCells = 2 ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\t\tconst splitCellRow = table.getChildIndex( tableRow );\n\n\t\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\t\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\t\tmodel.change( writer => {\n\t\t\t// First check - the cell spans over multiple rows so before doing anything else just split this cell.\n\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t// Cache table map before updating table.\n\t\t\t\tconst tableMap = [ ...new TableWalker( table, {\n\t\t\t\t\tstartRow: splitCellRow,\n\t\t\t\t\tendRow: splitCellRow + rowspan - 1,\n\t\t\t\t\tincludeSpanned: true\n\t\t\t\t} ) ];\n\n\t\t\t\t// Get spans of new (inserted) cells and span to update of split cell.\n\t\t\t\tconst { newCellsSpan, updatedSpan } = breakSpanEvenly( rowspan, numberOfCells );\n\n\t\t\t\tupdateNumericAttribute( 'rowspan', updatedSpan, tableCell, writer );\n\n\t\t\t\tconst { column: cellColumn } = tableMap.find( ( { cell } ) => cell === tableCell );\n\n\t\t\t\t// Each inserted cell will have the same attributes:\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Do not store default value in the model.\n\t\t\t\tif ( newCellsSpan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.rowspan = newCellsSpan;\n\t\t\t\t}\n\n\t\t\t\t// Copy colspan of split cell.\n\t\t\t\tif ( colspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.colspan = colspan;\n\t\t\t\t}\n\n\t\t\t\tfor ( const { column, row, cellIndex } of tableMap ) {\n\t\t\t\t\t// As both newly created cells and the split cell might have rowspan,\n\t\t\t\t\t// the insertion of new cells must go to appropriate rows:\n\t\t\t\t\t//\n\t\t\t\t\t// 1. It's a row after split cell + it's height.\n\t\t\t\t\tconst isAfterSplitCell = row >= splitCellRow + updatedSpan;\n\t\t\t\t\t// 2. Is on the same column.\n\t\t\t\t\tconst isOnSameColumn = column === cellColumn;\n\t\t\t\t\t// 3. And it's row index is after previous cell height.\n\t\t\t\t\tconst isInEvenlySplitRow = ( row + splitCellRow + updatedSpan ) % newCellsSpan === 0;\n\n\t\t\t\t\tif ( isAfterSplitCell && isOnSameColumn && isInEvenlySplitRow ) {\n\t\t\t\t\t\tconst position = writer.createPositionAt( table.getChild( row ), cellIndex );\n\n\t\t\t\t\t\tcreateCells( 1, writer, position, newCellsAttributes );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Second check - the cell has rowspan of 1 or we need to create more cells than the current cell spans over.\n\t\t\tif ( rowspan < numberOfCells ) {\n\t\t\t\t// We already split the cell in check one so here we split to the remaining number of cells only.\n\t\t\t\tconst cellsToInsert = numberOfCells - rowspan;\n\n\t\t\t\t// This check is needed since we need to check if there are any cells from previous rows than spans over this cell's row.\n\t\t\t\tconst tableMap = [ ...new TableWalker( table, { startRow: 0, endRow: splitCellRow } ) ];\n\n\t\t\t\t// First step: expand cells.\n\t\t\t\tfor ( const { cell, rowspan, row } of tableMap ) {\n\t\t\t\t\t// Expand rowspan of cells that are either:\n\t\t\t\t\t// - on the same row as current cell,\n\t\t\t\t\t// - or are below split cell row and overlaps that row.\n\t\t\t\t\tif ( cell !== tableCell && row + rowspan > splitCellRow ) {\n\t\t\t\t\t\tconst rowspanToSet = rowspan + cellsToInsert;\n\n\t\t\t\t\t\twriter.setAttribute( 'rowspan', rowspanToSet, cell );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Second step: create rows with single cell below split cell.\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Copy colspan of split cell.\n\t\t\t\tif ( colspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.colspan = colspan;\n\t\t\t\t}\n\n\t\t\t\tcreateEmptyRows( writer, table, splitCellRow + 1, cellsToInsert, 1, newCellsAttributes );\n\n\t\t\t\t// Update heading section if split cell is in heading section.\n\t\t\t\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\t\t\t\tif ( headingRows > splitCellRow ) {\n\t\t\t\t\tupdateNumericAttribute( 'headingRows', headingRows + cellsToInsert, table, writer );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the number of columns for a given table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).getColumns( table );\n\t *\n\t * @param {module:engine/model/element~Element} table The table to analyze.\n\t * @returns {Number}\n\t */\n\tgetColumns( table ) {\n\t\t// Analyze first row only as all the rows should have the same width.\n\t\tconst row = table.getChild( 0 );\n\n\t\treturn [ ...row.getChildren() ].reduce( ( columns, row ) => {\n\t\t\tconst columnWidth = parseInt( row.getAttribute( 'colspan' ) || 1 );\n\n\t\t\treturn columns + columnWidth;\n\t\t}, 0 );\n\t}\n}\n\n// Creates empty rows at the given index in an existing table.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/element~Element} table\n// @param {Number} insertAt The row index of row insertion.\n// @param {Number} rows The number of rows to create.\n// @param {Number} tableCellToInsert The number of cells to insert in each row.\nfunction createEmptyRows( writer, table, insertAt, rows, tableCellToInsert, attributes = {} ) {\n\tfor ( let i = 0; i < rows; i++ ) {\n\t\tconst tableRow = writer.createElement( 'tableRow' );\n\n\t\twriter.insert( tableRow, table, insertAt );\n\n\t\tcreateCells( tableCellToInsert, writer, writer.createPositionAt( tableRow, 'end' ), attributes );\n\t}\n}\n\n// Creates cells at a given position.\n//\n// @param {Number} columns The number of columns to create\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/position~Position} insertPosition\nfunction createCells( cells, writer, insertPosition, attributes = {} ) {\n\tfor ( let i = 0; i < cells; i++ ) {\n\t\tcreateEmptyTableCell( writer, insertPosition, attributes );\n\t}\n}\n\n// Evenly distributes the span of a cell to a number of provided cells.\n// The resulting spans will always be integer values.\n//\n// For instance breaking a span of 7 into 3 cells will return:\n//\n//\t\t{ newCellsSpan: 2, updatedSpan: 3 }\n//\n// as two cells will have a span of 2 and the remainder will go the first cell so its span will change to 3.\n//\n// @param {Number} span The span value do break.\n// @param {Number} numberOfCells The number of resulting spans.\n// @returns {{newCellsSpan: Number, updatedSpan: Number}}\nfunction breakSpanEvenly( span, numberOfCells ) {\n\tif ( span < numberOfCells ) {\n\t\treturn { newCellsSpan: 1, updatedSpan: 1 };\n\t}\n\n\tconst newCellsSpan = Math.floor( span / numberOfCells );\n\tconst updatedSpan = ( span - newCellsSpan * numberOfCells ) + newCellsSpan;\n\n\treturn { newCellsSpan, updatedSpan };\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/converters/table-layout-post-fixer\n */\n\nimport { createEmptyTableCell, findAncestor, updateNumericAttribute } from './../commands/utils';\nimport TableWalker from './../tablewalker';\n\n/**\n * Injects a table layout post-fixer into the model.\n *\n * The role of the table layout post-fixer is to ensure that the table rows have the correct structure\n * after a {@link module:engine/model/model~Model#change `change()`} block was executed.\n *\n * The correct structure means that:\n *\n * * All table rows have the same size.\n * * None of the table cells extend vertically beyond their section (either header or body).\n * * A table cell has always at least one element as a child.\n *\n * If the table structure is not correct, the post-fixer will automatically correct it in two steps:\n *\n * 1. It will clip table cells that extend beyond their section.\n * 2. It will add empty table cells to the rows that are narrower than the widest table row.\n *\n * ## Clipping overlapping table cells\n *\n * Such situation may occur when pasting a table (or a part of a table) to the editor from external sources.\n *\n * For example, see the following table which has a cell (FOO) with the rowspan attribute (2):\n *\n *\t\t<table headingRows=\"1\">\n *\t\t\t<tableRow>\n *\t\t\t\t<tableCell rowspan=\"2\"><paragraph>FOO</paragraph></tableCell>\n *\t\t\t\t<tableCell colspan=\"2\"><paragraph>BAR</paragraph></tableCell>\n *\t\t\t</tableRow>\n *\t\t\t<tableRow>\n *\t\t\t\t<tableCell><paragraph>BAZ</paragraph></tableCell>\n *\t\t\t\t<tableCell><paragraph>XYZ</paragraph></tableCell>\n *\t\t\t</tableRow>\n *\t\t</table>\n *\n * It will be rendered in the view as:\n *\n *\t\t<table>\n *\t\t\t<thead>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td rowspan=\"2\">FOO</td>\n *\t\t\t\t\t<td colspan=\"2\">BAR</td>\n *\t\t\t\t</tr>\n *\t\t\t</thead>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>BAZ</td>\n *\t\t\t\t\t<td>XYZ</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * In the above example the table will be rendered as a table with two rows: one in the header and second one in the body.\n * The table cell (FOO) cannot span over multiple rows as it would extend from the header to the body section.\n * The `rowspan` attribute must be changed to (1). The value (1) is the default value of the `rowspan` attribute\n * so the `rowspan` attribute will be removed from the model.\n *\n * The table cell with BAZ in the content will be in the first column of the table.\n *\n * ## Adding missing table cells\n *\n * The table post-fixer will insert empty table cells to equalize table row sizes (the number of columns).\n * The size of a table row is calculated by counting column spans of table cells, both horizontal (from the same row) and\n * vertical (from the rows above).\n *\n * In the above example, the table row in the body section of the table is narrower then the row from the header: it has two cells\n * with the default colspan (1). The header row has one cell with colspan (1) and the second with colspan (2).\n * The table cell (FOO) does not extend beyond the head section (and as such will be fixed in the first step of this post-fixer).\n * The post-fixer will add a missing table cell to the row in the body section of the table.\n *\n * The table from the above example will be fixed and rendered to the view as below:\n *\n *\t\t<table>\n *\t\t\t<thead>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td rowspan=\"2\">FOO</td>\n *\t\t\t\t\t<td colspan=\"2\">BAR</td>\n *\t\t\t\t</tr>\n *\t\t\t</thead>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>BAZ</td>\n *\t\t\t\t\t<td>XYZ</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * ## Collaboration and undo - Expectations vs post-fixer results\n *\n * The table post-fixer only ensures proper structure without a deeper analysis of the nature of the change. As such, it might lead\n * to a structure which was not intended by the user. In particular, it will also fix undo steps (in conjunction with collaboration)\n * in which the editor content might not return to the original state.\n *\n * This will usually happen when one or more users change the size of the table.\n *\n * As an example see the table below:\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * and the user actions:\n *\n * 1. Both users have a table with two rows and two columns.\n * 2. User A adds a column at the end of the table. This will insert empty table cells to two rows.\n * 3. User B adds a row at the end of the table. This will insert a row with two empty table cells.\n * 4. Both users will have a table as below:\n *\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t\t<td>(empty, inserted by A)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t\t<td>(empty, inserted by A)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * The last row is shorter then others so the table post-fixer will add an empty row to the last row:\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t\t<td>(empty, inserted by A)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t\t<td>(empty, inserted by A)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by the post-fixer)</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * Unfortunately undo does not know the nature of the changes and depending on which user applies the post-fixer changes, undoing them\n * might lead to a broken table. If User B undoes inserting the column to the table, the undo engine will undo only the operations of\n * inserting empty cells to rows from the initial table state (row 1 and 2) but the cell in the post-fixed row will remain:\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by a post-fixer)</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * After undo, the table post-fixer will detect that two rows are shorter than others and will fix the table to:\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t\t<td>(empty, inserted by a post-fixer after undo)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t\t<td>(empty, inserted by a post-fixer after undo)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by a post-fixer)</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n * @param {module:engine/model/model~Model} model\n */\nexport default function injectTableLayoutPostFixer( model ) {\n\tmodel.document.registerPostFixer( writer => tableLayoutPostFixer( writer, model ) );\n}\n\n// The table layout post-fixer.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/model~Model} model\nfunction tableLayoutPostFixer( writer, model ) {\n\tconst changes = model.document.differ.getChanges();\n\n\tlet wasFixed = false;\n\n\t// Do not analyze the same table more then once - may happen for multiple changes in the same table.\n\tconst analyzedTables = new Set();\n\n\tfor ( const entry of changes ) {\n\t\tlet table;\n\n\t\tif ( entry.name == 'table' && entry.type == 'insert' ) {\n\t\t\ttable = entry.position.nodeAfter;\n\t\t}\n\n\t\t// Fix table on adding/removing table cells and rows.\n\t\tif ( entry.name == 'tableRow' || entry.name == 'tableCell' ) {\n\t\t\ttable = findAncestor( 'table', entry.position );\n\t\t}\n\n\t\t// Fix table on any table's attribute change - including attributes of table cells.\n\t\tif ( isTableAttributeEntry( entry ) ) {\n\t\t\ttable = findAncestor( 'table', entry.range.start );\n\t\t}\n\n\t\tif ( table && !analyzedTables.has( table ) ) {\n\t\t\t// Step 1: correct rowspans of table cells if necessary.\n\t\t\t// The wasFixed flag should be true if any of tables in batch was fixed - might be more then one.\n\t\t\twasFixed = fixTableCellsRowspan( table, writer ) || wasFixed;\n\t\t\t// Step 2: fix table rows sizes.\n\t\t\twasFixed = fixTableRowsSizes( table, writer ) || wasFixed;\n\n\t\t\tanalyzedTables.add( table );\n\t\t}\n\t}\n\n\treturn wasFixed;\n}\n\n// Fixes the invalid value of the `rowspan` attribute because a table cell cannot vertically extend beyond the table section it belongs to.\n//\n// @param {module:engine/model/element~Element} table\n// @param {module:engine/model/writer~Writer} writer\n// @returns {Boolean} Returns `true` if the table was fixed.\nfunction fixTableCellsRowspan( table, writer ) {\n\tlet wasFixed = false;\n\n\tconst cellsToTrim = findCellsToTrim( table );\n\n\tif ( cellsToTrim.length ) {\n\t\twasFixed = true;\n\n\t\tfor ( const data of cellsToTrim ) {\n\t\t\tupdateNumericAttribute( 'rowspan', data.rowspan, data.cell, writer, 1 );\n\t\t}\n\t}\n\n\treturn wasFixed;\n}\n\n// Makes all table rows in a table the same size.\n//\n// @param {module:engine/model/element~Element} table\n// @param {module:engine/model/writer~Writer} writer\n// @returns {Boolean} Returns `true` if the table was fixed.\nfunction fixTableRowsSizes( table, writer ) {\n\tlet wasFixed = false;\n\n\tconst rowsLengths = getRowsLengths( table );\n\tconst tableSize = rowsLengths[ 0 ];\n\n\tconst isValid = Object.values( rowsLengths ).every( length => length === tableSize );\n\n\tif ( !isValid ) {\n\t\tconst maxColumns = Object.values( rowsLengths ).reduce( ( prev, current ) => current > prev ? current : prev, 0 );\n\n\t\tfor ( const [ rowIndex, size ] of Object.entries( rowsLengths ) ) {\n\t\t\tconst columnsToInsert = maxColumns - size;\n\n\t\t\tif ( columnsToInsert ) {\n\t\t\t\tfor ( let i = 0; i < columnsToInsert; i++ ) {\n\t\t\t\t\tcreateEmptyTableCell( writer, writer.createPositionAt( table.getChild( rowIndex ), 'end' ) );\n\t\t\t\t}\n\n\t\t\t\twasFixed = true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn wasFixed;\n}\n\n// Searches for table cells that extend beyond the table section to which they belong to. It will return an array of objects\n// that stores table cells to be trimmed and the correct value of the `rowspan` attribute to set.\n//\n// @param {module:engine/model/element~Element} table\n// @returns {Array.<{{cell, rowspan}}>}\nfunction findCellsToTrim( table ) {\n\tconst headingRows = parseInt( table.getAttribute( 'headingRows' ) || 0 );\n\tconst maxRows = table.childCount;\n\n\tconst cellsToTrim = [];\n\n\tfor ( const { row, rowspan, cell } of new TableWalker( table ) ) {\n\t\t// Skip cells that do not expand over its row.\n\t\tif ( rowspan < 2 ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst isInHeader = row < headingRows;\n\n\t\t// Row limit is either end of header section or whole table as table body is after the header.\n\t\tconst rowLimit = isInHeader ? headingRows : maxRows;\n\n\t\t// If table cell expands over its limit reduce it height to proper value.\n\t\tif ( row + rowspan > rowLimit ) {\n\t\t\tconst newRowspan = rowLimit - row;\n\n\t\t\tcellsToTrim.push( { cell, rowspan: newRowspan } );\n\t\t}\n\t}\n\n\treturn cellsToTrim;\n}\n\n// Returns an object with lengths of rows assigned to the corresponding row index.\n//\n// @param {module:engine/model/element~Element} table\n// @returns {Object}\nfunction getRowsLengths( table ) {\n\tconst lengths = {};\n\n\tfor ( const { row } of new TableWalker( table, { includeSpanned: true } ) ) {\n\t\tif ( !lengths[ row ] ) {\n\t\t\tlengths[ row ] = 0;\n\t\t}\n\n\t\tlengths[ row ] += 1;\n\t}\n\n\treturn lengths;\n}\n\n// Checks if the differ entry for an attribute change is one of the table's attributes.\n//\n// @param entry\n// @returns {Boolean}\nfunction isTableAttributeEntry( entry ) {\n\tconst isAttributeType = entry.type === 'attribute';\n\tconst key = entry.attributeKey;\n\n\treturn isAttributeType && ( key === 'headingRows' || key === 'colspan' || key === 'rowspan' );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/converters/table-cell-paragraph-post-fixer\n */\n\n/**\n * Injects a table cell post-fixer into the model which inserts a `paragraph` element into empty table cells.\n *\n * A table cell must contain at least one block element as a child. An empty table cell will have an empty `paragraph` as a child.\n *\n *\t\t<table>\n *\t\t\t<tableRow>\n *\t\t\t\t<tableCell></tableCell>\n *\t\t\t</tableRow>\n *\t\t</table>\n *\n * Will be fixed to:\n *\n *\t\t<table>\n *\t\t\t<tableRow>\n *\t\t\t\t<tableCell><paragraph></paragraph></tableCell>\n *\t\t\t</tableRow>\n *\t\t</table>\n *\n * @param {module:engine/model/model~Model} model\n */\nexport default function injectTableCellParagraphPostFixer( model ) {\n\tmodel.document.registerPostFixer( writer => tableCellContentsPostFixer( writer, model ) );\n}\n\n// The table cell contents post-fixer.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/model~Model} model\nfunction tableCellContentsPostFixer( writer, model ) {\n\tconst changes = model.document.differ.getChanges();\n\n\tlet wasFixed = false;\n\n\tfor ( const entry of changes ) {\n\t\tif ( entry.type == 'insert' && entry.name == 'table' ) {\n\t\t\twasFixed = fixTable( entry.position.nodeAfter, writer ) || wasFixed;\n\t\t}\n\n\t\tif ( entry.type == 'insert' && entry.name == 'tableRow' ) {\n\t\t\twasFixed = fixTableRow( entry.position.nodeAfter, writer ) || wasFixed;\n\t\t}\n\n\t\tif ( entry.type == 'insert' && entry.name == 'tableCell' ) {\n\t\t\twasFixed = fixTableCellContent( entry.position.nodeAfter, writer ) || wasFixed;\n\t\t}\n\n\t\tif ( checkTableCellChange( entry ) ) {\n\t\t\twasFixed = fixTableCellContent( entry.position.parent, writer ) || wasFixed;\n\t\t}\n\t}\n\n\treturn wasFixed;\n}\n\n// Fixes all table cells in a table.\n//\n// @param {module:engine/model/element~Element} table\n// @param {module:engine/model/writer~Writer} writer\nfunction fixTable( table, writer ) {\n\tlet wasFixed = false;\n\n\tfor ( const row of table.getChildren() ) {\n\t\twasFixed = fixTableRow( row, writer ) || wasFixed;\n\t}\n\n\treturn wasFixed;\n}\n\n// Fixes all table cells in a table row.\n//\n// @param {module:engine/model/element~Element} tableRow\n// @param {module:engine/model/writer~Writer} writer\nfunction fixTableRow( tableRow, writer ) {\n\tlet wasFixed = false;\n\n\tfor ( const tableCell of tableRow.getChildren() ) {\n\t\twasFixed = fixTableCellContent( tableCell, writer ) || wasFixed;\n\t}\n\n\treturn wasFixed;\n}\n\n// Fixes all table cell content by:\n// - Adding a paragraph to a table cell without any child.\n// - Wrapping direct $text in a `<paragraph>`.\n//\n// @param {module:engine/model/element~Element} table\n// @param {module:engine/model/writer~Writer} writer\n// @returns {Boolean}\nfunction fixTableCellContent( tableCell, writer ) {\n\t// Insert paragraph to an empty table cell.\n\tif ( tableCell.childCount == 0 ) {\n\t\twriter.insertElement( 'paragraph', tableCell );\n\n\t\treturn true;\n\t}\n\n\t// Check table cell children for directly placed text nodes.\n\t// Temporary solution. See https://github.com/ckeditor/ckeditor5/issues/1464.\n\tconst textNodes = Array.from( tableCell.getChildren() ).filter( child => child.is( 'text' ) );\n\n\tfor ( const child of textNodes ) {\n\t\twriter.wrap( writer.createRangeOn( child ), 'paragraph' );\n\t}\n\n\t// Return true when there were text nodes to fix.\n\treturn !!textNodes.length;\n}\n\n// Checks if a differ change should fix the table cell. This happens on:\n// - Removing content from the table cell (i.e. `tableCell` can be left empty).\n// - Adding a text node directly into a table cell.\n//\n// @param {Object} differ change entry\n// @returns {Boolean}\nfunction checkTableCellChange( entry ) {\n\tif ( !entry.position || !entry.position.parent.is( 'tableCell' ) ) {\n\t\treturn false;\n\t}\n\n\treturn entry.type == 'insert' && entry.name == '$text' || entry.type == 'remove';\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/converters/table-cell-refresh-post-fixer\n */\n\n/**\n * Injects a table cell post-fixer into the model which marks the table cell in the differ to have it re-rendered.\n *\n * Model `paragraph` inside a table cell can be rendered as `<span>` or `<p>`. It is rendered as `<span>` if this is the only block\n * element in that table cell and it does not have any attributes. It is rendered as `<p>` otherwise.\n *\n * When table cell content changes, for example a second `paragraph` element is added, we need to ensure that the first `paragraph` is\n * re-rendered so it changes from `<span>` to `<p>`. The easiest way to do it is to re-render the entire table cell.\n *\n * @param {module:engine/model/model~Model} model\n */\nexport default function injectTableCellRefreshPostFixer( model ) {\n\tmodel.document.registerPostFixer( () => tableCellRefreshPostFixer( model ) );\n}\n\nfunction tableCellRefreshPostFixer( model ) {\n\tconst differ = model.document.differ;\n\n\t// Stores cells to be refreshed so the table cell will be refreshed once for multiple changes.\n\tconst cellsToRefresh = new Set();\n\n\tfor ( const change of differ.getChanges() ) {\n\t\tconst parent = change.type == 'insert' || change.type == 'remove' ? change.position.parent : change.range.start.parent;\n\n\t\tif ( parent.is( 'tableCell' ) && checkRefresh( parent, change.type ) ) {\n\t\t\tcellsToRefresh.add( parent );\n\t\t}\n\t}\n\n\tif ( cellsToRefresh.size ) {\n\t\tfor ( const tableCell of cellsToRefresh.values() ) {\n\t\t\tdiffer.refreshItem( tableCell );\n\t\t}\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// Checks if the model table cell requires refreshing to be re-rendered to a proper state in the view.\n//\n// This method detects changes that will require renaming `<span>` to `<p>` (or vice versa) in the view.\n//\n// This method is a simple heuristic that checks only a single change and will sometimes give a false positive result when multiple changes\n// will result in a state that does not require renaming in the view (but will be seen as requiring a refresh).\n//\n// For instance: A `<span>` should be renamed to `<p>` when adding an attribute to a `<paragraph>`.\n// But adding one attribute and removing another one will result in a false positive: the check for an added attribute will see one\n// attribute on a paragraph and will falsely qualify such change as adding an attribute to a paragraph without any attribute.\n//\n// @param {module:engine/model/element~Element} tableCell The table cell to check.\n// @param {String} type Type of change.\nfunction checkRefresh( tableCell, type ) {\n\tconst hasInnerParagraph = Array.from( tableCell.getChildren() ).some( child => child.is( 'paragraph' ) );\n\n\t// If there is no paragraph in table cell then the view doesn't require refreshing.\n\t//\n\t// Why? What we really want to achieve is to make all the old paragraphs (which weren't added in this batch) to be\n\t// converted once again, so that the paragraph-in-table-cell converter can correctly create a `<p>` or a `<span>` element.\n\t// If there are no paragraphs in the table cell, we don't care.\n\tif ( !hasInnerParagraph ) {\n\t\treturn false;\n\t}\n\n\t// For attribute change we only refresh if there is a single paragraph as in this case we may want to change existing `<span>` to `<p>`.\n\tif ( type == 'attribute' ) {\n\t\tconst attributesCount = Array.from( tableCell.getChild( 0 ).getAttributeKeys() ).length;\n\n\t\treturn tableCell.childCount === 1 && attributesCount < 2;\n\t}\n\n\t// For other changes (insert, remove) the `<span>` to `<p>` change is needed when:\n\t//\n\t// - another element is added to a single paragraph (childCount becomes >= 2)\n\t// - another element is removed and a single paragraph is left (childCount == 1)\n\treturn tableCell.childCount <= ( type == 'insert' ? 2 : 1 );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/tableediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport upcastTable, { upcastTableCell } from './converters/upcasttable';\nimport {\n\tdowncastInsertCell,\n\tdowncastInsertRow,\n\tdowncastInsertTable,\n\tdowncastRemoveRow,\n\tdowncastTableHeadingColumnsChange,\n\tdowncastTableHeadingRowsChange\n} from './converters/downcast';\n\nimport InsertTableCommand from './commands/inserttablecommand';\nimport InsertRowCommand from './commands/insertrowcommand';\nimport InsertColumnCommand from './commands/insertcolumncommand';\nimport SplitCellCommand from './commands/splitcellcommand';\nimport MergeCellCommand from './commands/mergecellcommand';\nimport RemoveRowCommand from './commands/removerowcommand';\nimport RemoveColumnCommand from './commands/removecolumncommand';\nimport SetHeaderRowCommand from './commands/setheaderrowcommand';\nimport SetHeaderColumnCommand from './commands/setheadercolumncommand';\nimport { findAncestor } from './commands/utils';\nimport TableUtils from '../src/tableutils';\n\nimport injectTableLayoutPostFixer from './converters/table-layout-post-fixer';\nimport injectTableCellParagraphPostFixer from './converters/table-cell-paragraph-post-fixer';\nimport injectTableCellRefreshPostFixer from './converters/table-cell-refresh-post-fixer';\n\nimport '../theme/tableediting.css';\n\n/**\n * The table editing feature.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableEditing';\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 schema = model.schema;\n\t\tconst conversion = editor.conversion;\n\n\t\tschema.register( 'table', {\n\t\t\tallowWhere: '$block',\n\t\t\tallowAttributes: [ 'headingRows', 'headingColumns' ],\n\t\t\tisLimit: true,\n\t\t\tisObject: true,\n\t\t\tisBlock: true\n\t\t} );\n\n\t\tschema.register( 'tableRow', {\n\t\t\tallowIn: 'table',\n\t\t\tisLimit: true\n\t\t} );\n\n\t\tschema.register( 'tableCell', {\n\t\t\tallowIn: 'tableRow',\n\t\t\tallowAttributes: [ 'colspan', 'rowspan' ],\n\t\t\tisLimit: true\n\t\t} );\n\n\t\t// Allow all $block content inside table cell.\n\t\tschema.extend( '$block', { allowIn: 'tableCell' } );\n\n\t\t// Disallow table in table.\n\t\tschema.addChildCheck( ( context, childDefinition ) => {\n\t\t\tif ( childDefinition.name == 'table' && Array.from( context.getNames() ).includes( 'table' ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} );\n\n\t\t// Table conversion.\n\t\tconversion.for( 'upcast' ).add( upcastTable() );\n\n\t\tconversion.for( 'editingDowncast' ).add( downcastInsertTable( { asWidget: true } ) );\n\t\tconversion.for( 'dataDowncast' ).add( downcastInsertTable() );\n\n\t\t// Table row conversion.\n\t\tconversion.for( 'upcast' ).elementToElement( { model: 'tableRow', view: 'tr' } );\n\n\t\tconversion.for( 'editingDowncast' ).add( downcastInsertRow( { asWidget: true } ) );\n\t\tconversion.for( 'dataDowncast' ).add( downcastInsertRow() );\n\t\tconversion.for( 'downcast' ).add( downcastRemoveRow() );\n\n\t\t// Table cell conversion.\n\t\tconversion.for( 'upcast' ).add( upcastTableCell( 'td' ) );\n\t\tconversion.for( 'upcast' ).add( upcastTableCell( 'th' ) );\n\n\t\tconversion.for( 'editingDowncast' ).add( downcastInsertCell( { asWidget: true } ) );\n\t\tconversion.for( 'dataDowncast' ).add( downcastInsertCell() );\n\n\t\t// Table attributes conversion.\n\t\tconversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );\n\t\tconversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );\n\n\t\t// Table heading rows and columns conversion.\n\t\tconversion.for( 'editingDowncast' ).add( downcastTableHeadingColumnsChange( { asWidget: true } ) );\n\t\tconversion.for( 'dataDowncast' ).add( downcastTableHeadingColumnsChange() );\n\t\tconversion.for( 'editingDowncast' ).add( downcastTableHeadingRowsChange( { asWidget: true } ) );\n\t\tconversion.for( 'dataDowncast' ).add( downcastTableHeadingRowsChange() );\n\n\t\t// Define all the commands.\n\t\teditor.commands.add( 'insertTable', new InsertTableCommand( editor ) );\n\t\teditor.commands.add( 'insertTableRowAbove', new InsertRowCommand( editor, { order: 'above' } ) );\n\t\teditor.commands.add( 'insertTableRowBelow', new InsertRowCommand( editor, { order: 'below' } ) );\n\t\teditor.commands.add( 'insertTableColumnLeft', new InsertColumnCommand( editor, { order: 'left' } ) );\n\t\teditor.commands.add( 'insertTableColumnRight', new InsertColumnCommand( editor, { order: 'right' } ) );\n\n\t\teditor.commands.add( 'removeTableRow', new RemoveRowCommand( editor ) );\n\t\teditor.commands.add( 'removeTableColumn', new RemoveColumnCommand( editor ) );\n\n\t\teditor.commands.add( 'splitTableCellVertically', new SplitCellCommand( editor, { direction: 'vertically' } ) );\n\t\teditor.commands.add( 'splitTableCellHorizontally', new SplitCellCommand( editor, { direction: 'horizontally' } ) );\n\n\t\teditor.commands.add( 'mergeTableCellRight', new MergeCellCommand( editor, { direction: 'right' } ) );\n\t\teditor.commands.add( 'mergeTableCellLeft', new MergeCellCommand( editor, { direction: 'left' } ) );\n\t\teditor.commands.add( 'mergeTableCellDown', new MergeCellCommand( editor, { direction: 'down' } ) );\n\t\teditor.commands.add( 'mergeTableCellUp', new MergeCellCommand( editor, { direction: 'up' } ) );\n\n\t\teditor.commands.add( 'setTableColumnHeader', new SetHeaderColumnCommand( editor ) );\n\t\teditor.commands.add( 'setTableRowHeader', new SetHeaderRowCommand( editor ) );\n\n\t\tinjectTableLayoutPostFixer( model );\n\t\tinjectTableCellRefreshPostFixer( model );\n\t\tinjectTableCellParagraphPostFixer( model );\n\n\t\t// Handle Tab key navigation.\n\t\tthis.editor.keystrokes.set( 'Tab', ( ...args ) => this._handleTabOnSelectedTable( ...args ), { priority: 'low' } );\n\t\tthis.editor.keystrokes.set( 'Tab', this._getTabHandler( true ), { priority: 'low' } );\n\t\tthis.editor.keystrokes.set( 'Shift+Tab', this._getTabHandler( false ), { priority: 'low' } );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableUtils ];\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:keydown keydown} events for the <kbd>Tab</kbd> key executed\n\t * when the table widget is selected.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} eventInfo\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t */\n\t_handleTabOnSelectedTable( domEventData, cancel ) {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\n\t\tif ( !selection.isCollapsed && selection.rangeCount === 1 && selection.getFirstRange().isFlat ) {\n\t\t\tconst selectedElement = selection.getSelectedElement();\n\n\t\t\tif ( !selectedElement || !selectedElement.is( 'table' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcancel();\n\n\t\t\teditor.model.change( writer => {\n\t\t\t\twriter.setSelection( writer.createRangeIn( selectedElement.getChild( 0 ).getChild( 0 ) ) );\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a handler for {@link module:engine/view/document~Document#event:keydown keydown} events for the <kbd>Tab</kbd> key executed\n\t * inside table cell.\n\t *\n\t * @private\n\t * @param {Boolean} isForward Whether this handler will move the selection to the next or the previous cell.\n\t */\n\t_getTabHandler( isForward ) {\n\t\tconst editor = this.editor;\n\n\t\treturn ( domEventData, cancel ) => {\n\t\t\tconst selection = editor.model.document.selection;\n\n\t\t\tconst firstPosition = selection.getFirstPosition();\n\n\t\t\tconst tableCell = findAncestor( 'tableCell', firstPosition );\n\n\t\t\tif ( !tableCell ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcancel();\n\n\t\t\tconst tableRow = tableCell.parent;\n\t\t\tconst table = tableRow.parent;\n\n\t\t\tconst currentRowIndex = table.getChildIndex( tableRow );\n\t\t\tconst currentCellIndex = tableRow.getChildIndex( tableCell );\n\n\t\t\tconst isFirstCellInRow = currentCellIndex === 0;\n\n\t\t\tif ( !isForward && isFirstCellInRow && currentRowIndex === 0 ) {\n\t\t\t\t// It's the first cell of the table - don't do anything (stay in the current position).\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst isLastCellInRow = currentCellIndex === tableRow.childCount - 1;\n\t\t\tconst isLastRow = currentRowIndex === table.childCount - 1;\n\n\t\t\tif ( isForward && isLastRow && isLastCellInRow ) {\n\t\t\t\teditor.execute( 'insertTableRowBelow' );\n\n\t\t\t\t// Check if the command actually added a row. If `insertTableRowBelow` execution didn't add a row (because it was disabled\n\t\t\t\t// or it got overwritten) do not change the selection.\n\t\t\t\tif ( currentRowIndex === table.childCount - 1 ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet cellToFocus;\n\n\t\t\t// Move to first cell in next row.\n\t\t\tif ( isForward && isLastCellInRow ) {\n\t\t\t\tconst nextRow = table.getChild( currentRowIndex + 1 );\n\n\t\t\t\tcellToFocus = nextRow.getChild( 0 );\n\t\t\t}\n\t\t\t// Move to last cell in a previous row.\n\t\t\telse if ( !isForward && isFirstCellInRow ) {\n\t\t\t\tconst previousRow = table.getChild( currentRowIndex - 1 );\n\n\t\t\t\tcellToFocus = previousRow.getChild( previousRow.childCount - 1 );\n\t\t\t}\n\t\t\t// Move to next/previous cell.\n\t\t\telse {\n\t\t\t\tcellToFocus = tableRow.getChild( currentCellIndex + ( isForward ? 1 : -1 ) );\n\t\t\t}\n\n\t\t\teditor.model.change( writer => {\n\t\t\t\twriter.setSelection( writer.createRangeIn( cellToFocus ) );\n\t\t\t} );\n\t\t};\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/ui/inserttableview\n */\n\nimport View from '@ckeditor/ckeditor5-ui/src/view';\n\nimport './../../theme/inserttable.css';\n\n/**\n * The table size view.\n *\n * It renders a 10x10 grid to choose the inserted table size.\n *\n * @extends module:ui/view~View\n * @implements module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable\n */\nexport default class InsertTableView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * A collection of table size box items.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this.createCollection();\n\n\t\t/**\n\t\t * The currently selected number of rows of the new table.\n\t\t *\n\t\t * @observable\n\t\t * @member {Number} #rows\n\t\t */\n\t\tthis.set( 'rows', 0 );\n\n\t\t/**\n\t\t * The currently selected number of columns of the new table.\n\t\t *\n\t\t * @observable\n\t\t * @member {Number} #columns\n\t\t */\n\t\tthis.set( 'columns', 0 );\n\n\t\t/**\n\t\t * The label text displayed under the boxes.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #label\n\t\t */\n\t\tthis.bind( 'label' )\n\t\t\t.to( this, 'columns', this, 'rows', ( columns, rows ) => `${ rows } × ${ columns }` );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [ 'ck' ]\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [ 'ck-insert-table-dropdown__grid' ]\n\t\t\t\t\t},\n\t\t\t\t\tchildren: this.items\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [ 'ck-insert-table-dropdown__label' ]\n\t\t\t\t\t},\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttext: bind.to( 'label' )\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t],\n\n\t\t\ton: {\n\t\t\t\tmousedown: bind.to( evt => {\n\t\t\t\t\tevt.preventDefault();\n\t\t\t\t} ),\n\n\t\t\t\tclick: bind.to( () => {\n\t\t\t\t\tthis.fire( 'execute' );\n\t\t\t\t} )\n\t\t\t}\n\t\t} );\n\n\t\t// Add grid boxes to table selection view.\n\t\tfor ( let index = 0; index < 100; index++ ) {\n\t\t\tconst boxView = new TableSizeGridBoxView();\n\n\t\t\t// Listen to box view 'over' event which indicates that mouse is over this box.\n\t\t\tboxView.on( 'over', () => {\n\t\t\t\t// Translate box index to the row & column index.\n\t\t\t\tconst row = Math.floor( index / 10 );\n\t\t\t\tconst column = index % 10;\n\n\t\t\t\t// As row & column indexes are zero-based transform it to number of selected rows & columns.\n\t\t\t\tthis.set( 'rows', row + 1 );\n\t\t\t\tthis.set( 'columns', column + 1 );\n\t\t\t} );\n\n\t\t\tthis.items.add( boxView );\n\t\t}\n\n\t\tthis.on( 'change:columns', () => {\n\t\t\tthis._highlightGridBoxes();\n\t\t} );\n\n\t\tthis.on( 'change:rows', () => {\n\t\t\tthis._highlightGridBoxes();\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tfocus() {\n\t\t// The dropdown panel expects DropdownPanelFocusable interface on views passed to dropdown panel. See #30.\n\t\t// The method should be implemented while working on keyboard support for this view. See #22.\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tfocusLast() {\n\t\t// The dropdown panel expects DropdownPanelFocusable interface on views passed to dropdown panel. See #30.\n\t\t// The method should be implemented while working on keyboard support for this view. See #22.\n\t}\n\n\t/**\n\t * Highlights grid boxes depending on rows and columns selected.\n\t *\n\t * @private\n\t */\n\t_highlightGridBoxes() {\n\t\tconst rows = this.rows;\n\t\tconst columns = this.columns;\n\n\t\tthis.items.map( ( boxView, index ) => {\n\t\t\t// Translate box index to the row & column index.\n\t\t\tconst itemRow = Math.floor( index / 10 );\n\t\t\tconst itemColumn = index % 10;\n\n\t\t\t// Grid box is highlighted when its row & column index belongs to selected number of rows & columns.\n\t\t\tconst isOn = itemRow < rows && itemColumn < columns;\n\n\t\t\tboxView.set( 'isOn', isOn );\n\t\t} );\n\t}\n}\n\n/**\n * A single grid box view element.\n *\n * This class is used to render the table size selection grid in {@link module:table/ui/inserttableview~InsertTableView}.\n *\n * @private\n */\nclass TableSizeGridBoxView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Controls whether the grid box view is \"on\".\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isOn\n\t\t */\n\t\tthis.set( 'isOn', false );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-insert-table-dropdown-grid-box',\n\t\t\t\t\tbind.if( 'isOn', 'ck-on' )\n\t\t\t\t]\n\t\t\t},\n\t\t\ton: {\n\t\t\t\tmouseover: bind.to( 'over' )\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module table/tableui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport {\n addListToDropdown,\n createDropdown\n} from '@ckeditor/ckeditor5-ui/src/dropdown/utils';\nimport Model from '@ckeditor/ckeditor5-ui/src/model';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport InsertTableView from './ui/inserttableview';\nimport tableIcon from './../theme/assets/icons/table.svg';\nimport tableColumnIcon from './../theme/assets/icons/table-column.svg';\nimport tableRowIcon from './../theme/assets/icons/table-row.svg';\nimport tableMergeCellIcon from './../theme/assets/icons/table-merge-cell.svg';\n/**\n * The table UI plugin. It introduces:\n *\n * * The `'insertTable'` dropdown,\n * * The `'tableColumn'` dropdown,\n * * The `'tableRow'` dropdown,\n * * The `'mergeTableCells'` dropdown.\n *\n * The `'tableColumn'`, `'tableRow'` and `'mergeTableCells'` dropdowns work best with {@link module:table/tabletoolbar~TableToolbar}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = this.editor.t;\n const contentLanguageDirection = editor.locale.contentLanguageDirection;\n const isContentLtr = contentLanguageDirection === 'ltr';\n editor.ui.componentFactory.add('insertTable', locale => {\n const command = editor.commands.get('insertTable');\n const dropdownView = createDropdown(locale);\n dropdownView.bind('isEnabled').to(command);\n // Decorate dropdown's button.\n dropdownView.buttonView.set({\n icon: tableIcon,\n label: t('ap'),\n tooltip: true\n });\n let insertTableView;\n dropdownView.on('change:isOpen', () => {\n if (insertTableView) {\n return;\n }\n // Prepare custom view for dropdown's panel.\n insertTableView = new InsertTableView(locale);\n dropdownView.panelView.children.add(insertTableView);\n insertTableView.delegate('execute').to(dropdownView);\n dropdownView.buttonView.on('open', () => {\n // Reset the chooser before showing it to the user.\n insertTableView.rows = 0;\n insertTableView.columns = 0;\n });\n dropdownView.on('execute', () => {\n editor.execute('insertTable', {\n rows: insertTableView.rows,\n columns: insertTableView.columns\n });\n editor.editing.view.focus();\n });\n });\n return dropdownView;\n });\n editor.ui.componentFactory.add('tableColumn', locale => {\n const options = [\n {\n type: 'switchbutton',\n model: {\n commandName: 'setTableColumnHeader',\n label: t('aq'),\n bindIsOn: true\n }\n },\n { type: 'separator' },\n {\n type: 'button',\n model: {\n commandName: isContentLtr ? 'insertTableColumnLeft' : 'insertTableColumnRight',\n label: t('ar')\n }\n },\n {\n type: 'button',\n model: {\n commandName: isContentLtr ? 'insertTableColumnRight' : 'insertTableColumnLeft',\n label: t('as')\n }\n },\n {\n type: 'button',\n model: {\n commandName: 'removeTableColumn',\n label: t('at')\n }\n }\n ];\n return this._prepareDropdown(t('au'), tableColumnIcon, options, locale);\n });\n editor.ui.componentFactory.add('tableRow', locale => {\n const options = [\n {\n type: 'switchbutton',\n model: {\n commandName: 'setTableRowHeader',\n label: t('av'),\n bindIsOn: true\n }\n },\n { type: 'separator' },\n {\n type: 'button',\n model: {\n commandName: 'insertTableRowBelow',\n label: t('aw')\n }\n },\n {\n type: 'button',\n model: {\n commandName: 'insertTableRowAbove',\n label: t('ax')\n }\n },\n {\n type: 'button',\n model: {\n commandName: 'removeTableRow',\n label: t('ay')\n }\n }\n ];\n return this._prepareDropdown(t('az'), tableRowIcon, options, locale);\n });\n editor.ui.componentFactory.add('mergeTableCells', locale => {\n const options = [\n {\n type: 'button',\n model: {\n commandName: 'mergeTableCellUp',\n label: t('ba')\n }\n },\n {\n type: 'button',\n model: {\n commandName: isContentLtr ? 'mergeTableCellRight' : 'mergeTableCellLeft',\n label: t('bb')\n }\n },\n {\n type: 'button',\n model: {\n commandName: 'mergeTableCellDown',\n label: t('bc')\n }\n },\n {\n type: 'button',\n model: {\n commandName: isContentLtr ? 'mergeTableCellLeft' : 'mergeTableCellRight',\n label: t('bd')\n }\n },\n { type: 'separator' },\n {\n type: 'button',\n model: {\n commandName: 'splitTableCellVertically',\n label: t('be')\n }\n },\n {\n type: 'button',\n model: {\n commandName: 'splitTableCellHorizontally',\n label: t('bf')\n }\n }\n ];\n return this._prepareDropdown(t('bg'), tableMergeCellIcon, options, locale);\n });\n }\n /**\n\t * Creates a dropdown view from a set of options.\n\t *\n\t * @private\n\t * @param {String} label The dropdown button label.\n\t * @param {String} icon An icon for the dropdown button.\n\t * @param {Array.<module:ui/dropdown/utils~ListDropdownItemDefinition>} options The list of options for the dropdown.\n\t * @param {module:utils/locale~Locale} locale\n\t * @returns {module:ui/dropdown/dropdownview~DropdownView}\n\t */\n _prepareDropdown(label, icon, options, locale) {\n const editor = this.editor;\n const dropdownView = createDropdown(locale);\n const commands = [];\n // Prepare dropdown list items for list dropdown.\n const itemDefinitions = new Collection();\n for (const option of options) {\n addListOption(option, editor, commands, itemDefinitions);\n }\n addListToDropdown(dropdownView, itemDefinitions, editor.ui.componentFactory);\n // Decorate dropdown's button.\n dropdownView.buttonView.set({\n label,\n icon,\n tooltip: true\n });\n // Make dropdown button disabled when all options are disabled.\n dropdownView.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled) => {\n return areEnabled.some(isEnabled => isEnabled);\n });\n this.listenTo(dropdownView, 'execute', evt => {\n editor.execute(evt.source.commandName);\n editor.editing.view.focus();\n });\n return dropdownView;\n }\n}\n// Adds an option to a list view.\n//\n// @param {module:table/tableui~DropdownOption} option A configuration option.\n// @param {module:core/editor/editor~Editor} editor\n// @param {Array.<module:core/command~Command>} commands The list of commands to update.\n// @param {Iterable.<module:ui/dropdown/utils~ListDropdownItemDefinition>} itemDefinitions\n// A collection of dropdown items to update with the given option.\nfunction addListOption(option, editor, commands, itemDefinitions) {\n const model = option.model = new Model(option.model);\n const {commandName, bindIsOn} = option.model;\n if (option.type === 'button' || option.type === 'switchbutton') {\n const command = editor.commands.get(commandName);\n commands.push(command);\n model.set({ commandName });\n model.bind('isEnabled').to(command);\n if (bindIsOn) {\n model.bind('isOn').to(command, 'value');\n }\n }\n model.set({ withText: true });\n itemDefinitions.add(option);\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3 6v3h4V6H3zm0 4v3h4v-3H3zm0 4v3h4v-3H3zm5 3h4v-3H8v3zm5 0h4v-3h-4v3zm4-4v-3h-4v3h4zm0-4V6h-4v3h4zm1.5 8a1.5 1.5 0 01-1.5 1.5H3A1.5 1.5 0 011.5 17V4c.222-.863 1.068-1.5 2-1.5h13c.932 0 1.778.637 2 1.5v13zM12 13v-3H8v3h4zm0-4V6H8v3h4z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2.5 1h15A1.5 1.5 0 0119 2.5v15a1.5 1.5 0 01-1.5 1.5h-15A1.5 1.5 0 011 17.5v-15A1.5 1.5 0 012.5 1zM2 2v16h16V2H2z\\\" opacity=\\\".6\\\"/><path d=\\\"M18 7v1H2V7h16zm0 5v1H2v-1h16z\\\" opacity=\\\".6\\\"/><path d=\\\"M14 1v18a1 1 0 01-1 1H7a1 1 0 01-1-1V1a1 1 0 011-1h6a1 1 0 011 1zm-2 1H8v4h4V2zm0 6H8v4h4V8zm0 6H8v4h4v-4z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2.5 1h15A1.5 1.5 0 0119 2.5v15a1.5 1.5 0 01-1.5 1.5h-15A1.5 1.5 0 011 17.5v-15A1.5 1.5 0 012.5 1zM2 2v16h16V2H2z\\\" opacity=\\\".6\\\"/><path d=\\\"M7 2h1v16H7V2zm5 0h1v16h-1V2z\\\" opacity=\\\".6\\\"/><path d=\\\"M1 6h18a1 1 0 011 1v6a1 1 0 01-1 1H1a1 1 0 01-1-1V7a1 1 0 011-1zm1 2v4h4V8H2zm6 0v4h4V8H8zm6 0v4h4V8h-4z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2.5 1h15A1.5 1.5 0 0119 2.5v15a1.5 1.5 0 01-1.5 1.5h-15A1.5 1.5 0 011 17.5v-15A1.5 1.5 0 012.5 1zM2 2v16h16V2H2z\\\" opacity=\\\".6\\\"/><path d=\\\"M7 2h1v16H7V2zm5 0h1v7h-1V2zm6 5v1H2V7h16zM8 12v1H2v-1h6z\\\" opacity=\\\".6\\\"/><path d=\\\"M7 7h12a1 1 0 011 1v11a1 1 0 01-1 1H7a1 1 0 01-1-1V8a1 1 0 011-1zm1 2v9h10V9H8z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/underline/underlineediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport AttributeCommand from '../attributecommand';\n\nconst UNDERLINE = 'underline';\n\n/**\n * The underline editing feature.\n *\n * It registers the `'underline'` command, the <kbd>Ctrl+U</kbd> keystroke\n * and introduces the `underline` attribute in the model which renders to the view as an `<u>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class UnderlineEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'UnderlineEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow strikethrough attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: UNDERLINE } );\n\t\teditor.model.schema.setAttributeProperties( UNDERLINE, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: UNDERLINE,\n\t\t\tview: 'u',\n\t\t\tupcastAlso: {\n\t\t\t\tstyles: {\n\t\t\t\t\t'text-decoration': 'underline'\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Create underline command.\n\t\teditor.commands.add( UNDERLINE, new AttributeCommand( editor, UNDERLINE ) );\n\n\t\t// Set the Ctrl+U keystroke.\n\t\teditor.keystrokes.set( 'CTRL+U', 'underline' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module basic-styles/underline/underlineui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport underlineIcon from '../../theme/assets/icons/underline.svg';\nconst UNDERLINE = 'underline';\n/**\n * The underline UI feature. It introduces the Underline button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class UnderlineUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n // Add bold button to feature components.\n editor.ui.componentFactory.add(UNDERLINE, locale => {\n const command = editor.commands.get(UNDERLINE);\n const view = new ButtonView(locale);\n view.set({\n label: t('f'),\n icon: underlineIcon,\n keystroke: 'CTRL+U',\n tooltip: true,\n isToggleable: true\n });\n view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n // Execute command.\n this.listenTo(view, 'execute', () => {\n editor.execute(UNDERLINE);\n editor.editing.view.focus();\n });\n return view;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3 18v-1.5h14V18zm2.2-8V3.6c0-.4.4-.6.8-.6.3 0 .7.2.7.6v6.2c0 2 1.3 2.8 3.2 2.8 1.9 0 3.4-.9 3.4-2.9V3.6c0-.3.4-.5.8-.5.3 0 .7.2.7.5V10c0 2.7-2.2 4-4.9 4-2.6 0-4.7-1.2-4.7-4z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/strikethrough/strikethroughediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport AttributeCommand from '../attributecommand';\n\nconst STRIKETHROUGH = 'strikethrough';\n\n/**\n * The strikethrough editing feature.\n *\n * It registers the `'strikethrough'` command, the <kbd>Ctrl+Shift+X</kbd> keystroke and introduces the\n * `strikethroughsthrough` attribute in the model which renders to the view\n * as a `<s>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class StrikethroughEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'StrikethroughEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow strikethrough attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: STRIKETHROUGH } );\n\t\teditor.model.schema.setAttributeProperties( STRIKETHROUGH, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: STRIKETHROUGH,\n\t\t\tview: 's',\n\t\t\tupcastAlso: [\n\t\t\t\t'del',\n\t\t\t\t'strike',\n\t\t\t\t{\n\t\t\t\t\tstyles: {\n\t\t\t\t\t\t'text-decoration': 'line-through'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t// Create strikethrough command.\n\t\teditor.commands.add( STRIKETHROUGH, new AttributeCommand( editor, STRIKETHROUGH ) );\n\n\t\t// Set the Ctrl+Shift+X keystroke.\n\t\teditor.keystrokes.set( 'CTRL+SHIFT+X', 'strikethrough' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module basic-styles/strikethrough/strikethroughui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport strikethroughIcon from '../../theme/assets/icons/strikethrough.svg';\nconst STRIKETHROUGH = 'strikethrough';\n/**\n * The strikethrough UI feature. It introduces the Strikethrough button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class StrikethroughUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n // Add strikethrough button to feature components.\n editor.ui.componentFactory.add(STRIKETHROUGH, locale => {\n const command = editor.commands.get(STRIKETHROUGH);\n const view = new ButtonView(locale);\n view.set({\n label: t('e'),\n icon: strikethroughIcon,\n keystroke: 'CTRL+SHIFT+X',\n tooltip: true,\n isToggleable: true\n });\n view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n // Execute command.\n this.listenTo(view, 'execute', () => {\n editor.execute(STRIKETHROUGH);\n editor.editing.view.focus();\n });\n return view;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M7 16.4c-.8-.4-1.5-.9-2.2-1.5a.6.6 0 01-.2-.5l.3-.6h1c1 1.2 2.1 1.7 3.7 1.7 1 0 1.8-.3 2.3-.6.6-.4.6-1.2.6-1.3.2-1.2-.9-2.1-.9-2.1h2.1c.3.7.4 1.2.4 1.7v.8l-.6 1.2c-.6.8-1.1 1-1.6 1.2a6 6 0 01-2.4.6c-1 0-1.8-.3-2.5-.6zM6.8 9L6 8.3c-.4-.5-.5-.8-.5-1.6 0-.7.1-1.3.5-1.8.4-.6 1-1 1.6-1.3a6.3 6.3 0 014.7 0 4 4 0 011.7 1l.3.7c0 .1.2.4-.2.7-.4.2-.9.1-1 0a3 3 0 00-1.2-1c-.4-.2-1-.3-2-.4-.7 0-1.4.2-2 .6-.8.6-1 .8-1 1.5 0 .8.5 1 1.2 1.5.6.4 1.1.7 1.9 1H6.8z\\\"/><path d=\\\"M3 10.5V9h14v1.5z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/code/codeediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport AttributeCommand from '../attributecommand';\n\nconst CODE = 'code';\n\n/**\n * The code editing feature.\n *\n * It registers the `'code'` command and introduces the `code` attribute in the model which renders to the view\n * as a `<code>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CodeEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CodeEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow code attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: CODE } );\n\t\teditor.model.schema.setAttributeProperties( CODE, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: CODE,\n\t\t\tview: 'code',\n\t\t\tupcastAlso: {\n\t\t\t\tstyles: {\n\t\t\t\t\t'word-wrap': 'break-word'\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Create code command.\n\t\teditor.commands.add( CODE, new AttributeCommand( editor, CODE ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module basic-styles/code/codeui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport codeIcon from '../../theme/assets/icons/code.svg';\nimport '../../theme/code.css';\nconst CODE = 'code';\n/**\n * The code UI feature. It introduces the Code button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CodeUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n // Add code button to feature components.\n editor.ui.componentFactory.add(CODE, locale => {\n const command = editor.commands.get(CODE);\n const view = new ButtonView(locale);\n view.set({\n label: t('i'),\n icon: codeIcon,\n tooltip: true,\n isToggleable: true\n });\n view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n // Execute command.\n this.listenTo(view, 'execute', () => {\n editor.execute(CODE);\n editor.editing.view.focus();\n });\n return view;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M12.5 5.7l5.2 3.9v1.3l-5.6 4c-.1.2-.3.2-.5.2-.3-.1-.6-.7-.6-1l.3-.4 4.7-3.5L11.5 7l-.2-.2c-.1-.3-.1-.6 0-.8.2-.2.5-.4.8-.4a.8.8 0 01.4.1zm-5.2 0L2 9.6v1.3l5.6 4c.1.2.3.2.5.2.3-.1.7-.7.6-1 0-.1 0-.3-.2-.4l-5-3.5L8.2 7l.2-.2c.1-.3.1-.6 0-.8-.2-.2-.5-.4-.8-.4a.8.8 0 00-.3.1z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/subscript/subscriptediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport AttributeCommand from '../attributecommand';\n\nconst SUBSCRIPT = 'subscript';\n\n/**\n * The subscript editing feature.\n *\n * It registers the `sub` command and introduces the `sub` attribute in the model which renders to the view\n * as a `<sub>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SubscriptEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'SubscriptEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\t// Allow sub attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: SUBSCRIPT } );\n\t\teditor.model.schema.setAttributeProperties( SUBSCRIPT, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\t// Build converter from model to view for data and editing pipelines.\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: SUBSCRIPT,\n\t\t\tview: 'sub',\n\t\t\tupcastAlso: [\n\t\t\t\t{\n\t\t\t\t\tstyles: {\n\t\t\t\t\t\t'vertical-align': 'sub'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t// Create sub command.\n\t\teditor.commands.add( SUBSCRIPT, new AttributeCommand( editor, SUBSCRIPT ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module basic-styles/subscript/subscriptui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport subscriptIcon from '../../theme/assets/icons/subscript.svg';\nconst SUBSCRIPT = 'subscript';\n/**\n * The subscript UI feature. It introduces the Subscript button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SubscriptUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n // Add subscript button to feature components.\n editor.ui.componentFactory.add(SUBSCRIPT, locale => {\n const command = editor.commands.get(SUBSCRIPT);\n const view = new ButtonView(locale);\n view.set({\n label: t('h'),\n icon: subscriptIcon,\n tooltip: true,\n isToggleable: true\n });\n view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n // Execute command.\n this.listenTo(view, 'execute', () => {\n editor.execute(SUBSCRIPT);\n editor.editing.view.focus();\n });\n return view;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M7.03 10.349l3.818-3.819a.8.8 0 111.132 1.132L8.16 11.48l3.819 3.818a.8.8 0 11-1.132 1.132L7.03 12.61l-3.818 3.82a.8.8 0 11-1.132-1.132L5.9 11.48 2.08 7.662A.8.8 0 113.212 6.53l3.818 3.82zm8.147 7.829h2.549c.254 0 .447.05.58.152a.49.49 0 01.201.413.54.54 0 01-.159.393c-.105.108-.266.162-.48.162h-3.594c-.245 0-.435-.066-.572-.197a.621.621 0 01-.205-.463c0-.114.044-.265.132-.453a1.62 1.62 0 01.288-.444c.433-.436.824-.81 1.172-1.122.348-.312.597-.517.747-.615.267-.183.49-.368.667-.553.177-.185.312-.375.405-.57.093-.194.139-.384.139-.57a1.008 1.008 0 00-.554-.917 1.197 1.197 0 00-.56-.133c-.426 0-.761.182-1.005.546a2.332 2.332 0 00-.164.39 1.609 1.609 0 01-.258.488c-.096.114-.237.17-.423.17a.558.558 0 01-.405-.156.568.568 0 01-.161-.427c0-.218.05-.446.151-.683.101-.238.252-.453.452-.646s.454-.349.762-.467a2.998 2.998 0 011.081-.178c.498 0 .923.076 1.274.228a1.916 1.916 0 011.004 1.032 1.984 1.984 0 01-.156 1.794c-.2.32-.405.572-.613.754-.208.182-.558.468-1.048.857-.49.39-.826.691-1.008.906a2.703 2.703 0 00-.24.309z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/superscript/superscriptediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport AttributeCommand from '../attributecommand';\n\nconst SUPERSCRIPT = 'superscript';\n\n/**\n * The superscript editing feature.\n *\n * It registers the `super` command and introduces the `super` attribute in the model which renders to the view\n * as a `<super>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SuperscriptEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'SuperscriptEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\t// Allow super attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: SUPERSCRIPT } );\n\t\teditor.model.schema.setAttributeProperties( SUPERSCRIPT, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\t// Build converter from model to view for data and editing pipelines.\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: SUPERSCRIPT,\n\t\t\tview: 'sup',\n\t\t\tupcastAlso: [\n\t\t\t\t{\n\t\t\t\t\tstyles: {\n\t\t\t\t\t\t'vertical-align': 'super'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t// Create super command.\n\t\teditor.commands.add( SUPERSCRIPT, new AttributeCommand( editor, SUPERSCRIPT ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module basic-styles/superscript/superscriptui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport superscriptIcon from '../../theme/assets/icons/superscript.svg';\nconst SUPERSCRIPT = 'superscript';\n/**\n * The superscript UI feature. It introduces the Superscript button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SuperscriptUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n // Add superscript button to feature components.\n editor.ui.componentFactory.add(SUPERSCRIPT, locale => {\n const command = editor.commands.get(SUPERSCRIPT);\n const view = new ButtonView(locale);\n view.set({\n label: t('j'),\n icon: superscriptIcon,\n tooltip: true,\n isToggleable: true\n });\n view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n // Execute command.\n this.listenTo(view, 'execute', () => {\n editor.execute(SUPERSCRIPT);\n editor.editing.view.focus();\n });\n return view;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M15.677 8.678h2.549c.254 0 .447.05.58.152a.49.49 0 01.201.413.54.54 0 01-.159.393c-.105.108-.266.162-.48.162h-3.594c-.245 0-.435-.066-.572-.197a.621.621 0 01-.205-.463c0-.114.044-.265.132-.453a1.62 1.62 0 01.288-.444c.433-.436.824-.81 1.172-1.122.348-.312.597-.517.747-.615.267-.183.49-.368.667-.553.177-.185.312-.375.405-.57.093-.194.139-.384.139-.57a1.008 1.008 0 00-.554-.917 1.197 1.197 0 00-.56-.133c-.426 0-.761.182-1.005.546a2.332 2.332 0 00-.164.39 1.609 1.609 0 01-.258.488c-.096.114-.237.17-.423.17a.558.558 0 01-.405-.156.568.568 0 01-.161-.427c0-.218.05-.446.151-.683.101-.238.252-.453.452-.646s.454-.349.762-.467a2.998 2.998 0 011.081-.178c.498 0 .923.076 1.274.228a1.916 1.916 0 011.004 1.032 1.984 1.984 0 01-.156 1.794c-.2.32-.405.572-.613.754-.208.182-.558.468-1.048.857-.49.39-.826.691-1.008.906a2.703 2.703 0 00-.24.309zM7.03 10.349l3.818-3.819a.8.8 0 111.132 1.132L8.16 11.48l3.819 3.818a.8.8 0 11-1.132 1.132L7.03 12.61l-3.818 3.82a.8.8 0 11-1.132-1.132L5.9 11.48 2.08 7.662A.8.8 0 113.212 6.53l3.818 3.82z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module remove-format/removeformatui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport removeFormatIcon from '../theme/assets/icons/remove-format.svg';\nconst REMOVE_FORMAT = 'removeFormat';\n/**\n * The remove format UI plugin. It registers the `'removeFormat'` button which can be\n * used in the toolbar.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class RemoveFormatUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'RemoveFormatUI';\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n editor.ui.componentFactory.add(REMOVE_FORMAT, locale => {\n const command = editor.commands.get(REMOVE_FORMAT);\n const view = new ButtonView(locale);\n view.set({\n label: t('ao'),\n icon: removeFormatIcon,\n tooltip: true\n });\n view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n // Execute the command.\n this.listenTo(view, 'execute', () => {\n editor.execute(REMOVE_FORMAT);\n editor.editing.view.focus();\n });\n return view;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M8.69 14.915c.053.052.173.083.36.093a.366.366 0 01.345.485l-.003.01a.738.738 0 01-.697.497h-2.67a.374.374 0 01-.353-.496l.013-.038a.681.681 0 01.644-.458c.197-.012.325-.043.386-.093a.28.28 0 00.072-.11L9.592 4.5H6.269c-.359-.017-.609.013-.75.09-.142.078-.289.265-.442.563-.192.29-.516.464-.864.464H4.17a.43.43 0 01-.407-.569L4.46 3h13.08l-.62 2.043a.81.81 0 01-.775.574h-.114a.486.486 0 01-.486-.486c.001-.284-.054-.464-.167-.54-.112-.076-.367-.106-.766-.091h-3.28l-2.68 10.257c-.006.074.007.127.038.158zM3 17h8a.5.5 0 110 1H3a.5.5 0 110-1zm11.299 1.17a.75.75 0 11-1.06-1.06l1.414-1.415-1.415-1.414a.75.75 0 011.06-1.06l1.415 1.414 1.414-1.415a.75.75 0 111.06 1.06l-1.413 1.415 1.414 1.415a.75.75 0 01-1.06 1.06l-1.415-1.414-1.414 1.414z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 remove-format/removeformatcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The remove format command.\n *\n * It is used by the {@link module:remove-format/removeformat~RemoveFormat remove format feature}\n * to clear the formatting in the selection.\n *\n *\t\teditor.execute( 'removeFormat' );\n *\n * @extends module:core/command~Command\n */\nexport default class RemoveFormatCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\n\t\tthis.isEnabled = !!first( this._getFormattingItems( model.document.selection, model.schema ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\n\t\tmodel.change( writer => {\n\t\t\tfor ( const item of this._getFormattingItems( model.document.selection, schema ) ) {\n\t\t\t\tif ( item.is( 'selection' ) ) {\n\t\t\t\t\tfor ( const attributeName of this._getFormattingAttributes( item, schema ) ) {\n\t\t\t\t\t\twriter.removeSelectionAttribute( attributeName );\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Workaround for items with multiple removable attributes. See\n\t\t\t\t\t// https://github.com/ckeditor/ckeditor5-remove-format/pull/1#pullrequestreview-220515609\n\t\t\t\t\tconst itemRange = writer.createRangeOn( item );\n\n\t\t\t\t\tfor ( const attributeName of this._getFormattingAttributes( item, schema ) ) {\n\t\t\t\t\t\twriter.removeAttribute( attributeName, itemRange );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns an iterable of items in a selection (including the selection itself) that have formatting model\n\t * attributes to be removed by the feature.\n\t *\n\t * @protected\n\t * @param {module:engine/model/documentselection~DocumentSelection} selection\n\t * @param {module:engine/model/schema~Schema} schema The schema describing the item.\n\t * @returns {Iterable.<module:engine/model/item~Item>|Iterable.<module:engine/model/documentselection~DocumentSelection>}\n\t */\n\t* _getFormattingItems( selection, schema ) {\n\t\tconst itemHasRemovableFormatting = item => {\n\t\t\treturn !!first( this._getFormattingAttributes( item, schema ) );\n\t\t};\n\n\t\tfor ( const curRange of selection.getRanges() ) {\n\t\t\tfor ( const item of curRange.getItems() ) {\n\t\t\t\tif ( itemHasRemovableFormatting( item ) ) {\n\t\t\t\t\tyield item;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Finally the selection might be formatted as well, so make sure to check it.\n\t\tif ( itemHasRemovableFormatting( selection ) ) {\n\t\t\tyield selection;\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterable of formatting attributes of a given model item.\n\t *\n\t * **Note:** Formatting items have the `isFormatting` property set to `true`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/item~Item|module:engine/model/documentselection~DocumentSelection} item\n\t * @param {module:engine/model/schema~Schema} schema The schema describing the item.\n\t * @returns {Iterable.<String>} The names of formatting attributes found in a given item.\n\t */\n\t* _getFormattingAttributes( item, schema ) {\n\t\tfor ( const [ attributeName ] of item.getAttributes() ) {\n\t\t\tconst attributeProperties = schema.getAttributeProperties( attributeName );\n\n\t\t\tif ( attributeProperties && attributeProperties.isFormatting ) {\n\t\t\t\tyield attributeName;\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 remove-format/removeformatediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport RemoveFormatCommand from './removeformatcommand';\n\n/**\n * The remove format editing plugin.\n *\n * It registers the {@link module:remove-format/removeformatcommand~RemoveFormatCommand removeFormat} command.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class RemoveFormatEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'RemoveFormatEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.commands.add( 'removeFormat', new RemoveFormatCommand( editor ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 horizontal-line/horizontallinecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { findOptimalInsertionPosition } from '@ckeditor/ckeditor5-widget/src/utils';\n\n/**\n * The horizontal line command.\n *\n * The command is registered by {@link module:horizontal-line/horizontallineediting~HorizontalLineEditing} as `'horizontalLine'`.\n *\n * To insert a horizontal line at the current selection, execute the command:\n *\n *\t\teditor.execute( 'horizontalLine' );\n *\n * @extends module:core/command~Command\n */\nexport default class HorizontalLineCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = isHorizontalLineAllowed( this.editor.model );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\n\t\tmodel.change( writer => {\n\t\t\tconst horizontalElement = writer.createElement( 'horizontalLine' );\n\n\t\t\tmodel.insertContent( horizontalElement );\n\n\t\t\tlet nextElement = horizontalElement.nextSibling;\n\n\t\t\t// Check whether an element next to the inserted horizontal line is defined and can contain a text.\n\t\t\tconst canSetSelection = nextElement && model.schema.checkChild( nextElement, '$text' );\n\n\t\t\t// If the element is missing, but a paragraph could be inserted next to the horizontal line, let's add it.\n\t\t\tif ( !canSetSelection && model.schema.checkChild( horizontalElement.parent, 'paragraph' ) ) {\n\t\t\t\tnextElement = writer.createElement( 'paragraph' );\n\n\t\t\t\tmodel.insertContent( nextElement, writer.createPositionAfter( horizontalElement ) );\n\t\t\t}\n\n\t\t\t// Put the selection inside the element, at the beginning.\n\t\t\tif ( nextElement ) {\n\t\t\t\twriter.setSelection( nextElement, 0 );\n\t\t\t}\n\t\t} );\n\t}\n}\n\n// Checks if the `horizontalLine` element can be inserted at the current model selection.\n//\n// @param {module:engine/model/model~Model} model\n// @returns {Boolean}\nfunction isHorizontalLineAllowed( model ) {\n\tconst schema = model.schema;\n\tconst selection = model.document.selection;\n\n\treturn isHorizontalLineAllowedInParent( selection, schema, model ) &&\n\t\t!checkSelectionOnObject( selection, schema );\n}\n\n// Checks if a horizontal line is allowed by the schema in the optimal insertion parent.\n//\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/model/model~Model} model Model instance.\n// @returns {Boolean}\nfunction isHorizontalLineAllowedInParent( selection, schema, model ) {\n\tconst parent = getInsertHorizontalLineParent( selection, model );\n\n\treturn schema.checkChild( parent, 'horizontalLine' );\n}\n\n// Checks if the selection is on object.\n//\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction checkSelectionOnObject( selection, schema ) {\n\tconst selectedElement = selection.getSelectedElement();\n\n\treturn selectedElement && schema.isObject( selectedElement );\n}\n\n// Returns a node that will be used to insert a horizontal line with `model.insertContent` to check if the horizontal line can be\n// placed there.\n//\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n// @param {module:engine/model/model~Model} model Model instance.\n// @returns {module:engine/model/element~Element}\nfunction getInsertHorizontalLineParent( selection, model ) {\n\tconst insertAt = findOptimalInsertionPosition( selection, model );\n\n\tconst parent = insertAt.parent;\n\n\tif ( parent.isEmpty && !parent.is( '$root' ) ) {\n\t\treturn parent.parent;\n\t}\n\n\treturn parent;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module horizontal-line/horizontallineediting\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport HorizontalLineCommand from './horizontallinecommand';\nimport { toWidget } from '@ckeditor/ckeditor5-widget/src/utils';\nimport '../theme/horizontalline.css';\n/**\n * The horizontal line editing feature.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HorizontalLineEditing extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'HorizontalLineEditing';\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const schema = editor.model.schema;\n const t = editor.t;\n const conversion = editor.conversion;\n schema.register('horizontalLine', {\n isObject: true,\n allowWhere: '$block'\n });\n conversion.for('dataDowncast').elementToElement({\n model: 'horizontalLine',\n view: (modelElement, viewWriter) => {\n return viewWriter.createEmptyElement('hr');\n }\n });\n conversion.for('editingDowncast').elementToElement({\n model: 'horizontalLine',\n view: (modelElement, viewWriter) => {\n const label = t('ak');\n const viewWrapper = viewWriter.createContainerElement('div');\n const viewHrElement = viewWriter.createEmptyElement('hr');\n viewWriter.addClass('ck-horizontal-line', viewWrapper);\n viewWriter.setCustomProperty('hr', true, viewWrapper);\n viewWriter.insert(viewWriter.createPositionAt(viewWrapper, 0), viewHrElement);\n return toHorizontalLineWidget(viewWrapper, viewWriter, label);\n }\n });\n conversion.for('upcast').elementToElement({\n view: 'hr',\n model: 'horizontalLine'\n });\n editor.commands.add('horizontalLine', new HorizontalLineCommand(editor));\n }\n}\n// Converts a given {@link module:engine/view/element~Element} to a horizontal line widget:\n// * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to\n// recognize the horizontal line widget element.\n// * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.\n//\n// @param {module:engine/view/element~Element} viewElement\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.\n// @param {String} label The element's label.\n// @returns {module:engine/view/element~Element}\nfunction toHorizontalLineWidget(viewElement, writer, label) {\n writer.setCustomProperty('horizontalLine', true, viewElement);\n return toWidget(viewElement, writer, { label });\n}","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module horizontal-line/horizontallineui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport horizontalLineIcon from '../theme/assets/icons/horizontalline.svg';\n/**\n * The horizontal line UI plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HorizontalLineUI extends Plugin {\n init() {\n const editor = this.editor;\n const t = editor.t;\n // Add the `horizontalLine` button to feature components.\n editor.ui.componentFactory.add('horizontalLine', locale => {\n const command = editor.commands.get('horizontalLine');\n const view = new ButtonView(locale);\n view.set({\n label: t('ak'),\n icon: horizontalLineIcon,\n tooltip: true\n });\n view.bind('isEnabled').to(command, 'isEnabled');\n // Execute the command.\n this.listenTo(view, 'execute', () => {\n editor.execute('horizontalLine');\n editor.editing.view.focus();\n });\n return view;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 9h16v2H2z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 upload/adapters/base64uploadadapter\n */\n\n/* globals window */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FileRepository from '../filerepository';\n\n/**\n * A plugin that converts images inserted into the editor into [Base64 strings](https://en.wikipedia.org/wiki/Base64)\n * in the {@glink builds/guides/integration/saving-data editor output}.\n *\n * This kind of image upload does not require server processing – images are stored with the rest of the text and\n * displayed by the web browser without additional requests.\n *\n * Check out the {@glink features/image-upload/image-upload comprehensive \"Image upload overview\"} to learn about\n * other ways to upload images into CKEditor 5.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Base64UploadAdapter extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FileRepository ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Base64UploadAdapter';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tthis.editor.plugins.get( FileRepository ).createUploadAdapter = loader => new Adapter( loader );\n\t}\n}\n\n/**\n * The upload adapter that converts images inserted into the editor into Base64 strings.\n *\n * @private\n * @implements module:upload/filerepository~UploadAdapter\n */\nclass Adapter {\n\t/**\n\t * Creates a new adapter instance.\n\t *\n\t * @param {module:upload/filerepository~FileLoader} loader\n\t */\n\tconstructor( loader ) {\n\t\t/**\n\t\t * `FileLoader` instance to use during the upload.\n\t\t *\n\t\t * @member {module:upload/filerepository~FileLoader} #loader\n\t\t */\n\t\tthis.loader = loader;\n\t}\n\n\t/**\n\t * Starts the upload process.\n\t *\n\t * @see module:upload/filerepository~UploadAdapter#upload\n\t * @returns {Promise}\n\t */\n\tupload() {\n\t\treturn new Promise( ( resolve, reject ) => {\n\t\t\tconst reader = this.reader = new window.FileReader();\n\n\t\t\treader.addEventListener( 'load', () => {\n\t\t\t\tresolve( { default: reader.result } );\n\t\t\t} );\n\n\t\t\treader.addEventListener( 'error', err => {\n\t\t\t\treject( err );\n\t\t\t} );\n\n\t\t\treader.addEventListener( 'abort', () => {\n\t\t\t\treject();\n\t\t\t} );\n\n\t\t\tthis.loader.file.then( file => {\n\t\t\t\treader.readAsDataURL( file );\n\t\t\t} );\n\t\t} );\n\t}\n\n\t/**\n\t * Aborts the upload process.\n\t *\n\t * @see module:upload/filerepository~UploadAdapter#abort\n\t * @returns {Promise}\n\t */\n\tabort() {\n\t\tthis.reader.abort();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 alignment/utils\n */\n\n/**\n * The list of supported alignment options:\n *\n * * `'left'`,\n * * `'right'`,\n * * `'center'`,\n * * `'justify'`\n */\nexport const supportedOptions = [ 'left', 'right', 'center', 'justify' ];\n\n/**\n * Checks whether the passed option is supported by {@link module:alignment/alignmentediting~AlignmentEditing}.\n *\n * @param {String} option The option value to check.\n * @returns {Boolean}\n */\nexport function isSupported( option ) {\n\treturn supportedOptions.includes( option );\n}\n\n/**\n * Checks whether alignment is the default one considering the direction\n * of the editor content.\n *\n * @param {String} alignment The name of the alignment to check.\n * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.\n * @returns {Boolean}\n */\nexport function isDefault( alignment, locale ) {\n\t// Right now only LTR is supported so the 'left' value is always the default one.\n\n\tif ( locale.contentLanguageDirection == 'rtl' ) {\n\t\treturn alignment === 'right';\n\t} else {\n\t\treturn alignment === 'left';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 alignment/alignmentcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\nimport { isDefault } from './utils';\n\nconst ALIGNMENT = 'alignment';\n\n/**\n * The alignment command plugin.\n *\n * @extends module:core/command~Command\n */\nexport default class AlignmentCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst editor = this.editor;\n\t\tconst locale = editor.locale;\n\t\tconst firstBlock = first( this.editor.model.document.selection.getSelectedBlocks() );\n\n\t\t// As first check whether to enable or disable the command as the value will always be false if the command cannot be enabled.\n\t\tthis.isEnabled = !!firstBlock && this._canBeAligned( firstBlock );\n\n\t\t/**\n\t\t * A value of the current block's alignment.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {String} #value\n\t\t */\n\t\tif ( this.isEnabled && firstBlock.hasAttribute( 'alignment' ) ) {\n\t\t\tthis.value = firstBlock.getAttribute( 'alignment' );\n\t\t} else {\n\t\t\tthis.value = locale.contentLanguageDirection === 'rtl' ? 'right' : 'left';\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command. Applies the alignment `value` to the selected blocks.\n\t * If no `value` is passed, the `value` is the default one or it is equal to the currently selected block's alignment attribute,\n\t * the command will remove the attribute from the selected blocks.\n\t *\n\t * @param {Object} [options] Options for the executed command.\n\t * @param {String} [options.value] The value to apply.\n\t * @fires execute\n\t */\n\texecute( options = {} ) {\n\t\tconst editor = this.editor;\n\t\tconst locale = editor.locale;\n\t\tconst model = editor.model;\n\t\tconst doc = model.document;\n\n\t\tconst value = options.value;\n\n\t\tmodel.change( writer => {\n\t\t\t// Get only those blocks from selected that can have alignment set\n\t\t\tconst blocks = Array.from( doc.selection.getSelectedBlocks() ).filter( block => this._canBeAligned( block ) );\n\t\t\tconst currentAlignment = blocks[ 0 ].getAttribute( 'alignment' );\n\n\t\t\t// Remove alignment attribute if current alignment is:\n\t\t\t// - default (should not be stored in model as it will bloat model data)\n\t\t\t// - equal to currently set\n\t\t\t// - or no value is passed - denotes default alignment.\n\t\t\tconst removeAlignment = isDefault( value, locale ) || currentAlignment === value || !value;\n\n\t\t\tif ( removeAlignment ) {\n\t\t\t\tremoveAlignmentFromSelection( blocks, writer );\n\t\t\t} else {\n\t\t\t\tsetAlignmentOnSelection( blocks, writer, value );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks whether a block can have alignment set.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} block The block to be checked.\n\t * @returns {Boolean}\n\t */\n\t_canBeAligned( block ) {\n\t\treturn this.editor.model.schema.checkAttribute( block, ALIGNMENT );\n\t}\n}\n\n// Removes the alignment attribute from blocks.\n// @private\nfunction removeAlignmentFromSelection( blocks, writer ) {\n\tfor ( const block of blocks ) {\n\t\twriter.removeAttribute( ALIGNMENT, block );\n\t}\n}\n\n// Sets the alignment attribute on blocks.\n// @private\nfunction setAlignmentOnSelection( blocks, writer, alignment ) {\n\tfor ( const block of blocks ) {\n\t\twriter.setAttribute( ALIGNMENT, alignment, block );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 alignment/alignmentediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport AlignmentCommand from './alignmentcommand';\nimport { isDefault, isSupported, supportedOptions } from './utils';\n\n/**\n * The alignment editing feature. It introduces the {@link module:alignment/alignmentcommand~AlignmentCommand command} and adds\n * the `alignment` attribute for block elements in the {@link module:engine/model/model~Model model}.\n * @extends module:core/plugin~Plugin\n */\nexport default class AlignmentEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'AlignmentEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'alignment', {\n\t\t\toptions: [ ...supportedOptions ]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst locale = editor.locale;\n\t\tconst schema = editor.model.schema;\n\n\t\t// Filter out unsupported options.\n\t\tconst enabledOptions = editor.config.get( 'alignment.options' ).filter( isSupported );\n\n\t\t// Allow alignment attribute on all blocks.\n\t\tschema.extend( '$block', { allowAttributes: 'alignment' } );\n\t\teditor.model.schema.setAttributeProperties( 'alignment', { isFormatting: true } );\n\n\t\tconst definition = _buildDefinition( enabledOptions.filter( option => !isDefault( option, locale ) ) );\n\n\t\teditor.conversion.attributeToAttribute( definition );\n\n\t\teditor.commands.add( 'alignment', new AlignmentCommand( editor ) );\n\t}\n}\n\n// Utility function responsible for building converter definition.\n// @private\nfunction _buildDefinition( options ) {\n\tconst definition = {\n\t\tmodel: {\n\t\t\tkey: 'alignment',\n\t\t\tvalues: options.slice()\n\t\t},\n\t\tview: {}\n\t};\n\n\tfor ( const option of options ) {\n\t\tdefinition.view[ option ] = {\n\t\t\tkey: 'style',\n\t\t\tvalue: {\n\t\t\t\t'text-align': option\n\t\t\t}\n\t\t};\n\t}\n\n\treturn definition;\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0-8c0 .414.336.75.75.75h9.929a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M18 3.75a.75.75 0 01-.75.75H2.75a.75.75 0 110-1.5h14.5a.75.75 0 01.75.75zm0 8a.75.75 0 01-.75.75H2.75a.75.75 0 110-1.5h14.5a.75.75 0 01.75.75zm0 4a.75.75 0 01-.75.75H7.321a.75.75 0 110-1.5h9.929a.75.75 0 01.75.75zm0-8a.75.75 0 01-.75.75H7.321a.75.75 0 110-1.5h9.929a.75.75 0 01.75.75z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module alignment/alignmentui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport {\n createDropdown,\n addToolbarToDropdown\n} from '@ckeditor/ckeditor5-ui/src/dropdown/utils';\nimport { isSupported } from './utils';\nimport alignLeftIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/align-left.svg';\nimport alignRightIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/align-right.svg';\nimport alignCenterIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/align-center.svg';\nimport alignJustifyIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/align-justify.svg';\nconst icons = new Map([\n [\n 'left',\n alignLeftIcon\n ],\n [\n 'right',\n alignRightIcon\n ],\n [\n 'center',\n alignCenterIcon\n ],\n [\n 'justify',\n alignJustifyIcon\n ]\n]);\n/**\n * The default alignment UI plugin.\n *\n * It introduces the `'alignment:left'`, `'alignment:right'`, `'alignment:center'` and `'alignment:justify'` buttons\n * and the `'alignment'` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class AlignmentUI extends Plugin {\n /**\n\t * Returns the localized option titles provided by the plugin.\n\t *\n\t * The following localized titles corresponding with\n\t * {@link module:alignment/alignment~AlignmentConfig#options} are available:\n\t *\n\t * * `'left'`,\n\t * * `'right'`,\n\t * * `'center'`,\n\t * * `'justify'`.\n\t *\n\t * @readonly\n\t * @type {Object.<String,String>}\n\t */\n get localizedOptionTitles() {\n const t = this.editor.t;\n return {\n 'left': t('aa'),\n 'right': t('ab'),\n 'center': t('ac'),\n 'justify': t('ad')\n };\n }\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'AlignmentUI';\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const componentFactory = editor.ui.componentFactory;\n const t = editor.t;\n const options = editor.config.get('alignment.options');\n options.filter(isSupported).forEach(option => this._addButton(option));\n componentFactory.add('alignment', locale => {\n const dropdownView = createDropdown(locale);\n // Add existing alignment buttons to dropdown's toolbar.\n const buttons = options.map(option => componentFactory.create(`alignment:${ option }`));\n addToolbarToDropdown(dropdownView, buttons);\n // Configure dropdown properties an behavior.\n dropdownView.buttonView.set({\n label: t('ae'),\n tooltip: true\n });\n dropdownView.toolbarView.isVertical = true;\n dropdownView.toolbarView.ariaLabel = t('af');\n dropdownView.extendTemplate({ attributes: { class: 'ck-alignment-dropdown' } });\n // The default icon depends on the direction of the content.\n const defaultIcon = locale.contentLanguageDirection === 'rtl' ? alignRightIcon : alignLeftIcon;\n // Change icon to reflect current selection's alignment.\n dropdownView.buttonView.bind('icon').toMany(buttons, 'isOn', (...areActive) => {\n // Get the index of an active button.\n const index = areActive.findIndex(value => value);\n // If none of the commands is active, display either defaultIcon or the first button's icon.\n if (index < 0) {\n return defaultIcon;\n }\n // Return active button's icon.\n return buttons[index].icon;\n });\n // Enable button if any of the buttons is enabled.\n dropdownView.bind('isEnabled').toMany(buttons, 'isEnabled', (...areEnabled) => areEnabled.some(isEnabled => isEnabled));\n return dropdownView;\n });\n }\n /**\n\t * Helper method for initializing the button and linking it with an appropriate command.\n\t *\n\t * @private\n\t * @param {String} option The name of the alignment option for which the button is added.\n\t */\n _addButton(option) {\n const editor = this.editor;\n editor.ui.componentFactory.add(`alignment:${ option }`, locale => {\n const command = editor.commands.get('alignment');\n const buttonView = new ButtonView(locale);\n buttonView.set({\n label: this.localizedOptionTitles[option],\n icon: icons.get(option),\n tooltip: true,\n isToggleable: true\n });\n // Bind button model to command.\n buttonView.bind('isEnabled').to(command);\n buttonView.bind('isOn').to(command, 'value', value => value === option);\n // Execute command.\n this.listenTo(buttonView, 'execute', () => {\n editor.execute('alignment', { value: option });\n editor.editing.view.focus();\n });\n return buttonView;\n });\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm2.286 4c0 .414.336.75.75.75h9.928a.75.75 0 100-1.5H5.036a.75.75 0 00-.75.75zm0-8c0 .414.336.75.75.75h9.928a.75.75 0 100-1.5H5.036a.75.75 0 00-.75.75z\\\"/></svg>\"","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75zm0-8c0 .414.336.75.75.75h14.5a.75.75 0 100-1.5H2.75a.75.75 0 00-.75.75z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 widget/widgetresize/resizerstate\n */\n\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Stores the internal state of a single resizable object.\n *\n */\nexport default class ResizeState {\n\t/**\n\t * @param {module:widget/widgetresize~ResizerOptions} options Resizer options.\n\t */\n\tconstructor( options ) {\n\t\t/**\n\t\t * The original width (pixels) of the resized object when the resize process was started.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #originalWidth\n\t\t */\n\n\t\t/**\n\t\t * The original height (pixels) of the resized object when the resize process was started.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #originalHeight\n\t\t */\n\n\t\t/**\n\t\t * The original width (percents) of the resized object when the resize process was started.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #originalWidthPercents\n\t\t */\n\n\t\t/**\n\t\t * The position of the handle that initiated the resizing. E.g. `\"top-left\"`, `\"bottom-right\"` etc. or `null`\n\t\t * if unknown.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {String|null} #activeHandlePosition\n\t\t */\n\t\tthis.set( 'activeHandlePosition', null );\n\n\t\t/**\n\t\t * The width (percents) proposed, but not committed yet, in the current resize process.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number|null} #proposedWidthPercents\n\t\t */\n\t\tthis.set( 'proposedWidthPercents', null );\n\n\t\t/**\n\t\t * The width (pixels) proposed, but not committed yet, in the current resize process.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number|null} #proposedWidthPixels\n\t\t */\n\t\tthis.set( 'proposedWidth', null );\n\n\t\t/**\n\t\t * The height (pixels) proposed, but not committed yet, in the current resize process.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number|null} #proposedHeightPixels\n\t\t */\n\t\tthis.set( 'proposedHeight', null );\n\n\t\tthis.set( 'proposedHandleHostWidth', null );\n\t\tthis.set( 'proposedHandleHostHeight', null );\n\n\t\t/**\n\t\t * A width to height ratio of the resized image.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #aspectRatio\n\t\t */\n\n\t\t/**\n\t\t * @private\n\t\t * @type {module:widget/widgetresize~ResizerOptions}\n\t\t */\n\t\tthis._options = options;\n\n\t\t/**\n\t\t * The reference point of the resizer where the dragging started. It is used to measure the distance the user cursor\n\t\t * traveled, so how much the image should be enlarged.\n\t\t * This information is only known after the DOM was rendered, so it will be updated later.\n\t\t *\n\t\t * @private\n\t\t * @type {Object}\n\t\t */\n\t\tthis._referenceCoordinates = null;\n\t}\n\n\t/**\n\t *\n\t * @param {HTMLElement} domResizeHandle The handle used to calculate the reference point.\n\t * @param {HTMLElement} domHandleHost\n\t * @param {HTMLElement} domResizeHost\n\t */\n\tbegin( domResizeHandle, domHandleHost, domResizeHost ) {\n\t\tconst clientRect = new Rect( domHandleHost );\n\n\t\tthis.activeHandlePosition = getHandlePosition( domResizeHandle );\n\n\t\tthis._referenceCoordinates = getAbsoluteBoundaryPoint( domHandleHost, getOppositePosition( this.activeHandlePosition ) );\n\n\t\tthis.originalWidth = clientRect.width;\n\t\tthis.originalHeight = clientRect.height;\n\n\t\tthis.aspectRatio = clientRect.width / clientRect.height;\n\n\t\tconst widthStyle = domResizeHost.style.width;\n\n\t\tif ( widthStyle && widthStyle.match( /^\\d+\\.?\\d*%$/ ) ) {\n\t\t\tthis.originalWidthPercents = parseFloat( widthStyle );\n\t\t} else {\n\t\t\tthis.originalWidthPercents = calculateHostPercentageWidth( domResizeHost, clientRect );\n\t\t}\n\t}\n\n\tupdate( newSize ) {\n\t\tthis.proposedWidth = newSize.width;\n\t\tthis.proposedHeight = newSize.height;\n\t\tthis.proposedWidthPercents = newSize.widthPercents;\n\n\t\tthis.proposedHandleHostWidth = newSize.handleHostWidth;\n\t\tthis.proposedHandleHostHeight = newSize.handleHostHeight;\n\t}\n}\n\nmix( ResizeState, ObservableMixin );\n\n// Calculates a relative width of a `domResizeHost` compared to it's parent in percents.\n//\n// @private\n// @param {HTMLElement} domResizeHost\n// @param {module:utils/dom/rect~Rect} resizeHostRect\n// @returns {Number}\nfunction calculateHostPercentageWidth( domResizeHost, resizeHostRect ) {\n\tconst domResizeHostParent = domResizeHost.parentElement;\n\t// Need to use computed style as it properly excludes parent's paddings from the returned value.\n\tconst parentWidth = parseFloat( domResizeHostParent.ownerDocument.defaultView.getComputedStyle( domResizeHostParent ).width );\n\n\treturn resizeHostRect.width / parentWidth * 100;\n}\n\n// Returns coordinates of the top-left corner of an element, relative to the document's top-left corner.\n//\n// @private\n// @param {HTMLElement} element\n// @param {String} resizerPosition The position of the resize handle, e.g. `\"top-left\"`, `\"bottom-right\"`.\n// @returns {Object} return\n// @returns {Number} return.x\n// @returns {Number} return.y\nfunction getAbsoluteBoundaryPoint( element, resizerPosition ) {\n\tconst elementRect = new Rect( element );\n\tconst positionParts = resizerPosition.split( '-' );\n\tconst ret = {\n\t\tx: positionParts[ 1 ] == 'right' ? elementRect.right : elementRect.left,\n\t\ty: positionParts[ 0 ] == 'bottom' ? elementRect.bottom : elementRect.top\n\t};\n\n\tret.x += element.ownerDocument.defaultView.scrollX;\n\tret.y += element.ownerDocument.defaultView.scrollY;\n\n\treturn ret;\n}\n\n// @private\n// @param {String} resizerPosition The expected resizer position, like `\"top-left\"`, `\"bottom-right\"`.\n// @returns {String} A prefixed HTML class name for the resizer element.\nfunction getResizerHandleClass( resizerPosition ) {\n\treturn `ck-widget__resizer__handle-${ resizerPosition }`;\n}\n\n// Determines the position of a given resize handle.\n//\n// @private\n// @param {HTMLElement} domHandle Handle used to calculate the reference point.\n// @returns {String|undefined} Returns a string like `\"top-left\"` or `undefined` if not matched.\nfunction getHandlePosition( domHandle ) {\n\tconst resizerPositions = [ 'top-left', 'top-right', 'bottom-right', 'bottom-left' ];\n\n\tfor ( const position of resizerPositions ) {\n\t\tif ( domHandle.classList.contains( getResizerHandleClass( position ) ) ) {\n\t\t\treturn position;\n\t\t}\n\t}\n}\n\n// @private\n// @param {String} position Like `\"top-left\"`.\n// @returns {String} Inverted `position`, e.g. it returns `\"bottom-right\"` if `\"top-left\"` was given as `position`.\nfunction getOppositePosition( position ) {\n\tconst parts = position.split( '-' );\n\tconst replacements = {\n\t\ttop: 'bottom',\n\t\tbottom: 'top',\n\t\tleft: 'right',\n\t\tright: 'left'\n\t};\n\n\treturn `${ replacements[ parts[ 0 ] ] }-${ replacements[ parts[ 1 ] ] }`;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 widget/widgetresize/resizer\n */\n\nimport View from '@ckeditor/ckeditor5-ui/src/view';\nimport Template from '@ckeditor/ckeditor5-ui/src/template';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\nimport ResizeState from './resizerstate';\n\n/**\n * Represents a resizer for a single resizable object.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Resizer {\n\t/**\n\t * @param {module:widget/widgetresize~ResizerOptions} options Resizer options.\n\t */\n\tconstructor( options ) {\n\t\t/**\n\t\t * Stores the state of the resizable host geometry, such as the original width, the currently proposed height, etc.\n\t\t *\n\t\t * Note that a new state is created for each resize transaction.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:widget/widgetresize/resizerstate~ResizerState} #state\n\t\t */\n\n\t\t/**\n\t\t * A view displaying the proposed new element size during the resizing.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @member {module:widget/widgetresize/resizer~SizeView} #_sizeUI\n\t\t */\n\n\t\t/**\n\t\t * Options passed to the {@link #constructor}.\n\t\t *\n\t\t * @private\n\t\t * @type {module:widget/widgetresize~ResizerOptions}\n\t\t */\n\t\tthis._options = options;\n\n\t\t/**\n\t\t * Container of the entire resize UI.\n\t\t *\n\t\t * Note that this property is initialized only after the element bound with the resizer is drawn\n\t\t * so it will be a `null` when uninitialized.\n\t\t *\n\t\t * @private\n\t\t * @type {HTMLElement|null}\n\t\t */\n\t\tthis._domResizerWrapper = null;\n\n\t\t/**\n\t\t * A wrapper that is controlled by the resizer. This is usually a widget element.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/view/element~Element|null}\n\t\t */\n\t\tthis._viewResizerWrapper = null;\n\n\t\t/**\n\t\t * @observable\n\t\t */\n\t\tthis.set( 'isEnabled', true );\n\n\t\tthis.decorate( 'begin' );\n\t\tthis.decorate( 'cancel' );\n\t\tthis.decorate( 'commit' );\n\t\tthis.decorate( 'updateSize' );\n\n\t\tthis.on( 'commit', event => {\n\t\t\t// State might not be initialized yet. In this case, prevent further handling and make sure that the resizer is\n\t\t\t// cleaned up (#5195).\n\t\t\tif ( !this.state.proposedWidth ) {\n\t\t\t\tthis._cleanup();\n\t\t\t\tevent.stop();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Attaches the resizer to the DOM.\n\t */\n\tattach() {\n\t\tconst that = this;\n\t\tconst widgetElement = this._options.viewElement;\n\t\tconst editingView = this._options.editor.editing.view;\n\n\t\teditingView.change( writer => {\n\t\t\tconst viewResizerWrapper = writer.createUIElement( 'div', {\n\t\t\t\tclass: 'ck ck-reset_all ck-widget__resizer'\n\t\t\t}, function( domDocument ) {\n\t\t\t\tconst domElement = this.toDomElement( domDocument );\n\n\t\t\t\tthat._appendHandles( domElement );\n\t\t\t\tthat._appendSizeUI( domElement );\n\n\t\t\t\tthat._domResizerWrapper = domElement;\n\n\t\t\t\tthat.on( 'change:isEnabled', ( evt, propName, newValue ) => {\n\t\t\t\t\tdomElement.style.display = newValue ? '' : 'none';\n\t\t\t\t} );\n\n\t\t\t\tdomElement.style.display = that.isEnabled ? '' : 'none';\n\n\t\t\t\treturn domElement;\n\t\t\t} );\n\n\t\t\t// Append the resizer wrapper to the widget's wrapper.\n\t\t\twriter.insert( writer.createPositionAt( widgetElement, 'end' ), viewResizerWrapper );\n\t\t\twriter.addClass( 'ck-widget_with-resizer', widgetElement );\n\n\t\t\tthis._viewResizerWrapper = viewResizerWrapper;\n\t\t} );\n\t}\n\n\t/**\n\t * Starts the resizing process.\n\t *\n\t * Creates a new {@link #state} for the current process.\n\t *\n\t * @fires begin\n\t * @param {HTMLElement} domResizeHandle Clicked handle.\n\t */\n\tbegin( domResizeHandle ) {\n\t\tthis.state = new ResizeState( this._options );\n\n\t\tthis._sizeUI.bindToState( this._options, this.state );\n\n\t\tthis.state.begin( domResizeHandle, this._getHandleHost(), this._getResizeHost() );\n\t}\n\n\t/**\n\t * Updates the proposed size based on `domEventData`.\n\t *\n\t * @fires updateSize\n\t * @param {Event} domEventData\n\t */\n\tupdateSize( domEventData ) {\n\t\tconst newSize = this._proposeNewSize( domEventData );\n\t\tconst editingView = this._options.editor.editing.view;\n\n\t\teditingView.change( writer => {\n\t\t\tconst unit = this._options.unit;\n\t\t\tconst newWidth = ( unit === '%' ? newSize.widthPercents : newSize.width ) + unit;\n\n\t\t\twriter.setStyle( 'width', newWidth, this._options.viewElement );\n\t\t} );\n\n\t\t// Get an actual image width, and:\n\t\t// * reflect this size to the resize wrapper\n\t\t// * apply this **real** size to the state\n\t\tconst domHandleHost = this._getHandleHost();\n\t\tconst domHandleHostRect = new Rect( domHandleHost );\n\n\t\tnewSize.handleHostWidth = Math.round( domHandleHostRect.width );\n\t\tnewSize.handleHostHeight = Math.round( domHandleHostRect.height );\n\n\t\t// Handle max-width limitation.\n\t\tconst domResizeHostRect = new Rect( domHandleHost );\n\n\t\tnewSize.width = Math.round( domResizeHostRect.width );\n\t\tnewSize.height = Math.round( domResizeHostRect.height );\n\n\t\tthis.redraw( domHandleHostRect );\n\n\t\tthis.state.update( newSize );\n\t}\n\n\t/**\n\t * Applies the geometry proposed with the resizer.\n\t *\n\t * @fires commit\n\t */\n\tcommit() {\n\t\tconst unit = this._options.unit;\n\t\tconst newValue = ( unit === '%' ? this.state.proposedWidthPercents : this.state.proposedWidth ) + this._options.unit;\n\n\t\tthis._options.onCommit( newValue );\n\n\t\tthis._cleanup();\n\t}\n\n\t/**\n\t * Cancels and rejects the proposed resize dimensions, hiding the UI.\n\t *\n\t * @fires cancel\n\t */\n\tcancel() {\n\t\tthis._cleanup();\n\t}\n\n\t/**\n\t * Destroys the resizer.\n\t */\n\tdestroy() {\n\t\tthis.cancel();\n\t}\n\n\t/**\n\t * Redraws the resizer.\n\t *\n\t * @param {module:utils/dom/rect~Rect} [handleHostRect] Handle host rectangle might be given to improve performance.\n\t */\n\tredraw( handleHostRect ) {\n\t\tconst domWrapper = this._domResizerWrapper;\n\n\t\tif ( existsInDom( domWrapper ) ) {\n\t\t\tthis._options.editor.editing.view.change( writer => {\n\t\t\t\t// Refresh only if resizer exists in the DOM.\n\t\t\t\tconst widgetWrapper = domWrapper.parentElement;\n\t\t\t\tconst handleHost = this._getHandleHost();\n\t\t\t\tconst clientRect = handleHostRect || new Rect( handleHost );\n\n\t\t\t\twriter.setStyle( 'width', clientRect.width + 'px', this._viewResizerWrapper );\n\t\t\t\twriter.setStyle( 'height', clientRect.height + 'px', this._viewResizerWrapper );\n\n\t\t\t\tconst offsets = {\n\t\t\t\t\tleft: handleHost.offsetLeft,\n\t\t\t\t\ttop: handleHost.offsetTop,\n\t\t\t\t\theight: handleHost.offsetHeight,\n\t\t\t\t\twidth: handleHost.offsetWidth\n\t\t\t\t};\n\n\t\t\t\t// In case a resizing host is not a widget wrapper, we need to compensate\n\t\t\t\t// for any additional offsets the resize host might have. E.g. wrapper padding\n\t\t\t\t// or simply another editable. By doing that the border and resizers are shown\n\t\t\t\t// only around the resize host.\n\t\t\t\tif ( !widgetWrapper.isSameNode( handleHost ) ) {\n\t\t\t\t\twriter.setStyle( 'left', offsets.left + 'px', this._viewResizerWrapper );\n\t\t\t\t\twriter.setStyle( 'top', offsets.top + 'px', this._viewResizerWrapper );\n\n\t\t\t\t\twriter.setStyle( 'height', offsets.height + 'px', this._viewResizerWrapper );\n\t\t\t\t\twriter.setStyle( 'width', offsets.width + 'px', this._viewResizerWrapper );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\tfunction existsInDom( element ) {\n\t\t\treturn element && element.ownerDocument && element.ownerDocument.contains( element );\n\t\t}\n\t}\n\n\tcontainsHandle( domElement ) {\n\t\treturn this._domResizerWrapper.contains( domElement );\n\t}\n\n\tstatic isResizeHandle( domElement ) {\n\t\treturn domElement.classList.contains( 'ck-widget__resizer__handle' );\n\t}\n\n\t/**\n\t * Cleans up the context state.\n\t *\n\t * @protected\n\t */\n\t_cleanup() {\n\t\tthis._sizeUI.dismiss();\n\t\tthis._sizeUI.isVisible = false;\n\t}\n\n\t/**\n\t * Calculates the proposed size as the resize handles are dragged.\n\t *\n\t * @private\n\t * @param {Event} domEventData Event data that caused the size update request. It should be used to calculate the proposed size.\n\t * @returns {Object} return\n\t * @returns {Number} return.width Proposed width.\n\t * @returns {Number} return.height Proposed height.\n\t */\n\t_proposeNewSize( domEventData ) {\n\t\tconst state = this.state;\n\t\tconst currentCoordinates = extractCoordinates( domEventData );\n\t\tconst isCentered = this._options.isCentered ? this._options.isCentered( this ) : true;\n\n\t\t// Enlargement defines how much the resize host has changed in a given axis. Naturally it could be a negative number\n\t\t// meaning that it has been shrunk.\n\t\t//\n\t\t// +----------------+--+\n\t\t// | | |\n\t\t// | img | |\n\t\t// | /handle host | |\n\t\t// +----------------+ | ^\n\t\t// | | | - enlarge y\n\t\t// +-------------------+ v\n\t\t// \t\t\t\t\t<-->\n\t\t// \t\t\t\t\t enlarge x\n\t\tconst enlargement = {\n\t\t\tx: state._referenceCoordinates.x - ( currentCoordinates.x + state.originalWidth ),\n\t\t\ty: ( currentCoordinates.y - state.originalHeight ) - state._referenceCoordinates.y\n\t\t};\n\n\t\tif ( isCentered && state.activeHandlePosition.endsWith( '-right' ) ) {\n\t\t\tenlargement.x = currentCoordinates.x - ( state._referenceCoordinates.x + state.originalWidth );\n\t\t}\n\n\t\t// Objects needs to be resized twice as much in horizontal axis if centered, since enlargement is counted from\n\t\t// one resized corner to your cursor. It needs to be duplicated to compensate for the other side too.\n\t\tif ( isCentered ) {\n\t\t\tenlargement.x *= 2;\n\t\t}\n\n\t\t// const resizeHost = this._getResizeHost();\n\n\t\t// The size proposed by the user. It does not consider the aspect ratio.\n\t\tconst proposedSize = {\n\t\t\twidth: Math.abs( state.originalWidth + enlargement.x ),\n\t\t\theight: Math.abs( state.originalHeight + enlargement.y )\n\t\t};\n\n\t\t// Dominant determination must take the ratio into account.\n\t\tproposedSize.dominant = proposedSize.width / state.aspectRatio > proposedSize.height ? 'width' : 'height';\n\t\tproposedSize.max = proposedSize[ proposedSize.dominant ];\n\n\t\t// Proposed size, respecting the aspect ratio.\n\t\tconst targetSize = {\n\t\t\twidth: proposedSize.width,\n\t\t\theight: proposedSize.height\n\t\t};\n\n\t\tif ( proposedSize.dominant == 'width' ) {\n\t\t\ttargetSize.height = targetSize.width / state.aspectRatio;\n\t\t} else {\n\t\t\ttargetSize.width = targetSize.height * state.aspectRatio;\n\t\t}\n\n\t\treturn {\n\t\t\twidth: Math.round( targetSize.width ),\n\t\t\theight: Math.round( targetSize.height ),\n\t\t\twidthPercents: Math.min( Math.round( state.originalWidthPercents / state.originalWidth * targetSize.width * 100 ) / 100, 100 )\n\t\t};\n\t}\n\n\t/**\n\t * Obtains the resize host.\n\t *\n\t * Resize host is an object that receives dimensions which are the result of resizing.\n\t *\n\t * @protected\n\t * @returns {HTMLElement}\n\t */\n\t_getResizeHost() {\n\t\tconst widgetWrapper = this._domResizerWrapper.parentElement;\n\n\t\treturn this._options.getResizeHost( widgetWrapper );\n\t}\n\n\t/**\n\t * Obtains the handle host.\n\t *\n\t * Handle host is an object that the handles are aligned to.\n\t *\n\t * Handle host will not always be an entire widget itself. Take an image as an example. The image widget\n\t * contains an image and a caption. Only the image should be surrounded with handles.\n\t *\n\t * @protected\n\t * @returns {HTMLElement}\n\t */\n\t_getHandleHost() {\n\t\tconst widgetWrapper = this._domResizerWrapper.parentElement;\n\n\t\treturn this._options.getHandleHost( widgetWrapper );\n\t}\n\n\t/**\n\t * Renders the resize handles in the DOM.\n\t *\n\t * @private\n\t * @param {HTMLElement} domElement The resizer wrapper.\n\t */\n\t_appendHandles( domElement ) {\n\t\tconst resizerPositions = [ 'top-left', 'top-right', 'bottom-right', 'bottom-left' ];\n\n\t\tfor ( const currentPosition of resizerPositions ) {\n\t\t\tdomElement.appendChild( ( new Template( {\n\t\t\t\ttag: 'div',\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: `ck-widget__resizer__handle ${ getResizerClass( currentPosition ) }`\n\t\t\t\t}\n\t\t\t} ).render() ) );\n\t\t}\n\t}\n\n\t/**\n\t * Sets up the {@link #_sizeUI} property and adds it to the passed `domElement`.\n\t *\n\t * @private\n\t * @param {HTMLElement} domElement\n\t */\n\t_appendSizeUI( domElement ) {\n\t\tconst sizeUI = new SizeView();\n\n\t\t// Make sure icon#element is rendered before passing to appendChild().\n\t\tsizeUI.render();\n\n\t\tthis._sizeUI = sizeUI;\n\n\t\tdomElement.appendChild( sizeUI.element );\n\t}\n\n\t/**\n\t * Determines the position of a given resize handle.\n\t *\n\t * @private\n\t * @param {HTMLElement} domHandle Handle used to calculate the reference point.\n\t * @returns {String|undefined} Returns a string like `\"top-left\"` or `undefined` if not matched.\n\t */\n\t_getHandlePosition( domHandle ) {\n\t\tconst resizerPositions = [ 'top-left', 'top-right', 'bottom-right', 'bottom-left' ];\n\n\t\tfor ( const position of resizerPositions ) {\n\t\t\tif ( domHandle.classList.contains( getResizerClass( position ) ) ) {\n\t\t\t\treturn position;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @event begin\n\t */\n\n\t/**\n\t * @event updateSize\n\t */\n\n\t/**\n\t * @event commit\n\t */\n\n\t/**\n\t * @event cancel\n\t */\n}\n\nmix( Resizer, ObservableMixin );\n\n/**\n * A view displaying the proposed new element size during the resizing.\n *\n * @extends {module:ui/view~View}\n */\nclass SizeView extends View {\n\tconstructor() {\n\t\tsuper();\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-size-view',\n\t\t\t\t\tbind.to( 'activeHandlePosition', value => value ? `ck-orientation-${ value }` : '' )\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\tdisplay: bind.if( 'isVisible', 'none', visible => !visible )\n\t\t\t\t}\n\t\t\t},\n\t\t\tchildren: [ {\n\t\t\t\ttext: bind.to( 'label' )\n\t\t\t} ]\n\t\t} );\n\t}\n\n\tbindToState( options, resizerState ) {\n\t\tthis.bind( 'isVisible' ).to( resizerState, 'proposedWidth', resizerState, 'proposedHeight', ( width, height ) =>\n\t\t\twidth !== null && height !== null );\n\n\t\tthis.bind( 'label' ).to(\n\t\t\tresizerState, 'proposedHandleHostWidth',\n\t\t\tresizerState, 'proposedHandleHostHeight',\n\t\t\tresizerState, 'proposedWidthPercents',\n\t\t\t( width, height, widthPercents ) => {\n\t\t\t\tif ( options.unit === 'px' ) {\n\t\t\t\t\treturn `${ width }×${ height }`;\n\t\t\t\t} else {\n\t\t\t\t\treturn `${ widthPercents }%`;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\n\t\tthis.bind( 'activeHandlePosition' ).to( resizerState );\n\t}\n\n\tdismiss() {\n\t\tthis.unbind();\n\t\tthis.isVisible = false;\n\t}\n}\n\n// @private\n// @param {String} resizerPosition Expected resizer position like `\"top-left\"`, `\"bottom-right\"`.\n// @returns {String} A prefixed HTML class name for the resizer element\nfunction getResizerClass( resizerPosition ) {\n\treturn `ck-widget__resizer__handle-${ resizerPosition }`;\n}\n\nfunction extractCoordinates( event ) {\n\treturn {\n\t\tx: event.pageX,\n\t\ty: event.pageY\n\t};\n}\n","import debounce from './debounce.js';\nimport isObject from './isObject.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a throttled function that only invokes `func` at most once per\n * every `wait` milliseconds. The throttled function comes with a `cancel`\n * method to cancel delayed `func` invocations and a `flush` method to\n * immediately invoke them. Provide `options` to indicate whether `func`\n * should be invoked on the leading and/or trailing edge of the `wait`\n * timeout. The `func` is invoked with the last arguments provided to the\n * throttled function. Subsequent calls to the throttled function return the\n * result of the last `func` invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the throttled function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.throttle` and `_.debounce`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to throttle.\n * @param {number} [wait=0] The number of milliseconds to throttle invocations to.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=true]\n * Specify invoking on the leading edge of the timeout.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new throttled function.\n * @example\n *\n * // Avoid excessively updating the position while scrolling.\n * jQuery(window).on('scroll', _.throttle(updatePosition, 100));\n *\n * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.\n * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });\n * jQuery(element).on('click', throttled);\n *\n * // Cancel the trailing throttled invocation.\n * jQuery(window).on('popstate', throttled.cancel);\n */\nfunction throttle(func, wait, options) {\n var leading = true,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n if (isObject(options)) {\n leading = 'leading' in options ? !!options.leading : leading;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n return debounce(func, wait, {\n 'leading': leading,\n 'maxWait': wait,\n 'trailing': trailing\n });\n}\n\nexport default throttle;\n","/**\n * @license Copyright (c) 2003-2020, 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 widget/widgetresize\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Resizer from './widgetresize/resizer';\nimport DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { throttle } from 'lodash-es';\n\nimport '../theme/widgetresize.css';\n\n/**\n * The widget resize feature plugin.\n *\n * Use the {@link module:widget/widgetresize~WidgetResize#attachTo} method to create a resizer for the specified widget.\n *\n * @extends module:core/plugin~Plugin\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class WidgetResize extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'WidgetResize';\n\t}\n\n\tinit() {\n\t\t/**\n\t\t * The currently visible resizer.\n\t\t *\n\t\t * @protected\n\t\t * @observable\n\t\t * @member {module:widget/widgetresize/resizer~Resizer|null} #_visibleResizer\n\t\t */\n\t\tthis.set( '_visibleResizer', null );\n\n\t\t/**\n\t\t * References an active resizer.\n\t\t *\n\t\t * Active resizer means a resizer which handle is actively used by the end user.\n\t\t *\n\t\t * @protected\n\t\t * @observable\n\t\t * @member {module:widget/widgetresize/resizer~Resizer|null} #_activeResizer\n\t\t */\n\t\tthis.set( '_activeResizer', null );\n\n\t\t/**\n\t\t * A map of resizers created using this plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<module:engine/view/containerelement~ContainerElement, module:widget/widgetresize/resizer~Resizer>}\n\t\t */\n\t\tthis._resizers = new Map();\n\n\t\tconst domDocument = global.window.document;\n\n\t\tthis.editor.model.schema.setAttributeProperties( 'width', {\n\t\t\tisFormatting: true\n\t\t} );\n\n\t\tthis._observer = Object.create( DomEmitterMixin );\n\n\t\tthis._observer.listenTo( domDocument, 'mousedown', ( event, domEventData ) => {\n\t\t\tif ( !Resizer.isResizeHandle( domEventData.target ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst resizeHandle = domEventData.target;\n\n\t\t\tthis._activeResizer = this._getResizerByHandle( resizeHandle );\n\n\t\t\tif ( this._activeResizer ) {\n\t\t\t\tthis._activeResizer.begin( resizeHandle );\n\t\t\t}\n\t\t} );\n\n\t\tthis._observer.listenTo( domDocument, 'mousemove', ( event, domEventData ) => {\n\t\t\tif ( this._activeResizer ) {\n\t\t\t\tthis._activeResizer.updateSize( domEventData );\n\t\t\t}\n\t\t} );\n\n\t\tthis._observer.listenTo( domDocument, 'mouseup', () => {\n\t\t\tif ( this._activeResizer ) {\n\t\t\t\tthis._activeResizer.commit();\n\n\t\t\t\tthis._activeResizer = null;\n\t\t\t}\n\t\t} );\n\n\t\tconst redrawFocusedResizer = () => {\n\t\t\tif ( this._visibleResizer ) {\n\t\t\t\tthis._visibleResizer.redraw();\n\t\t\t}\n\t\t};\n\n\t\tconst redrawFocusedResizerThrottled = throttle( redrawFocusedResizer, 200 ); // 5fps\n\n\t\t// Redraws occurring upon a change of visible resizer must not be throttled, as it is crucial for the initial\n\t\t// render. Without it the resizer frame would be misaligned with resizing host for a fraction of second.\n\t\tthis.on( 'change:_visibleResizer', redrawFocusedResizer );\n\n\t\t// Redrawing on any change of the UI of the editor (including content changes).\n\t\tthis.editor.ui.on( 'update', redrawFocusedResizerThrottled );\n\n\t\t// Resizers need to be redrawn upon window resize, because new window might shrink resize host.\n\t\tthis._observer.listenTo( global.window, 'resize', redrawFocusedResizerThrottled );\n\n\t\tconst viewSelection = this.editor.editing.view.document.selection;\n\n\t\tviewSelection.on( 'change', () => {\n\t\t\tconst selectedElement = viewSelection.getSelectedElement();\n\n\t\t\tthis._visibleResizer = this._getResizerByViewElement( selectedElement ) || null;\n\t\t} );\n\t}\n\n\tdestroy() {\n\t\tthis._observer.stopListening();\n\t}\n\n\t/**\n\t * @param {module:widget/widgetresize~ResizerOptions} [options] Resizer options.\n\t * @returns {module:widget/widgetresize/resizer~Resizer}\n\t */\n\tattachTo( options ) {\n\t\tconst resizer = new Resizer( options );\n\t\tconst plugins = this.editor.plugins;\n\n\t\tresizer.attach();\n\n\t\tif ( plugins.has( 'WidgetToolbarRepository' ) ) {\n\t\t\t// Hiding widget toolbar to improve the performance\n\t\t\t// (https://github.com/ckeditor/ckeditor5-widget/pull/112#issuecomment-564528765).\n\t\t\tconst widgetToolbarRepository = plugins.get( 'WidgetToolbarRepository' );\n\n\t\t\tresizer.on( 'begin', () => {\n\t\t\t\twidgetToolbarRepository.forceDisabled( 'resize' );\n\t\t\t}, { priority: 'lowest' } );\n\n\t\t\tresizer.on( 'cancel', () => {\n\t\t\t\twidgetToolbarRepository.clearForceDisabled( 'resize' );\n\t\t\t}, { priority: 'highest' } );\n\n\t\t\tresizer.on( 'commit', () => {\n\t\t\t\twidgetToolbarRepository.clearForceDisabled( 'resize' );\n\t\t\t}, { priority: 'highest' } );\n\t\t}\n\n\t\tthis._resizers.set( options.viewElement, resizer );\n\n\t\treturn resizer;\n\t}\n\n\t/**\n\t * Returns a resizer that contains a given resize handle.\n\t *\n\t * @protected\n\t * @param {HTMLElement} domResizeHandle\n\t * @returns {module:widget/widgetresize/resizer~Resizer}\n\t */\n\t_getResizerByHandle( domResizeHandle ) {\n\t\tfor ( const resizer of this._resizers.values() ) {\n\t\t\tif ( resizer.containsHandle( domResizeHandle ) ) {\n\t\t\t\treturn resizer;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns a resizer created for a given view element (widget element).\n\t *\n\t * @protected\n\t * @param {module:engine/view/containerelement~ContainerElement} viewElement\n\t * @returns {module:widget/widgetresize/resizer~Resizer}\n\t */\n\t_getResizerByViewElement( viewElement ) {\n\t\treturn this._resizers.get( viewElement );\n\t}\n}\n\nmix( WidgetResize, ObservableMixin );\n\n/**\n * Interface describing a resizer. It allows to specify the resizing host, custom logic for calculating aspect ratio, etc.\n *\n * @interface ResizerOptions\n */\n\n/**\n * Editor instance associated with the resizer.\n *\n * @member {module:core/editor/editor~Editor} module:widget/widgetresize~ResizerOptions#editor\n */\n\n/**\n * @member {module:engine/model/element~Element} module:widget/widgetresize~ResizerOptions#modelElement\n */\n\n/**\n * @member {module:engine/view/containerelement~ContainerElement} module:widget/widgetresize~ResizerOptions#viewElement\n */\n\n/**\n * A callback to be executed once the resizing process is done.\n *\n * It receives a `Number` (`newValue`) as a parameter.\n *\n * For example, {@link module:image/imageresize~ImageResize} uses it to execute the image resize command\n * which puts the new value into the model.\n *\n * ```js\n * {\n *\teditor,\n *\tmodelElement: data.item,\n *\tviewElement: widget,\n *\n *\tonCommit( newValue ) {\n *\t\teditor.execute( 'imageResize', { width: newValue } );\n *\t}\n * };\n * ```\n *\n *\n * @member {Function} module:widget/widgetresize~ResizerOptions#onCommit\n */\n\n/**\n * @member {Function} module:widget/widgetresize~ResizerOptions#getResizeHost\n */\n\n/**\n * @member {Function} module:widget/widgetresize~ResizerOptions#isCentered\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 image/imageresize/imageresizecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { isImage } from '../image/utils';\n\n/**\n * The image resize command. Currently, it supports only the width attribute.\n *\n * @extends module:core/command~Command\n */\nexport default class ImageResizeCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst element = this.editor.model.document.selection.getSelectedElement();\n\n\t\tthis.isEnabled = isImage( element );\n\n\t\tif ( !element || !element.hasAttribute( 'width' ) ) {\n\t\t\tthis.value = null;\n\t\t} else {\n\t\t\tthis.value = {\n\t\t\t\twidth: element.getAttribute( 'width' ),\n\t\t\t\theight: null\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t *\t\t// Sets the width to 50%:\n\t *\t\teditor.execute( 'imageResize', { width: '50%' } );\n\t *\n\t *\t\t// Removes the width attribute:\n\t *\t\teditor.execute( 'imageResize', { width: null } );\n\t *\n\t * @param {Object} options\n\t * @param {String|null} options.width The new width of the image.\n\t * @fires execute\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\t\tconst imageElement = model.document.selection.getSelectedElement();\n\n\t\tmodel.change( writer => {\n\t\t\twriter.setAttribute( 'width', options.width, imageElement );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 font/fontcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\n/**\n * The base font command.\n *\n * @extends module:core/command~Command\n */\nexport default class FontCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor Editor instance.\n\t * @param {String} attributeKey The name of a model attribute on which this command operates.\n\t */\n\tconstructor( editor, attributeKey ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * When set, it reflects the {@link #attributeKey} value of the selection.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} module:font/fontcommand~FontCommand#value\n\t\t */\n\n\t\t/**\n\t\t * A model attribute on which this command operates.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:font/fontcommand~FontCommand#attributeKey\n\t\t */\n\t\tthis.attributeKey = attributeKey;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tthis.value = doc.selection.getAttribute( this.attributeKey );\n\t\tthis.isEnabled = model.schema.checkAttributeInSelection( doc.selection, this.attributeKey );\n\t}\n\n\t/**\n\t * Executes the command. Applies the `value` of the {@link #attributeKey} to the selection.\n\t * If no `value` is passed, it removes the attribute from the selection.\n\t *\n\t * @protected\n\t * @param {Object} [options] Options for the executed command.\n\t * @param {String} [options.value] The value to apply.\n\t * @fires execute\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\t\tconst selection = document.selection;\n\n\t\tconst value = options.value;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\tif ( value ) {\n\t\t\t\t\twriter.setSelectionAttribute( this.attributeKey, value );\n\t\t\t\t} else {\n\t\t\t\t\twriter.removeSelectionAttribute( this.attributeKey );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst ranges = model.schema.getValidRanges( selection.getRanges(), this.attributeKey );\n\n\t\t\t\tfor ( const range of ranges ) {\n\t\t\t\t\tif ( value ) {\n\t\t\t\t\t\twriter.setAttribute( this.attributeKey, value, range );\n\t\t\t\t\t} else {\n\t\t\t\t\t\twriter.removeAttribute( this.attributeKey, range );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ui/colorgrid/colortile\n */\n\nimport ButtonView from '../button/buttonview';\nimport checkIcon from '../../theme/assets/icons/color-tile-check.svg';\n\n/**\n * This class represents a single color tile in the {@link module:ui/colorgrid/colorgrid~ColorGridView}.\n *\n * @extends module:ui/button/buttonview~ButtonView\n */\nexport default class ColorTileView extends ButtonView {\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * String representing a color shown as tile's background.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.set( 'color' );\n\n\t\t/**\n\t\t * A flag that toggles a special CSS class responsible for displaying\n\t\t * a border around the button.\n\t\t *\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis.set( 'hasBorder' );\n\n\t\tthis.icon = checkIcon;\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tstyle: {\n\t\t\t\t\tbackgroundColor: bind.to( 'color' )\n\t\t\t\t},\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-color-grid__tile',\n\t\t\t\t\tbind.if( 'hasBorder', 'ck-color-table__color-tile_bordered' )\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.iconView.fillColor = 'hsl(0, 0%, 100%)';\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path class=\\\"ck-icon__fill\\\" d=\\\"M16.935 5.328a2 2 0 010 2.829l-7.778 7.778a2 2 0 01-2.829 0L3.5 13.107a1.999 1.999 0 112.828-2.829l.707.707a1 1 0 001.414 0l5.658-5.657a2 2 0 012.828 0z\\\"/><path d=\\\"M14.814 6.035L8.448 12.4a1 1 0 01-1.414 0l-1.413-1.415A1 1 0 104.207 12.4l2.829 2.829a1 1 0 001.414 0l7.778-7.778a1 1 0 10-1.414-1.415z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 ui/colorgrid/colorgrid\n */\n\nimport View from '../view';\nimport ColorTileView from './colortileview';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '../focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport '../../theme/components/colorgrid/colorgrid.css';\n\n/**\n * A grid of {@link module:ui/colorgrid/colortile~ColorTileView color tiles}.\n *\n * @extends module:ui/view~View\n */\nexport default class ColorGridView extends View {\n\t/**\n\t * Creates an instance of a color grid containing {@link module:ui/colorgrid/colortile~ColorTileView tiles}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t * @param {Object} options Component configuration\n\t * @param {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>} [options.colorDefinitions] Array with definitions\n\t * required to create the {@link module:ui/colorgrid/colortile~ColorTileView tiles}.\n\t * @param {Number} options.columns A number of columns to display the tiles.\n\t */\n\tconstructor( locale, options ) {\n\t\tsuper( locale );\n\n\t\tconst colorDefinitions = options && options.colorDefinitions || [];\n\t\tconst viewStyleAttribute = {};\n\n\t\tif ( options && options.columns ) {\n\t\t\tviewStyleAttribute.gridTemplateColumns = `repeat( ${ options.columns }, 1fr)`;\n\t\t}\n\n\t\t/**\n\t\t * The color of the currently selected color tile in {@link #items}.\n\t\t *\n\t\t * @observable\n\t\t * @type {String}\n\t\t */\n\t\tthis.set( 'selectedColor' );\n\n\t\t/**\n\t\t * Collection of the child tile views.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this.createCollection();\n\n\t\t/**\n\t\t * Tracks information about DOM focus in the grid.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * Helps cycling over focusable {@link #items} in the grid.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this.items,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate grid items backwards using the arrowup key.\n\t\t\t\tfocusPrevious: 'arrowleft',\n\n\t\t\t\t// Navigate grid items forwards using the arrowdown key.\n\t\t\t\tfocusNext: 'arrowright',\n\t\t\t}\n\t\t} );\n\n\t\tthis.items.on( 'add', ( evt, colorTile ) => {\n\t\t\tcolorTile.isOn = colorTile.color === this.selectedColor;\n\t\t} );\n\n\t\tcolorDefinitions.forEach( item => {\n\t\t\tconst colorTile = new ColorTileView();\n\n\t\t\tcolorTile.set( {\n\t\t\t\tcolor: item.color,\n\t\t\t\tlabel: item.label,\n\t\t\t\ttooltip: true,\n\t\t\t\thasBorder: item.options.hasBorder\n\t\t\t} );\n\n\t\t\tcolorTile.on( 'execute', () => {\n\t\t\t\tthis.fire( 'execute', {\n\t\t\t\t\tvalue: item.color,\n\t\t\t\t\thasBorder: item.options.hasBorder,\n\t\t\t\t\tlabel: item.label\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\tthis.items.add( colorTile );\n\t\t} );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tchildren: this.items,\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-color-grid'\n\t\t\t\t],\n\t\t\t\tstyle: viewStyleAttribute\n\t\t\t}\n\t\t} );\n\n\t\tthis.on( 'change:selectedColor', ( evt, name, selectedColor ) => {\n\t\t\tfor ( const item of this.items ) {\n\t\t\t\titem.isOn = item.color === selectedColor;\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the first focusable in {@link #items}.\n\t */\n\tfocus() {\n\t\tif ( this.items.length ) {\n\t\t\tthis.items.first.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Focuses the last focusable in {@link #items}.\n\t */\n\tfocusLast() {\n\t\tif ( this.items.length ) {\n\t\t\tthis.items.last.focus();\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Items added before rendering should be known to the #focusTracker.\n\t\tfor ( const item of this.items ) {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t}\n\n\t\tthis.items.on( 'add', ( evt, item ) => {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t} );\n\n\t\tthis.items.on( 'remove', ( evt, item ) => {\n\t\t\tthis.focusTracker.remove( item.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n}\n\n/**\n * A color definition used to create a {@link module:ui/colorgrid/colortile~ColorTileView}.\n *\n *\t\t{\n *\t\t\tcolor: hsl(0, 0%, 75%),\n *\t\t\tlabel: 'Light Grey',\n *\t\t\toptions: {\n *\t\t\t\thasBorder: true\n *\t\t\t}\n *\t\t}\n *\n * @typedef {Object} module:ui/colorgrid/colorgrid~ColorDefinition\n * @type Object\n *\n * @property {String} color String representing a color.\n * It is used as value of background-color style in {@link module:ui/colorgrid/colortile~ColorTileView}.\n * @property {String} label String used as label for {@link module:ui/colorgrid/colortile~ColorTileView}.\n * @property {Object} options Additional options passed to create a {@link module:ui/colorgrid/colortile~ColorTileView}.\n * @property {Boolean} options.hasBorder A flag that indicates if special a CSS class should be added\n * to {@link module:ui/colorgrid/colortile~ColorTileView}, which renders a border around it.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 font/documentcolorcollection\n */\n\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * A collection to store document colors. It enforces colors to be unique.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n * @extends module:utils/collection~Collection\n */\nexport default class DocumentColorCollection extends Collection {\n\tconstructor( options ) {\n\t\tsuper( options );\n\n\t\t/**\n\t\t * Indicates whether the document color collection is empty.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #isEmpty\n\t\t */\n\t\tthis.set( 'isEmpty', true );\n\t}\n\n\t/**\n\t * Adds a color to the document color collection.\n\t *\n\t * This method ensures that no color duplicates are inserted (compared using\n\t * the color value of the {@link module:ui/colorgrid/colorgrid~ColorDefinition}).\n\t *\n\t * If the item does not have an ID, it will be automatically generated and set on the item.\n\t *\n\t * @chainable\n\t * @param {module:ui/colorgrid/colorgrid~ColorDefinition} item\n\t * @param {Number} [index] The position of the item in the collection. The item\n\t * is pushed to the collection when `index` is not specified.\n\t * @fires add\n\t */\n\tadd( item, index ) {\n\t\tif ( this.find( element => element.color === item.color ) ) {\n\t\t\t// No duplicates are allowed.\n\t\t\treturn;\n\t\t}\n\n\t\tsuper.add( item, index );\n\n\t\tthis.set( 'isEmpty', false );\n\t}\n\n\t/**\n\t * @inheritdoc\n\t */\n\tremove( subject ) {\n\t\tconst ret = super.remove( subject );\n\n\t\tif ( this.length === 0 ) {\n\t\t\tthis.set( 'isEmpty', true );\n\t\t}\n\n\t\treturn ret;\n\t}\n\n\t/**\n\t * Checks if an object with given colors is present in the document color collection.\n\t *\n\t * @param {String} color\n\t * @returns {Boolean}\n\t */\n\thasColor( color ) {\n\t\treturn !!this.find( item => item.color === color );\n\t}\n}\n\nmix( DocumentColorCollection, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, 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 font/ui/colortableview\n */\n\nimport View from '@ckeditor/ckeditor5-ui/src/view';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport ColorTileView from '@ckeditor/ckeditor5-ui/src/colorgrid/colortileview';\nimport ColorGridView from '@ckeditor/ckeditor5-ui/src/colorgrid/colorgridview';\nimport LabelView from '@ckeditor/ckeditor5-ui/src/label/labelview';\nimport DocumentColorCollection from '../documentcolorcollection';\nimport Template from '@ckeditor/ckeditor5-ui/src/template';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport removeButtonIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/eraser.svg';\nimport '../../theme/fontcolor.css';\n\n/**\n * A class which represents a view with the following sub–components:\n *\n * * A remove color button,\n * * A static {@link module:ui/colorgrid/colorgrid~ColorGridView} of colors defined in the configuration,\n * * A dynamic {@link module:ui/colorgrid/colorgrid~ColorGridView} of colors used in the document.\n *\n * @extends module:ui/view~View\n */\nexport default class ColorTableView extends View {\n\t/**\n\t * Creates a view to be inserted as a child of {@link module:ui/dropdown/dropdownview~DropdownView}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t * @param {Object} config The configuration object.\n\t * @param {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>} config.colors An array with definitions of colors to\n\t * be displayed in the table.\n\t * @param {Number} config.columns The number of columns in the color grid.\n\t * @param {String} config.removeButtonLabel The label of the button responsible for removing the color.\n\t * @param {String} config.documentColorsLabel The label for the section with the document colors.\n\t * @param {String} config.documentColorsCount The number of colors in the document colors section inside the color dropdown.\n\t */\n\tconstructor( locale, { colors, columns, removeButtonLabel, documentColorsLabel, documentColorsCount } ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * A collection of the children of the table.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this.createCollection();\n\n\t\t/**\n\t\t * An array with objects representing colors to be displayed in the grid.\n\t\t *\n\t\t * @type {Arrray.<module:ui/colorgrid/colorgrid~ColorDefinition>}\n\t\t */\n\t\tthis.colorDefinitions = colors;\n\n\t\t/**\n\t\t * Tracks information about the DOM focus in the list.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * Keeps the value of the command associated with the table for the current selection.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.set( 'selectedColor' );\n\n\t\t/**\n\t\t * The label of the button responsible for removing color attributes.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.removeButtonLabel = removeButtonLabel;\n\n\t\t/**\n\t\t * The number of columns in the color grid.\n\t\t *\n\t\t * @type {Number}\n\t\t */\n\t\tthis.columns = columns;\n\n\t\t/**\n\t\t * A collection of definitions that store the document colors.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:font/documentcolorcollection~DocumentColorCollection}\n\t\t */\n\t\tthis.documentColors = new DocumentColorCollection();\n\n\t\t/**\n\t\t * The maximum number of colors in the document colors section.\n\t\t * If it equals 0, the document colors section is not added.\n\t\t *\n\t\t * @readonly\n\t\t * @type {Number}\n\t\t */\n\t\tthis.documentColorsCount = documentColorsCount;\n\n\t\t/**\n\t\t * Preserves the reference to {@link module:ui/colorgrid/colorgrid~ColorGridView} used to create\n\t\t * the default (static) color set.\n\t\t *\n\t\t * The property is loaded once the the parent dropdown is opened the first time.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/colorgrid/colorgrid~ColorGridView|undefined} #staticColorsGrid\n\t\t */\n\n\t\t/**\n\t\t * Preserves the reference to {@link module:ui/colorgrid/colorgrid~ColorGridView} used to create\n\t\t * the document colors. It remains undefined if the document colors feature is disabled.\n\t\t *\n\t\t * The property is loaded once the the parent dropdown is opened the first time.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/colorgrid/colorgrid~ColorGridView|undefined} #documentColorsGrid\n\t\t */\n\n\t\t/**\n\t\t * Helps cycling over focusable {@link #items} in the list.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this.items,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate list items backwards using the Arrow Up key.\n\t\t\t\tfocusPrevious: 'arrowup',\n\n\t\t\t\t// Navigate list items forwards using the Arrow Down key.\n\t\t\t\tfocusNext: 'arrowdown',\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * Document color section's label.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @type {String}\n\t\t */\n\t\tthis._documentColorsLabel = documentColorsLabel;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-color-table'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: this.items\n\t\t} );\n\n\t\tthis.items.add( this._removeColorButton() );\n\t}\n\n\t/**\n\t * Scans through the editor model and searches for text node attributes with the given attribute name.\n\t * Found entries are set as document colors.\n\t *\n\t * All the previously stored document colors will be lost in the process.\n\t *\n\t * @param {module:engine/model/model~Model} model The model used as a source to obtain the document colors.\n\t * @param {String} attributeName Determines the name of the related model's attribute for a given dropdown.\n\t */\n\tupdateDocumentColors( model, attributeName ) {\n\t\tconst document = model.document;\n\t\tconst maxCount = this.documentColorsCount;\n\n\t\tthis.documentColors.clear();\n\n\t\tfor ( const rootName of document.getRootNames() ) {\n\t\t\tconst root = document.getRoot( rootName );\n\t\t\tconst range = model.createRangeIn( root );\n\n\t\t\tfor ( const node of range.getItems() ) {\n\t\t\t\tif ( node.is( 'textProxy' ) && node.hasAttribute( attributeName ) ) {\n\t\t\t\t\tthis._addColorToDocumentColors( node.getAttribute( attributeName ) );\n\n\t\t\t\t\tif ( this.documentColors.length >= maxCount ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Refreshes the state of the selected color in one or both {@link module:ui/colorgrid/colorgrid~ColorGridView}s\n\t * available in the {@link module:font/ui/colortableview~ColorTableView}. It guarantees that the selection will occur only in one\n\t * of them.\n\t */\n\tupdateSelectedColors() {\n\t\tconst documentColorsGrid = this.documentColorsGrid;\n\t\tconst staticColorsGrid = this.staticColorsGrid;\n\t\tconst selectedColor = this.selectedColor;\n\n\t\tstaticColorsGrid.selectedColor = selectedColor;\n\n\t\tif ( documentColorsGrid ) {\n\t\t\tdocumentColorsGrid.selectedColor = selectedColor;\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Items added before rendering should be known to the #focusTracker.\n\t\tfor ( const item of this.items ) {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t}\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Appends {@link #staticColorsGrid} and {@link #documentColorsGrid} views.\n\t */\n\tappendGrids() {\n\t\tif ( this.staticColorsGrid ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.staticColorsGrid = this._createStaticColorsGrid();\n\n\t\tthis.items.add( this.staticColorsGrid );\n\n\t\tif ( this.documentColorsCount ) {\n\t\t\t// Create a label for document colors.\n\t\t\tconst bind = Template.bind( this.documentColors, this.documentColors );\n\t\t\tconst label = new LabelView( this.locale );\n\t\t\tlabel.text = this._documentColorsLabel;\n\t\t\tlabel.extendTemplate( {\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: [\n\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t'ck-color-grid__label',\n\t\t\t\t\t\tbind.if( 'isEmpty', 'ck-hidden' )\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t} );\n\t\t\tthis.items.add( label );\n\t\t\tthis.documentColorsGrid = this._createDocumentColorsGrid();\n\t\t\tthis.items.add( this.documentColorsGrid );\n\t\t}\n\t}\n\n\t/**\n\t * Focuses the first focusable element in {@link #items}.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Focuses the last focusable element in {@link #items}.\n\t */\n\tfocusLast() {\n\t\tthis._focusCycler.focusLast();\n\t}\n\n\t/**\n\t * Adds the remove color button as a child of the current view.\n\t *\n\t * @private\n\t * @returns {module:ui/button/buttonview~ButtonView}\n\t */\n\t_removeColorButton() {\n\t\tconst buttonView = new ButtonView();\n\n\t\tbuttonView.set( {\n\t\t\twithText: true,\n\t\t\ticon: removeButtonIcon,\n\t\t\ttooltip: true,\n\t\t\tlabel: this.removeButtonLabel\n\t\t} );\n\n\t\tbuttonView.class = 'ck-color-table__remove-color';\n\t\tbuttonView.on( 'execute', () => {\n\t\t\tthis.fire( 'execute', { value: null } );\n\t\t} );\n\n\t\treturn buttonView;\n\t}\n\n\t/**\n\t * Creates a static color table grid based on the editor configuration.\n\t *\n\t * @private\n\t * @returns {module:ui/colorgrid/colorgrid~ColorGridView}\n\t */\n\t_createStaticColorsGrid() {\n\t\tconst colorGrid = new ColorGridView( this.locale, {\n\t\t\tcolorDefinitions: this.colorDefinitions,\n\t\t\tcolumns: this.columns\n\t\t} );\n\n\t\tcolorGrid.delegate( 'execute' ).to( this );\n\n\t\treturn colorGrid;\n\t}\n\n\t/**\n\t * Creates the document colors section view and binds it to {@link #documentColors}.\n\t *\n\t * @private\n\t * @returns {module:ui/colorgrid/colorgrid~ColorGridView}\n\t */\n\t_createDocumentColorsGrid() {\n\t\tconst bind = Template.bind( this.documentColors, this.documentColors );\n\t\tconst documentColorsGrid = new ColorGridView( this.locale, {\n\t\t\tcolumns: this.columns\n\t\t} );\n\n\t\tdocumentColorsGrid.delegate( 'execute' ).to( this );\n\n\t\tdocumentColorsGrid.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: bind.if( 'isEmpty', 'ck-hidden' )\n\t\t\t}\n\t\t} );\n\n\t\tdocumentColorsGrid.items.bindTo( this.documentColors ).using(\n\t\t\tcolorObj => {\n\t\t\t\tconst colorTile = new ColorTileView();\n\n\t\t\t\tcolorTile.set( {\n\t\t\t\t\tcolor: colorObj.color,\n\t\t\t\t\thasBorder: colorObj.options && colorObj.options.hasBorder\n\t\t\t\t} );\n\n\t\t\t\tif ( colorObj.label ) {\n\t\t\t\t\tcolorTile.set( {\n\t\t\t\t\t\tlabel: colorObj.label,\n\t\t\t\t\t\ttooltip: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\tcolorTile.on( 'execute', () => {\n\t\t\t\t\tthis.fire( 'execute', {\n\t\t\t\t\t\tvalue: colorObj.color\n\t\t\t\t\t} );\n\t\t\t\t} );\n\n\t\t\t\treturn colorTile;\n\t\t\t}\n\t\t);\n\n\t\t// Selected color should be cleared when document colors became empty.\n\t\tthis.documentColors.on( 'change:isEmpty', ( evt, name, val ) => {\n\t\t\tif ( val ) {\n\t\t\t\tdocumentColorsGrid.selectedColor = null;\n\t\t\t}\n\t\t} );\n\n\t\treturn documentColorsGrid;\n\t}\n\n\t/**\n\t * Adds a given color to the document colors list. If possible, the method will attempt to use\n\t * data from the {@link #colorDefinitions} (label, color options).\n\t *\n\t * @private\n\t * @param {String} color A string that stores the value of the recently applied color.\n\t */\n\t_addColorToDocumentColors( color ) {\n\t\tconst predefinedColor = this.colorDefinitions\n\t\t\t.find( definition => definition.color === color );\n\n\t\tif ( !predefinedColor ) {\n\t\t\tthis.documentColors.add( {\n\t\t\t\tcolor,\n\t\t\t\tlabel: color,\n\t\t\t\toptions: {\n\t\t\t\t\thasBorder: false\n\t\t\t\t}\n\t\t\t} );\n\t\t} else {\n\t\t\tthis.documentColors.add( Object.assign( {}, predefinedColor ) );\n\t\t}\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M8.636 9.531l-2.758 3.94a.5.5 0 00.122.696l3.224 2.284h1.314l2.636-3.736L8.636 9.53zm.288 8.451L5.14 15.396a2 2 0 01-.491-2.786l6.673-9.53a2 2 0 012.785-.49l3.742 2.62a2 2 0 01.491 2.785l-7.269 10.053-2.147-.066z\\\"/><path d=\\\"M4 18h5.523v-1H4zm-2 0h1v-1H2z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 font/utils\n */\n\nimport ColorTableView from './ui/colortableview';\n\n/**\n * The name of the font size plugin.\n */\nexport const FONT_SIZE = 'fontSize';\n\n/**\n * The name of the font family plugin.\n */\nexport const FONT_FAMILY = 'fontFamily';\n\n/**\n * The name of the font color plugin.\n */\nexport const FONT_COLOR = 'fontColor';\n\n/**\n * The name of the font background color plugin.\n */\nexport const FONT_BACKGROUND_COLOR = 'fontBackgroundColor';\n\n/**\n * Builds a proper {@link module:engine/conversion/conversion~ConverterDefinition converter definition} out of input data.\n *\n * @param {String} modelAttributeKey Key\n * @param {Array.<module:font/fontfamily~FontFamilyOption>|Array.<module:font/fontsize~FontSizeOption>} options\n * @returns {module:engine/conversion/conversion~ConverterDefinition}\n */\nexport function buildDefinition( modelAttributeKey, options ) {\n\tconst definition = {\n\t\tmodel: {\n\t\t\tkey: modelAttributeKey,\n\t\t\tvalues: []\n\t\t},\n\t\tview: {},\n\t\tupcastAlso: {}\n\t};\n\n\tfor ( const option of options ) {\n\t\tdefinition.model.values.push( option.model );\n\t\tdefinition.view[ option.model ] = option.view;\n\n\t\tif ( option.upcastAlso ) {\n\t\t\tdefinition.upcastAlso[ option.model ] = option.upcastAlso;\n\t\t}\n\t}\n\n\treturn definition;\n}\n\n/**\n * A {@link module:font/fontcolor~FontColor font color} and\n * {@link module:font/fontbackgroundcolor~FontBackgroundColor font background color} helper\n * responsible for upcasting data to the model.\n *\n * **Note**: The `styleAttr` parameter should be either `'color'` or `'background-color'`.\n *\n * @param {String} styleAttr\n * @return {String}\n */\nexport function renderUpcastAttribute( styleAttr ) {\n\treturn viewElement => normalizeColorCode( viewElement.getStyle( styleAttr ) );\n}\n\n/**\n * A {@link module:font/fontcolor~FontColor font color} and\n * {@link module:font/fontbackgroundcolor~FontBackgroundColor font background color} helper\n * responsible for downcasting a color attribute to a `<span>` element.\n *\n * **Note**: The `styleAttr` parameter should be either `'color'` or `'background-color'`.\n *\n * @param {String} styleAttr\n */\nexport function renderDowncastElement( styleAttr ) {\n\treturn ( modelAttributeValue, viewWriter ) => viewWriter.createAttributeElement( 'span', {\n\t\tstyle: `${ styleAttr }:${ modelAttributeValue }`\n\t}, { priority: 7 } );\n}\n\n/**\n * A helper that adds {@link module:font/ui/colortableview~ColorTableView} to the color dropdown with proper initial values.\n *\n * @param {Object} config The configuration object.\n * @param {module:ui/dropdown/dropdownview~DropdownView} config.dropdownView The dropdown view to which\n * a {@link module:font/ui/colortableview~ColorTableView} will be added.\n * @param {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>} config.colors An array with definitions\n * representing colors to be displayed in the color table.\n * @param {String} config.removeButtonLabel The label for the button responsible for removing the color.\n * @param {String} config.documentColorsLabel The label for the section with document colors.\n * @param {String} config.documentColorsCount The number of document colors inside the dropdown.\n * @returns {module:font/ui/colortableview~ColorTableView} The new color table view.\n */\nexport function addColorTableToDropdown( { dropdownView, colors, columns, removeButtonLabel, documentColorsLabel, documentColorsCount } ) {\n\tconst locale = dropdownView.locale;\n\tconst colorTableView = new ColorTableView( locale, { colors, columns, removeButtonLabel, documentColorsLabel, documentColorsCount } );\n\n\tdropdownView.colorTableView = colorTableView;\n\tdropdownView.panelView.children.add( colorTableView );\n\n\tcolorTableView.delegate( 'execute' ).to( dropdownView, 'execute' );\n\n\treturn colorTableView;\n}\n\n// Fixes the color value string.\n//\n// @param {String} value\n// @returns {String}\nfunction normalizeColorCode( value ) {\n\treturn value.replace( /\\s/g, '' );\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 font/fontfamily/fontfamilycommand\n */\n\nimport FontCommand from '../fontcommand';\nimport { FONT_FAMILY } from '../utils';\n\n/**\n * The font family command. It is used by {@link module:font/fontfamily/fontfamilyediting~FontFamilyEditing}\n * to apply the font family.\n *\n *\t\teditor.execute( 'fontFamily', { value: 'Arial' } );\n *\n * **Note**: Executing the command without the value removes the attribute from the model.\n *\n * @extends module:font/fontcommand~FontCommand\n */\nexport default class FontFamilyCommand extends FontCommand {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, FONT_FAMILY );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 font/fontfamily/utils\n */\n\n/**\n * Normalizes the {@link module:font/fontfamily~FontFamilyConfig#options configuration options}\n * to the {@link module:font/fontfamily~FontFamilyOption} format.\n *\n * @param {Array.<String|Object>} configuredOptions An array of options taken from the configuration.\n * @returns {Array.<module:font/fontfamily~FontFamilyOption>}\n */\nexport function normalizeOptions( configuredOptions ) {\n\t// Convert options to objects.\n\treturn configuredOptions\n\t\t.map( getOptionDefinition )\n\t\t// Filter out undefined values that `getOptionDefinition` might return.\n\t\t.filter( option => !!option );\n}\n\n// Returns an option definition either created from string shortcut.\n// If object is passed then this method will return it without alternating it. Returns undefined for item than cannot be parsed.\n//\n// @param {String|Object} option\n// @returns {undefined|module:font/fontfamily~FontFamilyOption}\nfunction getOptionDefinition( option ) {\n\t// Treat any object as full item definition provided by user in configuration.\n\tif ( typeof option === 'object' ) {\n\t\treturn option;\n\t}\n\n\t// Handle 'default' string as a special case. It will be used to remove the fontFamily attribute.\n\tif ( option === 'default' ) {\n\t\treturn {\n\t\t\ttitle: 'Default',\n\t\t\tmodel: undefined\n\t\t};\n\t}\n\n\t// Ignore values that we cannot parse to a definition.\n\tif ( typeof option !== 'string' ) {\n\t\treturn;\n\t}\n\n\t// Return font family definition from font string.\n\treturn generateFontPreset( option );\n}\n\n// Creates a predefined preset for pixel size. It deconstructs font-family like string into full configuration option.\n// A font definition is passed as coma delimited set of font family names. Font names might be quoted.\n//\n// @param {String} A font definition form configuration.\nfunction generateFontPreset( fontDefinition ) {\n\t// Remove quotes from font names. They will be normalized later.\n\tconst fontNames = fontDefinition.replace( /\"|'/g, '' ).split( ',' );\n\n\t// The first matched font name will be used as dropdown list item title and as model value.\n\tconst firstFontName = fontNames[ 0 ];\n\n\t// CSS-compatible font names.\n\tconst cssFontNames = fontNames.map( normalizeFontNameForCSS ).join( ', ' );\n\n\treturn {\n\t\ttitle: firstFontName,\n\t\tmodel: firstFontName,\n\t\tview: {\n\t\t\tname: 'span',\n\t\t\tstyles: {\n\t\t\t\t'font-family': cssFontNames\n\t\t\t},\n\t\t\tpriority: 7\n\t\t}\n\t};\n}\n\n// Normalizes font name for the style attribute. It adds braces (') if font name contains spaces.\n//\n// @param {String} fontName\n// @returns {String}\nfunction normalizeFontNameForCSS( fontName ) {\n\tfontName = fontName.trim();\n\n\t// Compound font names should be quoted.\n\tif ( fontName.indexOf( ' ' ) > 0 ) {\n\t\tfontName = `'${ fontName }'`;\n\t}\n\n\treturn fontName;\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 font/fontfamily/fontfamilyediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport FontFamilyCommand from './fontfamilycommand';\nimport { normalizeOptions } from './utils';\nimport { buildDefinition, FONT_FAMILY } from '../utils';\n\n/**\n * The font family editing feature.\n *\n * It introduces the {@link module:font/fontfamily/fontfamilycommand~FontFamilyCommand command} and\n * the `fontFamily` attribute in the {@link module:engine/model/model~Model model} which renders\n * in the {@link module:engine/view/view view} as an inline `<span>` element (`<span style=\"font-family: Arial\">`),\n * depending on the {@link module:font/fontfamily~FontFamilyConfig configuration}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontFamilyEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontFamilyEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t// Define default configuration using font families shortcuts.\n\t\teditor.config.define( FONT_FAMILY, {\n\t\t\toptions: [\n\t\t\t\t'default',\n\t\t\t\t'Arial, Helvetica, sans-serif',\n\t\t\t\t'Courier New, Courier, monospace',\n\t\t\t\t'Georgia, serif',\n\t\t\t\t'Lucida Sans Unicode, Lucida Grande, sans-serif',\n\t\t\t\t'Tahoma, Geneva, sans-serif',\n\t\t\t\t'Times New Roman, Times, serif',\n\t\t\t\t'Trebuchet MS, Helvetica, sans-serif',\n\t\t\t\t'Verdana, Geneva, sans-serif'\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow fontFamily attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: FONT_FAMILY } );\n\t\teditor.model.schema.setAttributeProperties( FONT_FAMILY, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\t// Get configured font family options without \"default\" option.\n\t\tconst options = normalizeOptions( editor.config.get( 'fontFamily.options' ) ).filter( item => item.model );\n\t\tconst definition = buildDefinition( FONT_FAMILY, options );\n\n\t\t// Set-up the two-way conversion.\n\t\teditor.conversion.attributeToElement( definition );\n\n\t\teditor.commands.add( FONT_FAMILY, new FontFamilyCommand( editor ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module font/fontfamily/fontfamilyui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Model from '@ckeditor/ckeditor5-ui/src/model';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport {\n createDropdown,\n addListToDropdown\n} from '@ckeditor/ckeditor5-ui/src/dropdown/utils';\nimport { normalizeOptions } from './utils';\nimport { FONT_FAMILY } from '../utils';\nimport fontFamilyIcon from '../../theme/assets/icons/font-family.svg';\n/**\n * The font family UI plugin. It introduces the `'fontFamily'` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontFamilyUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n const options = this._getLocalizedOptions();\n const command = editor.commands.get(FONT_FAMILY);\n // Register UI component.\n editor.ui.componentFactory.add(FONT_FAMILY, locale => {\n const dropdownView = createDropdown(locale);\n addListToDropdown(dropdownView, _prepareListOptions(options, command));\n dropdownView.buttonView.set({\n label: t('br'),\n icon: fontFamilyIcon,\n tooltip: true\n });\n dropdownView.extendTemplate({ attributes: { class: 'ck-font-family-dropdown' } });\n dropdownView.bind('isEnabled').to(command);\n // Execute command when an item from the dropdown is selected.\n this.listenTo(dropdownView, 'execute', evt => {\n editor.execute(evt.source.commandName, { value: evt.source.commandParam });\n editor.editing.view.focus();\n });\n return dropdownView;\n });\n }\n /**\n\t * Returns options as defined in `config.fontFamily.options` but processed to account for\n\t * editor localization, i.e. to display {@link module:font/fontfamily~FontFamilyOption}\n\t * in the correct language.\n\t *\n\t * Note: The reason behind this method is that there is no way to use {@link module:utils/locale~Locale#t}\n\t * when the user configuration is defined because the editor does not exist yet.\n\t *\n\t * @private\n\t * @returns {Array.<module:font/fontfamily~FontFamilyOption>}.\n\t */\n _getLocalizedOptions() {\n const editor = this.editor;\n const t = editor.t;\n const options = normalizeOptions(editor.config.get(FONT_FAMILY).options);\n return options.map(option => {\n // The only title to localize is \"Default\" others are font names.\n if (option.title === 'Default') {\n option.title = t('bs');\n }\n return option;\n });\n }\n}\n// Prepares FontFamily dropdown items.\n// @private\n// @param {Array.<module:font/fontsize~FontSizeOption>} options\n// @param {module:font/fontsize/fontsizecommand~FontSizeCommand} command\nfunction _prepareListOptions(options, command) {\n const itemDefinitions = new Collection();\n // Create dropdown items.\n for (const option of options) {\n const def = {\n type: 'button',\n model: new Model({\n commandName: FONT_FAMILY,\n commandParam: option.model,\n label: option.title,\n withText: true\n })\n };\n def.model.bind('isOn').to(command, 'value', value => value === option.model);\n // Try to set a dropdown list item style.\n if (option.view && option.view.styles) {\n def.model.set('labelStyle', `font-family: ${ option.view.styles['font-family'] }`);\n }\n itemDefinitions.add(def);\n }\n return itemDefinitions;\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.03 3h6.149a.75.75 0 110 1.5h-5.514L11.03 3zm1.27 3h4.879a.75.75 0 110 1.5h-4.244L12.3 6zm1.27 3h3.609a.75.75 0 110 1.5h-2.973L13.57 9zm-2.754 2.5L8.038 4.785 5.261 11.5h5.555zm.62 1.5H4.641l-1.666 4.028H1.312l5.789-14h1.875l5.789 14h-1.663L11.436 13z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 font/fontfamily\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FontFamilyEditing from './fontfamily/fontfamilyediting';\nimport FontFamilyUI from './fontfamily/fontfamilyui';\n\n/**\n * The font family plugin.\n *\n * For a detailed overview, check the {@glink features/font font feature} documentatiom\n * and the {@glink api/font package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:font/fontfamily/fontfamilyediting~FontFamilyEditing} and\n * {@link module:font/fontfamily/fontfamilyui~FontFamilyUI} features in the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontFamily extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FontFamilyEditing, FontFamilyUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontFamily';\n\t}\n}\n\n/**\n * The font family option descriptor.\n *\n * @typedef {Object} module:font/fontfamily~FontFamilyOption\n *\n * @property {String} title The user-readable title of the option.\n * @property {String} model The attribute's unique value in the model.\n * @property {module:engine/view/elementdefinition~ElementDefinition} view View element configuration.\n * @property {Array.<module:engine/view/elementdefinition~ElementDefinition>} [upcastAlso] An array with all matched elements that\n * the view-to-model conversion should also accept.\n */\n\n/**\n * The configuration of the font family feature.\n * It is introduced by the {@link module:font/fontfamily/fontfamilyediting~FontFamilyEditing} feature.\n *\n * Read more in {@link module:font/fontfamily~FontFamilyConfig}.\n *\n * @member {module:font/fontfamily~FontFamilyConfig} module:core/editor/editorconfig~EditorConfig#fontFamily\n */\n\n/**\n * The configuration of the font family feature.\n * This option is used by the {@link module:font/fontfamily/fontfamilyediting~FontFamilyEditing} feature.\n *\n *\t\tClassicEditor\n *\t\t\t.create( {\n * \t\t\t\tfontFamily: ... // Font family feature configuration.\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 module:font/fontfamily~FontFamilyConfig\n */\n\n/**\n * Available font family options defined as an array of strings. The default value is:\n *\n *\t\tconst fontFamilyConfig = {\n *\t\t\toptions: [\n *\t\t\t\t'default',\n *\t\t\t\t'Arial, Helvetica, sans-serif',\n *\t\t\t\t'Courier New, Courier, monospace',\n *\t\t\t\t'Georgia, serif',\n *\t\t\t\t'Lucida Sans Unicode, Lucida Grande, sans-serif',\n *\t\t\t\t'Tahoma, Geneva, sans-serif',\n *\t\t\t\t'Times New Roman, Times, serif',\n *\t\t\t\t'Trebuchet MS, Helvetica, sans-serif',\n *\t\t\t\t'Verdana, Geneva, sans-serif'\n *\t\t\t]\n *\t\t};\n *\n * which configures 8 font family options. Each option consists of one or more comma–separated font family names. The first font name is\n * used as the dropdown item description in the UI.\n *\n * **Note:** The family names that consist of spaces should not have quotes (as opposed to the CSS standard). The necessary quotes\n * will be added automatically in the view. For example, the `\"Lucida Sans Unicode\"` will render as follows:\n *\n * \t\t<span style=\"font-family:'Lucida Sans Unicode', 'Lucida Grande', sans-serif\">...</span>\n *\n * The \"default\" option removes the `fontFamily` attribute from the selection. In such case, the text will\n * be rendered in the view using the default font family defined in the styles of the web page.\n *\n * Font family can be applied using the command API. To do that, use the `fontFamily` command and pass the desired family as a `value`.\n * For example, the following code will apply the `fontFamily` attribute with the `'Arial'` `value` to the current selection:\n *\n *\t\teditor.execute( 'fontFamily', { value: 'Arial' } );\n *\n * Executing the `'fontFamily'` command without any value will remove the `fontFamily` attribute from the current selection.\n *\n * @member {Array.<String|module:font/fontfamily~FontFamilyOption>} module:font/fontfamily~FontFamilyConfig#options\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 font/fontsize/fontsizecommand\n */\n\nimport FontCommand from '../fontcommand';\nimport { FONT_SIZE } from '../utils';\n\n/**\n * The font size command. It is used by {@link module:font/fontsize/fontsizeediting~FontSizeEditing}\n * to apply the font size.\n *\n *\t\teditor.execute( 'fontSize', { value: 'small' } );\n *\n * **Note**: Executing the command without the value removes the attribute from the model.\n *\n * @extends module:font/fontcommand~FontCommand\n */\nexport default class FontSizeCommand extends FontCommand {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, FONT_SIZE );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 font/fontsize/utils\n */\n\n/**\n * Normalizes and translates the {@link module:font/fontsize~FontSizeConfig#options configuration options}\n * to the {@link module:font/fontsize~FontSizeOption} format.\n *\n * @param {Array.<String|Number|Object>} configuredOptions An array of options taken from the configuration.\n * @returns {Array.<module:font/fontsize~FontSizeOption>}\n */\nexport function normalizeOptions( configuredOptions ) {\n\t// Convert options to objects.\n\treturn configuredOptions\n\t\t.map( getOptionDefinition )\n\t\t// Filter out undefined values that `getOptionDefinition` might return.\n\t\t.filter( option => !!option );\n}\n\n// Default named presets map.\nconst namedPresets = {\n\ttiny: {\n\t\ttitle: 'Tiny',\n\t\tmodel: 'tiny',\n\t\tview: {\n\t\t\tname: 'span',\n\t\t\tclasses: 'text-tiny',\n\t\t\tpriority: 7\n\t\t}\n\t},\n\tsmall: {\n\t\ttitle: 'Small',\n\t\tmodel: 'small',\n\t\tview: {\n\t\t\tname: 'span',\n\t\t\tclasses: 'text-small',\n\t\t\tpriority: 7\n\t\t}\n\t},\n\tbig: {\n\t\ttitle: 'Big',\n\t\tmodel: 'big',\n\t\tview: {\n\t\t\tname: 'span',\n\t\t\tclasses: 'text-big',\n\t\t\tpriority: 7\n\t\t}\n\t},\n\thuge: {\n\t\ttitle: 'Huge',\n\t\tmodel: 'huge',\n\t\tview: {\n\t\t\tname: 'span',\n\t\t\tclasses: 'text-huge',\n\t\t\tpriority: 7\n\t\t}\n\t}\n};\n\n// Returns an option definition either from preset or creates one from number shortcut.\n// If object is passed then this method will return it without alternating it. Returns undefined for item than cannot be parsed.\n//\n// @param {String|Number|Object} item\n// @returns {undefined|module:font/fontsize~FontSizeOption}\nfunction getOptionDefinition( option ) {\n\t// Treat any object as full item definition provided by user in configuration.\n\tif ( typeof option === 'object' ) {\n\t\treturn option;\n\t}\n\n\t// Item is a named preset.\n\tif ( namedPresets[ option ] ) {\n\t\treturn namedPresets[ option ];\n\t}\n\n\t// 'Default' font size. It will be used to remove the fontSize attribute.\n\tif ( option === 'default' ) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\ttitle: 'Default'\n\t\t};\n\t}\n\n\t// At this stage we probably have numerical value to generate a preset so parse it's value.\n\tconst sizePreset = parseFloat( option );\n\n\t// Discard any faulty values.\n\tif ( isNaN( sizePreset ) ) {\n\t\treturn;\n\t}\n\n\t// Return font size definition from size value.\n\treturn generatePixelPreset( sizePreset );\n}\n\n// Creates a predefined preset for pixel size.\n//\n// @param {Number} size Font size in pixels.\n// @returns {module:font/fontsize~FontSizeOption}\nfunction generatePixelPreset( size ) {\n\tconst sizeName = String( size );\n\n\treturn {\n\t\ttitle: sizeName,\n\t\tmodel: size,\n\t\tview: {\n\t\t\tname: 'span',\n\t\t\tstyles: {\n\t\t\t\t'font-size': `${ size }px`\n\t\t\t},\n\t\t\tpriority: 7\n\t\t}\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 font/fontsize/fontsizeediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport FontSizeCommand from './fontsizecommand';\nimport { normalizeOptions } from './utils';\nimport { buildDefinition, FONT_SIZE } from '../utils';\n\n/**\n * The font size editing feature.\n *\n * It introduces the {@link module:font/fontsize/fontsizecommand~FontSizeCommand command} and the `fontSize`\n * attribute in the {@link module:engine/model/model~Model model} which renders in the {@link module:engine/view/view view}\n * as a `<span>` element with either:\n * * a style attribute (`<span style=\"font-size:12px\">...</span>`),\n * * or a class attribute (`<span class=\"text-small\">...</span>`)\n *\n * depending on the {@link module:font/fontsize~FontSizeConfig configuration}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontSizeEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontSizeEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t// Define default configuration using named presets.\n\t\teditor.config.define( FONT_SIZE, {\n\t\t\toptions: [\n\t\t\t\t'tiny',\n\t\t\t\t'small',\n\t\t\t\t'default',\n\t\t\t\t'big',\n\t\t\t\t'huge'\n\t\t\t]\n\t\t} );\n\n\t\t// Define view to model conversion.\n\t\tconst options = normalizeOptions( this.editor.config.get( 'fontSize.options' ) ).filter( item => item.model );\n\t\tconst definition = buildDefinition( FONT_SIZE, options );\n\n\t\t// Set-up the two-way conversion.\n\t\teditor.conversion.attributeToElement( definition );\n\n\t\t// Add FontSize command.\n\t\teditor.commands.add( FONT_SIZE, new FontSizeCommand( editor ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow fontSize attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: FONT_SIZE } );\n\t\teditor.model.schema.setAttributeProperties( FONT_SIZE, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module font/fontsize/fontsizeui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Model from '@ckeditor/ckeditor5-ui/src/model';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport {\n createDropdown,\n addListToDropdown\n} from '@ckeditor/ckeditor5-ui/src/dropdown/utils';\nimport { normalizeOptions } from './utils';\nimport { FONT_SIZE } from '../utils';\nimport fontSizeIcon from '../../theme/assets/icons/font-size.svg';\nimport '../../theme/fontsize.css';\n/**\n * The font size UI plugin. It introduces the `'fontSize'` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontSizeUI extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const t = editor.t;\n const options = this._getLocalizedOptions();\n const command = editor.commands.get(FONT_SIZE);\n // Register UI component.\n editor.ui.componentFactory.add(FONT_SIZE, locale => {\n const dropdownView = createDropdown(locale);\n addListToDropdown(dropdownView, _prepareListOptions(options, command));\n // Create dropdown model.\n dropdownView.buttonView.set({\n label: t('bt'),\n icon: fontSizeIcon,\n tooltip: true\n });\n dropdownView.extendTemplate({ attributes: { class: ['ck-font-size-dropdown'] } });\n dropdownView.bind('isEnabled').to(command);\n // Execute command when an item from the dropdown is selected.\n this.listenTo(dropdownView, 'execute', evt => {\n editor.execute(evt.source.commandName, { value: evt.source.commandParam });\n editor.editing.view.focus();\n });\n return dropdownView;\n });\n }\n /**\n\t * Returns options as defined in `config.fontSize.options` but processed to account for\n\t * editor localization, i.e. to display {@link module:font/fontsize~FontSizeOption}\n\t * in the correct language.\n\t *\n\t * Note: The reason behind this method is that there is no way to use {@link module:utils/locale~Locale#t}\n\t * when the user configuration is defined because the editor does not exist yet.\n\t *\n\t * @private\n\t * @returns {Array.<module:font/fontsize~FontSizeOption>}.\n\t */\n _getLocalizedOptions() {\n const editor = this.editor;\n const t = editor.t;\n const localizedTitles = {\n Default: t('bs'),\n Tiny: t('bu'),\n Small: t('bv'),\n Big: t('bw'),\n Huge: t('bx')\n };\n const options = normalizeOptions(editor.config.get(FONT_SIZE).options);\n return options.map(option => {\n const title = localizedTitles[option.title];\n if (title && title != option.title) {\n // Clone the option to avoid altering the original `namedPresets` from `./utils.js`.\n option = Object.assign({}, option, { title });\n }\n return option;\n });\n }\n}\n// Prepares FontSize dropdown items.\n// @private\n// @param {Array.<module:font/fontsize~FontSizeOption>} options\n// @param {module:font/fontsize/fontsizecommand~FontSizeCommand} command\nfunction _prepareListOptions(options, command) {\n const itemDefinitions = new Collection();\n for (const option of options) {\n const def = {\n type: 'button',\n model: new Model({\n commandName: FONT_SIZE,\n commandParam: option.model,\n label: option.title,\n class: 'ck-fontsize-option',\n withText: true\n })\n };\n if (option.view && option.view.styles) {\n def.model.set('labelStyle', `font-size:${ option.view.styles['font-size'] }`);\n }\n if (option.view && option.view.classes) {\n def.model.set('class', `${ def.model.class } ${ option.view.classes }`);\n }\n def.model.bind('isOn').to(command, 'value', value => value === option.model);\n // Add the option to the collection.\n itemDefinitions.add(def);\n }\n return itemDefinitions;\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M9.816 11.5L7.038 4.785 4.261 11.5h5.555zm.62 1.5H3.641l-1.666 4.028H.312l5.789-14h1.875l5.789 14h-1.663L10.436 13zm7.55 2.279l.779-.779.707.707-2.265 2.265-2.193-2.265.707-.707.765.765V4.825c0-.042 0-.083.002-.123l-.77.77-.707-.707L17.207 2.5l2.265 2.265-.707.707-.782-.782c.002.043.003.089.003.135v10.454z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 font/fontsize\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FontSizeEditing from './fontsize/fontsizeediting';\nimport FontSizeUI from './fontsize/fontsizeui';\n\n/**\n * The font size plugin.\n *\n * For a detailed overview, check the {@glink features/font font feature} documentation\n * and the {@glink api/font package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:font/fontsize/fontsizeediting~FontSizeEditing} and\n * {@link module:font/fontsize/fontsizeui~FontSizeUI} features in the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontSize extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FontSizeEditing, FontSizeUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontSize';\n\t}\n}\n\n/**\n * The font size option descriptor.\n *\n * @typedef {Object} module:font/fontsize~FontSizeOption\n *\n * @property {String} title The user-readable title of the option.\n * @property {String} model The attribute's unique value in the model.\n * @property {module:engine/view/elementdefinition~ElementDefinition} view View element configuration.\n * @property {Array.<module:engine/view/elementdefinition~ElementDefinition>} [upcastAlso] An array with all matched elements that\n * the view-to-model conversion should also accept.\n */\n\n/**\n * The configuration of the font size feature.\n * It is introduced by the {@link module:font/fontsize/fontsizeediting~FontSizeEditing} feature.\n *\n * Read more in {@link module:font/fontsize~FontSizeConfig}.\n *\n * @member {module:font/fontsize~FontSizeConfig} module:core/editor/editorconfig~EditorConfig#fontSize\n */\n\n/**\n * The configuration of the font size feature.\n * This option is used by the {@link module:font/fontsize/fontsizeediting~FontSizeEditing} feature.\n *\n * \t\tClassicEditor\n * \t\t\t.create( {\n * \t\t\t\tfontSize: ... // Font size feature configuration.\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 module:font/fontsize~FontSizeConfig\n */\n\n/**\n * Available font size options. Expressed as predefined presets, numerical \"pixel\" values\n * or the {@link module:font/fontsize~FontSizeOption}.\n *\n * The default value is:\n *\n *\t\tconst fontSizeConfig = {\n *\t\t\toptions: [\n *\t\t\t\t'tiny',\n * \t\t\t\t'small',\n * \t\t\t\t'default',\n * \t\t\t\t'big',\n * \t\t\t\t'huge'\n *\t\t\t]\n *\t\t};\n *\n * It defines 4 sizes: **tiny**, **small**, **big**, and **huge**. These values will be rendered as `<span>` elements in the view.\n * The **default** defines a text without the `fontSize` attribute.\n *\n * Each `<span>` has the the `class` attribute set to the corresponding size name. For instance, this is what the **small** size looks\n * like in the view:\n *\n * \t\t<span class=\"text-small\">...</span>\n *\n * As an alternative, the font size might be defined using numerical values (either as a `Number` or as a `String`):\n *\n * \t\tconst fontSizeConfig = {\n * \t\t\toptions: [ 9, 10, 11, 12, 13, 14, 15 ]\n * \t\t};\n *\n * Font size can be applied using the command API. To do that, use the `'fontSize'` command and pass the desired font size as a `value`.\n * For example, the following code will apply the `fontSize` attribute with the **tiny** value to the current selection:\n *\n *\t\teditor.execute( 'fontSize', { value: 'tiny' } );\n *\n * Executing the `fontSize` command without value will remove the `fontSize` attribute from the current selection.\n *\n * @member {Array.<String|Number|module:font/fontsize~FontSizeOption>} module:font/fontsize~FontSizeConfig#options\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 font/fontcolor/fontcolorcommand\n */\n\nimport FontCommand from '../fontcommand';\nimport { FONT_COLOR } from '../utils';\n\n/**\n * The font color command. It is used by {@link module:font/fontcolor/fontcolorediting~FontColorEditing}\n * to apply the font color.\n *\n *\t\teditor.execute( 'fontColor', { value: 'rgb(250, 20, 20)' } );\n *\n * **Note**: Executing the command with the `null` value removes the attribute from the model.\n *\n * @extends module:font/fontcommand~FontCommand\n */\nexport default class FontColorCommand extends FontCommand {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, FONT_COLOR );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 font/fontcolor/fontcolorediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FontColorCommand from './fontcolorcommand';\nimport { FONT_COLOR, renderDowncastElement, renderUpcastAttribute } from '../utils';\n\n/**\n * The font color editing feature.\n *\n * It introduces the {@link module:font/fontcolor/fontcolorcommand~FontColorCommand command} and\n * the `fontColor` attribute in the {@link module:engine/model/model~Model model} which renders\n * in the {@link module:engine/view/view view} as a `<span>` element (`<span style=\"color: ...\">`),\n * depending on the {@link module:font/fontcolor~FontColorConfig configuration}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontColorEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontColorEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( FONT_COLOR, {\n\t\t\tcolors: [\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 0%)',\n\t\t\t\t\tlabel: 'Black'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 30%)',\n\t\t\t\t\tlabel: 'Dim grey'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n\t\t\t\t\tlabel: 'Grey'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n\t\t\t\t\tlabel: 'Light grey'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n\t\t\t\t\tlabel: 'White',\n\t\t\t\t\thasBorder: true\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 75%, 60%)',\n\t\t\t\t\tlabel: 'Red'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(30, 75%, 60%)',\n\t\t\t\t\tlabel: 'Orange'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(60, 75%, 60%)',\n\t\t\t\t\tlabel: 'Yellow'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(90, 75%, 60%)',\n\t\t\t\t\tlabel: 'Light green'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(120, 75%, 60%)',\n\t\t\t\t\tlabel: 'Green'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(150, 75%, 60%)',\n\t\t\t\t\tlabel: 'Aquamarine'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(180, 75%, 60%)',\n\t\t\t\t\tlabel: 'Turquoise'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(210, 75%, 60%)',\n\t\t\t\t\tlabel: 'Light blue'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(240, 75%, 60%)',\n\t\t\t\t\tlabel: 'Blue'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(270, 75%, 60%)',\n\t\t\t\t\tlabel: 'Purple'\n\t\t\t\t}\n\t\t\t],\n\t\t\tcolumns: 5\n\t\t} );\n\n\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tstyles: {\n\t\t\t\t\t'color': /[\\s\\S]+/\n\t\t\t\t}\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tkey: FONT_COLOR,\n\t\t\t\tvalue: renderUpcastAttribute( 'color' )\n\t\t\t}\n\t\t} );\n\n\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\tmodel: FONT_COLOR,\n\t\t\tview: renderDowncastElement( 'color' )\n\t\t} );\n\n\t\teditor.commands.add( FONT_COLOR, new FontColorCommand( editor ) );\n\n\t\t// Allow the font color attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: FONT_COLOR } );\n\n\t\teditor.model.schema.setAttributeProperties( FONT_COLOR, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module ui/colorgrid/utils\n */\n/**\n * Returns color configuration options as defined in `editor.config.(fontColor|fontBackgroundColor).colors` or\n * `editor.config.table.(tableProperties|tableCellProperties).(background|border).colors\n * but processed to account for editor localization in the correct language.\n *\n * Note: The reason behind this method is that there is no way to use {@link module:utils/locale~Locale#t}\n * when the user configuration is defined because the editor does not exist yet.\n *\n * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.\n * @param {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>} options\n * @returns {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>}.\n */\nexport function getLocalizedColorOptions(locale, options) {\n const t = locale.t;\n const localizedColorNames = {\n Black: t('cr'),\n 'Dim grey': t('cs'),\n Grey: t('ct'),\n 'Light grey': t('cu'),\n White: t('cv'),\n Red: t('cw'),\n Orange: t('cx'),\n Yellow: t('cy'),\n 'Light green': t('cz'),\n Green: t('da'),\n Aquamarine: t('db'),\n Turquoise: t('dc'),\n 'Light blue': t('dd'),\n Blue: t('de'),\n Purple: t('df')\n };\n return options.map(colorOption => {\n const label = localizedColorNames[colorOption.label];\n if (label && label != colorOption.label) {\n colorOption.label = label;\n }\n return colorOption;\n });\n}\n/**\n * Creates a unified color definition object from color configuration options.\n * The object contains the information necessary to both render the UI and initialize the conversion.\n *\n * @param {module:ui/colorgrid/colorgrid~ColorDefinition} options\n * @returns {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>}\n */\nexport function normalizeColorOptions(options) {\n return options.map(normalizeSingleColorDefinition).filter(option => !!option);\n}\n// Creates a normalized color definition from the user-defined configuration.\n//\n// @param {String|module:ui/colorgrid/colorgrid~ColorDefinition}\n// @returns {module:ui/colorgrid/colorgrid~ColorDefinition}\nexport function normalizeSingleColorDefinition(color) {\n if (typeof color === 'string') {\n return {\n model: color.replace(/ /g, ''),\n label: color,\n hasBorder: false,\n view: {\n name: 'span',\n styles: { color }\n }\n };\n } else {\n return {\n model: color.color.replace(/ /g, ''),\n label: color.label || color.color,\n hasBorder: color.hasBorder === undefined ? false : color.hasBorder,\n view: {\n name: 'span',\n styles: { color: `${ color.color }` }\n }\n };\n }\n}","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module font/ui/colorui\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { createDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils';\nimport {\n normalizeColorOptions,\n getLocalizedColorOptions\n} from '@ckeditor/ckeditor5-ui/src/colorgrid/utils';\nimport { addColorTableToDropdown } from '../utils';\n/**\n * The color UI plugin which isolates the common logic responsible for displaying dropdowns with color grids.\n *\n * It is used to create the `'fontBackgroundColor'` and `'fontColor'` dropdowns, each hosting\n * a {@link module:font/ui/colortableview~ColorTableView}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ColorUI extends Plugin {\n /**\n\t * Creates a plugin which introduces a dropdown with a pre–configured {@link module:font/ui/colortableview~ColorTableView}.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {Object} config The configuration object.\n\t * @param {String} config.commandName The name of the command which will be executed when a color tile is clicked.\n\t * @param {String} config.componentName The name of the dropdown in the {@link module:ui/componentfactory~ComponentFactory}\n\t * and the configuration scope name in `editor.config`.\n\t * @param {String} config.icon The SVG icon used by the dropdown.\n\t * @param {String} config.dropdownLabel The label used by the dropdown.\n\t */\n constructor(editor, {commandName, icon, componentName, dropdownLabel}) {\n super(editor);\n /**\n\t\t * The name of the command which will be executed when a color tile is clicked.\n\t\t *\n\t\t * @type {String}\n\t\t */\n this.commandName = commandName;\n /**\n\t\t * The name of this component in the {@link module:ui/componentfactory~ComponentFactory}.\n\t\t * Also the configuration scope name in `editor.config`.\n\t\t *\n\t\t * @type {String}\n\t\t */\n this.componentName = componentName;\n /**\n\t\t * The SVG icon used by the dropdown.\n\t\t * @type {String}\n\t\t */\n this.icon = icon;\n /**\n\t\t * The label used by the dropdown.\n\t\t *\n\t\t * @type {String}\n\t\t */\n this.dropdownLabel = dropdownLabel;\n /**\n\t\t * The number of columns in the color grid.\n\t\t *\n\t\t * @type {Number}\n\t\t */\n this.columns = editor.config.get(`${ this.componentName }.columns`);\n /**\n\t\t * Keeps a reference to {@link module:font/ui/colortableview~ColorTableView}.\n\t\t *\n\t\t * @member {module:font/ui/colortableview~ColorTableView}\n\t\t */\n this.colorTableView;\n }\n /**\n\t * @inheritDoc\n\t */\n init() {\n const editor = this.editor;\n const locale = editor.locale;\n const t = locale.t;\n const command = editor.commands.get(this.commandName);\n const colorsConfig = normalizeColorOptions(editor.config.get(this.componentName).colors);\n const localizedColors = getLocalizedColorOptions(locale, colorsConfig);\n const documentColorsCount = editor.config.get(`${ this.componentName }.documentColors`);\n // Register the UI component.\n editor.ui.componentFactory.add(this.componentName, locale => {\n const dropdownView = createDropdown(locale);\n this.colorTableView = addColorTableToDropdown({\n dropdownView,\n colors: localizedColors.map(option => ({\n label: option.label,\n color: option.model,\n options: { hasBorder: option.hasBorder }\n })),\n columns: this.columns,\n removeButtonLabel: t('cp'),\n documentColorsLabel: documentColorsCount !== 0 ? t('cq') : undefined,\n documentColorsCount: documentColorsCount === undefined ? this.columns : documentColorsCount\n });\n this.colorTableView.bind('selectedColor').to(command, 'value');\n dropdownView.buttonView.set({\n label: this.dropdownLabel,\n icon: this.icon,\n tooltip: true\n });\n dropdownView.extendTemplate({ attributes: { class: 'ck-color-ui-dropdown' } });\n dropdownView.bind('isEnabled').to(command);\n dropdownView.on('execute', (evt, data) => {\n editor.execute(this.commandName, data);\n editor.editing.view.focus();\n });\n dropdownView.on('change:isOpen', (evt, name, isVisible) => {\n // Grids rendering is deferred (#6192).\n dropdownView.colorTableView.appendGrids();\n if (isVisible) {\n if (documentColorsCount !== 0) {\n this.colorTableView.updateDocumentColors(editor.model, this.componentName);\n }\n this.colorTableView.updateSelectedColors();\n }\n });\n return dropdownView;\n });\n }\n}","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module font/fontcolor/fontcolorui\n */\nimport ColorUI from '../ui/colorui';\nimport { FONT_COLOR } from '../utils';\nimport fontColorIcon from '../../theme/assets/icons/font-color.svg';\n/**\n * The font color UI plugin. It introduces the `'fontColor'` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontColorUI extends ColorUI {\n /**\n\t * @inheritDoc\n\t */\n constructor(editor) {\n const t = editor.locale.t;\n super(editor, {\n commandName: FONT_COLOR,\n componentName: FONT_COLOR,\n icon: fontColorIcon,\n dropdownLabel: t('bq')\n });\n }\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'FontColorUI';\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M12.4 10.3L10 4.5l-2.4 5.8h4.8zm.5 1.2H7.1L5.7 15H4.2l5-12h1.6l5 12h-1.5L13 11.5zm3.1 7H4a1 1 0 010-2h12a1 1 0 010 2z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 font/fontcolor\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FontColorEditing from './fontcolor/fontcolorediting';\nimport FontColorUI from './fontcolor/fontcolorui';\n\n/**\n * The font color plugin.\n *\n * For a detailed overview, check the {@glink features/font font feature} documentation\n * and the {@glink api/font package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:font/fontcolor/fontcolorediting~FontColorEditing} and\n * {@link module:font/fontcolor/fontcolorui~FontColorUI} features in the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontColor extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FontColorEditing, FontColorUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontColor';\n\t}\n}\n\n/**\n * The configuration of the font color feature.\n * It is introduced by the {@link module:font/fontcolor/fontcolorediting~FontColorEditing} feature.\n *\n * Read more in {@link module:font/fontcolor~FontColorConfig}.\n *\n * @member {module:font/fontcolor~FontColorConfig} module:core/editor/editorconfig~EditorConfig#fontColor\n */\n\n/**\n * The configuration of the font color feature.\n * This option is used by the {@link module:font/fontcolor/fontcolorediting~FontColorEditing} feature.\n *\n *\t\tClassicEditor\n *\t\t\t.create( {\n *\t\t\t\tfontColor: ... // Font color feature configuration.\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 module:font/fontcolor~FontColorConfig\n */\n\n/**\n * Available font colors defined as an array of strings or objects.\n *\n * The default value registers the following colors:\n *\n *\t\tconst fontColorConfig = {\n *\t\t\tcolors: [\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 0%)',\n *\t\t\t\t\tlabel: 'Black'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 30%)',\n *\t\t\t\t\tlabel: 'Dim grey'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n *\t\t\t\t\tlabel: 'Grey'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n *\t\t\t\t\tlabel: 'Light grey'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n *\t\t\t\t\tlabel: 'White',\n *\t\t\t\t\thasBorder: true\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Red'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(30, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Orange'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(60, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Yellow'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(90, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Light green'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(120, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Green'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(150, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Aquamarine'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(180, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Turquoise'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(210, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Light blue'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(240, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Blue'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(270, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Purple'\n *\t\t\t\t}\n *\t\t\t]\n *\t\t};\n *\n * **Note**: The colors are displayed in the `'fontColor'` dropdown.\n *\n * @member {Array.<String|Object>} module:font/fontcolor~FontColorConfig#colors\n */\n\n/**\n * Represents the number of columns in the font color dropdown.\n *\n * The default value is:\n *\n *\t\tconst fontColorConfig = {\n *\t\t\tcolumns: 5\n *\t\t}\n *\n * @member {Number} module:font/fontcolor~FontColorConfig#columns\n */\n\n/**\n * Determines the maximum number of available document colors.\n * Setting it to `0` will disable the document colors feature.\n *\n * By default it equals to the {@link module:font/fontcolor~FontColorConfig#columns} value.\n *\n * Examples:\n *\n * \t// 1) Neither document colors nor columns are defined in the configuration.\n * \t// Document colors will equal 5,\n * \t// because the value will be inherited from columns,\n * \t// which has a predefined value of 5.\n * \tconst fontColorConfig = {}\n *\n * \t// 2) Document colors will equal 8, because the value will be inherited from columns.\n * \tconst fontColorConfig = {\n * \t\tcolumns: 8\n * \t}\n *\n * \t// 3) Document colors will equal 24, because it has its own value defined.\n * \tconst fontColorConfig = {\n * \t\tcolumns: 8,\n * \t\tdocumentColors: 24\n * \t}\n *\n * \t// 4) The document colors feature will be disabled.\n * \tconst fontColorConfig = {\n * \t\tcolumns: 8,\n * \t\tdocumentColors: 0\n * \t}\n *\n * @member {Number} module:font/fontcolor~FontColorConfig#documentColors\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 font/fontbackgroundcolor/fontbackgroundcolorcommand\n */\n\nimport FontCommand from '../fontcommand';\nimport { FONT_BACKGROUND_COLOR } from '../utils';\n\n/**\n * The font background color command. It is used by\n * {@link module:font/fontbackgroundcolor/fontbackgroundcolorediting~FontBackgroundColorEditing}\n * to apply the font background color.\n *\n *\t\teditor.execute( 'fontBackgroundColor', { value: 'rgb(250, 20, 20)' } );\n *\n * **Note**: Executing the command with the `null` value removes the attribute from the model.\n *\n * @extends module:font/fontcommand~FontCommand\n */\nexport default class FontBackgroundColorCommand extends FontCommand {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, FONT_BACKGROUND_COLOR );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 font/fontbackgroundcolor/fontbackgroundcolorediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FontBackgroundColorCommand from './fontbackgroundcolorcommand';\nimport { FONT_BACKGROUND_COLOR, renderDowncastElement, renderUpcastAttribute } from '../utils';\n\n/**\n * The font background color editing feature.\n *\n * It introduces the {@link module:font/fontbackgroundcolor/fontbackgroundcolorcommand~FontBackgroundColorCommand command} and\n * the `fontBackgroundColor` attribute in the {@link module:engine/model/model~Model model} which renders\n * in the {@link module:engine/view/view view} as a `<span>` element (`<span style=\"background-color: ...\">`),\n * depending on the {@link module:font/fontbackgroundcolor~FontBackgroundColorConfig configuration}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontBackgroundColorEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontBackgroundColorEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( FONT_BACKGROUND_COLOR, {\n\t\t\tcolors: [\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 0%)',\n\t\t\t\t\tlabel: 'Black'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 30%)',\n\t\t\t\t\tlabel: 'Dim grey'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n\t\t\t\t\tlabel: 'Grey'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n\t\t\t\t\tlabel: 'Light grey'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n\t\t\t\t\tlabel: 'White',\n\t\t\t\t\thasBorder: true\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 75%, 60%)',\n\t\t\t\t\tlabel: 'Red'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(30, 75%, 60%)',\n\t\t\t\t\tlabel: 'Orange'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(60, 75%, 60%)',\n\t\t\t\t\tlabel: 'Yellow'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(90, 75%, 60%)',\n\t\t\t\t\tlabel: 'Light green'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(120, 75%, 60%)',\n\t\t\t\t\tlabel: 'Green'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(150, 75%, 60%)',\n\t\t\t\t\tlabel: 'Aquamarine'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(180, 75%, 60%)',\n\t\t\t\t\tlabel: 'Turquoise'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(210, 75%, 60%)',\n\t\t\t\t\tlabel: 'Light blue'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(240, 75%, 60%)',\n\t\t\t\t\tlabel: 'Blue'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(270, 75%, 60%)',\n\t\t\t\t\tlabel: 'Purple'\n\t\t\t\t}\n\t\t\t],\n\t\t\tcolumns: 5\n\t\t} );\n\n\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tstyles: {\n\t\t\t\t\t'background-color': /[\\s\\S]+/\n\t\t\t\t}\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tkey: FONT_BACKGROUND_COLOR,\n\t\t\t\tvalue: renderUpcastAttribute( 'background-color' )\n\t\t\t}\n\t\t} );\n\n\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\tmodel: FONT_BACKGROUND_COLOR,\n\t\t\tview: renderDowncastElement( 'background-color' )\n\t\t} );\n\n\t\teditor.commands.add( FONT_BACKGROUND_COLOR, new FontBackgroundColorCommand( editor ) );\n\n\t\t// Allow the font backgroundColor attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: FONT_BACKGROUND_COLOR } );\n\n\t\teditor.model.schema.setAttributeProperties( FONT_BACKGROUND_COLOR, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module font/fontbackgroundcolor/fontbackgroundcolorui\n */\nimport ColorUI from '../ui/colorui';\nimport { FONT_BACKGROUND_COLOR } from '../utils';\nimport fontBackgroundColorIcon from '../../theme/assets/icons/font-background.svg';\n/**\n * The font background color UI plugin. It introduces the `'fontBackgroundColor'` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontBackgroundColorUI extends ColorUI {\n /**\n\t * @inheritDoc\n\t */\n constructor(editor) {\n const t = editor.locale.t;\n super(editor, {\n commandName: FONT_BACKGROUND_COLOR,\n componentName: FONT_BACKGROUND_COLOR,\n icon: fontBackgroundColorIcon,\n dropdownLabel: t('bp')\n });\n }\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'FontBackgroundColorUI';\n }\n}","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M4 2h12a2 2 0 012 2v12a2 2 0 01-2 2H4a2 2 0 01-2-2V4a2 2 0 012-2zm8.38 9.262H7.62L10 5.506l2.38 5.756zm.532 1.285L14.34 16h1.426L10.804 4H9.196L4.234 16H5.66l1.428-3.453h5.824z\\\"/></svg>\"","/**\n * @license Copyright (c) 2003-2020, 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 font/fontbackgroundcolor\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FontBackgroundColorEditing from './fontbackgroundcolor/fontbackgroundcolorediting';\nimport FontBackgroundColorUI from './fontbackgroundcolor/fontbackgroundcolorui';\n\n/**\n * The font background color plugin.\n *\n * For a detailed overview, check the {@glink features/font font feature} documentation\n * and the {@glink api/font package page}.\n *\n * This is a \"glue\" plugin which loads\n * the {@link module:font/fontbackgroundcolor/fontbackgroundcolorediting~FontBackgroundColorEditing} and\n * {@link module:font/fontbackgroundcolor/fontbackgroundcolorui~FontBackgroundColorUI} features in the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontBackgroundColor extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FontBackgroundColorEditing, FontBackgroundColorUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontBackgroundColor';\n\t}\n}\n\n/**\n * The configuration of the font background color feature.\n * It is introduced by the {@link module:font/fontbackgroundcolor/fontbackgroundcolorediting~FontBackgroundColorEditing} feature.\n *\n * Read more in {@link module:font/fontbackgroundcolor~FontBackgroundColorConfig}.\n *\n * @member {module:font/fontbackgroundcolor~FontBackgroundColorConfig} module:core/editor/editorconfig~EditorConfig#fontBackgroundColor\n */\n\n/**\n * The configuration of the font background color feature.\n * This option is used by the {@link module:font/fontbackgroundcolor/fontbackgroundcolorediting~FontBackgroundColorEditing} feature.\n *\n *\t\tClassicEditor\n *\t\t\t.create( {\n *\t\t\t\tfontBackgroundColor: ... // Font background color feature configuration.\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 module:font/fontbackgroundcolor~FontBackgroundColorConfig\n */\n\n/**\n * Available font background colors defined as an array of strings or objects.\n *\n * The default value registers the following colors:\n *\n *\t\tconst fontBackgroundColorConfig = {\n *\t\t\tcolors: [\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 0%)',\n *\t\t\t\t\tlabel: 'Black'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 30%)',\n *\t\t\t\t\tlabel: 'Dim grey'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n *\t\t\t\t\tlabel: 'Grey'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n *\t\t\t\t\tlabel: 'Light grey'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n *\t\t\t\t\tlabel: 'White',\n *\t\t\t\t\thasBorder: true\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Red'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(30, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Orange'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(60, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Yellow'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(90, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Light green'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(120, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Green'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(150, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Aquamarine'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(180, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Turquoise'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(210, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Light blue'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(240, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Blue'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(270, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Purple'\n *\t\t\t\t}\n *\t\t\t]\n *\t\t};\n *\n * **Note**: The colors are displayed in the `'fontBackgroundColor'` dropdown.\n *\n * @member {Array.<String|Object>} module:font/fontbackgroundcolor~FontBackgroundColorConfig#colors\n */\n\n/**\n * Represents the number of columns in the font background color dropdown.\n *\n * The default value is:\n *\n *\t\tconst fontBackgroundColorConfig = {\n *\t\t\tcolumns: 5\n *\t\t}\n *\n * @member {Number} module:font/fontbackgroundcolor~FontBackgroundColorConfig#columns\n */\n\n/**\n * Determines the maximum number of available document colors.\n * Setting it to `0` will disable the document colors feature.\n *\n * By default it equals to the {@link module:font/fontbackgroundcolor~FontBackgroundColorConfig#columns} value.\n *\n * Examples:\n *\n * \t// 1) Neither document colors nor columns are defined in the configuration.\n * \t// Document colors will equal 5,\n * \t// because the value will be inherited from columns,\n * \t// which has a predefined value of 5.\n * \tconst fontBackgroundColorConfig = {}\n *\n * \t// 2) Document colors will equal 8, because the value will be inherited from columns.\n * \tconst fontBackgroundColorConfig = {\n * \t\tcolumns: 8\n * \t}\n *\n * \t// 3) Document colors will equal 24, because it has its own value defined.\n * \tconst fontBackgroundColorConfig = {\n * \t\tcolumns: 8,\n * \t\tdocumentColors: 24\n * \t}\n *\n * \t// 4) The document colors feature will be disabled.\n * \tconst fontBackgroundColorConfig = {\n * \t\tcolumns: 8,\n * \t\tdocumentColors: 0\n * \t}\n *\n * @member {Number} module:font/fontbackgroundcolor~FontBackgroundColorConfig#documentColors\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n// The editor creator to use.\nimport ClassicEditorBase from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';\n\nimport Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';\nimport UploadAdapter from '@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter';\nimport Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat';\nimport Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';\nimport Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';\nimport BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote';\nimport CKFinder from '@ckeditor/ckeditor5-ckfinder/src/ckfinder';\nimport EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage';\nimport Heading from '@ckeditor/ckeditor5-heading/src/heading';\nimport Image from '@ckeditor/ckeditor5-image/src/image';\nimport ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption';\nimport ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle';\nimport ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar';\nimport ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload';\nimport Indent from '@ckeditor/ckeditor5-indent/src/indent';\nimport Link from '@ckeditor/ckeditor5-link/src/link';\nimport List from '@ckeditor/ckeditor5-list/src/list';\nimport MediaEmbed from '@ckeditor/ckeditor5-media-embed/src/mediaembed';\nimport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\nimport PasteFromOffice from '@ckeditor/ckeditor5-paste-from-office/src/pastefromoffice';\nimport Table from '@ckeditor/ckeditor5-table/src/table';\nimport TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar';\n\n// NEW Minteck Projects Features\nimport Underline from '@ckeditor/ckeditor5-basic-styles/src/underline';\nimport Strikethrough from '@ckeditor/ckeditor5-basic-styles/src/strikethrough';\nimport Code from '@ckeditor/ckeditor5-basic-styles/src/code';\nimport Subscript from '@ckeditor/ckeditor5-basic-styles/src/subscript';\nimport Superscript from '@ckeditor/ckeditor5-basic-styles/src/superscript';\nimport RemoveFormat from '@ckeditor/ckeditor5-remove-format/src/removeformat';\nimport HorizontalLine from '@ckeditor/ckeditor5-horizontal-line/src/horizontalline';\nimport Base64UploadAdapter from '@ckeditor/ckeditor5-upload/src/adapters/base64uploadadapter';\nimport Alignment from '@ckeditor/ckeditor5-alignment/src/alignment';\nimport ImageResize from '@ckeditor/ckeditor5-image/src/imageresize'\nimport Font from '@ckeditor/ckeditor5-font/src/font';\n\nexport default class ClassicEditor extends ClassicEditorBase {}\n\n// Plugins to include in the build.\nClassicEditor.builtinPlugins = [\n\tEssentials,\n\tUploadAdapter,\n\tAutoformat,\n\tBold,\n\tItalic,\n\tBlockQuote,\n\tCKFinder,\n\tEasyImage,\n\tHeading,\n\tImage,\n\tImageCaption,\n\tImageStyle,\n\tImageToolbar,\n\tImageUpload,\n\tIndent,\n\tLink,\n\tList,\n\tMediaEmbed,\n\tParagraph,\n\tPasteFromOffice,\n\tTable,\n\tTableToolbar,\n\t// Minteck Projects Plugins\n\tUnderline,\n\tStrikethrough,\n\tCode,\n\tSubscript,\n\tSuperscript,\n\tRemoveFormat,\n\tHorizontalLine,\n\tBase64UploadAdapter,\n\tAlignment,\n\tImageResize,\n\tFont\n];\n\n// Editor configuration.\nClassicEditor.defaultConfig = {\n\ttoolbar: {\n\t\titems: [\n\t\t\t'heading',\n\t\t\t'|',\n\t\t\t'bold',\n\t\t\t'italic',\n\t\t\t'link',\n\t\t\t'bulletedList',\n\t\t\t'numberedList',\n\t\t\t'|',\n\t\t\t'indent',\n\t\t\t'outdent',\n\t\t\t'|',\n\t\t\t'imageUpload',\n\t\t\t'blockQuote',\n\t\t\t'insertTable',\n\t\t\t'mediaEmbed',\n\t\t\t'undo',\n\t\t\t'redo'\n\t\t]\n\t},\n\timage: {\n\t\ttoolbar: [\n\t\t\t'imageStyle:full',\n\t\t\t'imageStyle:side',\n\t\t\t'|',\n\t\t\t'imageTextAlternative'\n\t\t]\n\t},\n\ttable: {\n\t\tcontentToolbar: [\n\t\t\t'tableColumn',\n\t\t\t'tableRow',\n\t\t\t'mergeTableCells'\n\t\t]\n\t},\n\t// This value must be kept in sync with the language defined in webpack.config.js.\n\tlanguage: 'en'\n};\n","/**\n * @license Copyright (c) 2003-2020, 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 essentials/essentials\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';\nimport Enter from '@ckeditor/ckeditor5-enter/src/enter';\nimport ShiftEnter from '@ckeditor/ckeditor5-enter/src/shiftenter';\nimport Typing from '@ckeditor/ckeditor5-typing/src/typing';\nimport Undo from '@ckeditor/ckeditor5-undo/src/undo';\n\n/**\n * A plugin including all essential editing features. It represents a set of features that enables similar functionalities\n * to a `<textarea>` element.\n *\n * It includes:\n *\n * * {@link module:clipboard/clipboard~Clipboard},\n * * {@link module:enter/enter~Enter},\n * * {@link module:enter/shiftenter~ShiftEnter},\n * * {@link module:typing/typing~Typing},\n * * {@link module:undo/undo~Undo}.\n *\n * This plugin set does not define any block-level containers (such as {@link module:paragraph/paragraph~Paragraph}).\n * If your editor is supposed to handle block content, make sure to include it.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Essentials extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Clipboard, Enter, ShiftEnter, Typing, Undo ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Essentials';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/bold\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport BoldEditing from './bold/boldediting';\nimport BoldUI from './bold/boldui';\n\n/**\n * The bold feature.\n *\n * For a detailed overview check the {@glink features/basic-styles Basic styles feature documentation}\n * and the {@glink api/basic-styles package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:basic-styles/bold/boldediting~BoldEditing bold editing feature}\n * and {@link module:basic-styles/bold/boldui~BoldUI bold UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Bold extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ BoldEditing, BoldUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Bold';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/italic\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ItalicEditing from './italic/italicediting';\nimport ItalicUI from './italic/italicui';\n\n/**\n * The italic feature.\n *\n * For a detailed overview check the {@glink features/basic-styles Basic styles feature documentation}\n * and the {@glink api/basic-styles package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:basic-styles/italic/italicediting~ItalicEditing} and\n * {@link module:basic-styles/italic/italicui~ItalicUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Italic extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ItalicEditing, ItalicUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Italic';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 block-quote/blockquote\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport BlockQuoteEditing from './blockquoteediting';\nimport BlockQuoteUI from './blockquoteui';\n\n/**\n * The block quote plugin.\n *\n * For more information about this feature check the {@glink api/block-quote package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:block-quote/blockquoteediting~BlockQuoteEditing block quote editing feature}\n * and {@link module:block-quote/blockquoteui~BlockQuoteUI block quote UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BlockQuote extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ BlockQuoteEditing, BlockQuoteUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BlockQuote';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 ckfinder/ckfinder\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport CKFinderUI from './ckfinderui';\nimport CKFinderEditing from './ckfinderediting';\nimport CKFinderUploadAdapter from '@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter';\n\n/**\n * The CKFinder feature, a bridge between the CKEditor 5 WYSIWYG editor and the\n * [CKFinder](https://ckeditor.com/ckfinder) file manager and uploader.\n *\n * This is a \"glue\" plugin which enables:\n *\n * * {@link module:ckfinder/ckfinderediting~CKFinderEditing},\n * * {@link module:ckfinder/ckfinderui~CKFinderUI},\n * * {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter}.\n *\n * See the {@glink features/image-upload/ckfinder \"CKFinder integration\" guide} to learn how to configure\n * and use this feature.\n *\n * Check out the {@glink features/image-upload/image-upload comprehensive \"Image upload\" guide} to learn about\n * other ways to upload images into CKEditor 5.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CKFinder extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CKFinder';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ CKFinderEditing, CKFinderUI, CKFinderUploadAdapter ];\n\t}\n}\n\n/**\n * The configuration of the {@link module:ckfinder/ckfinder~CKFinder CKFinder feature}.\n *\n * Read more in {@link module:ckfinder/ckfinder~CKFinderConfig}.\n *\n * @member {module:ckfinder/ckfinder~CKFinderConfig} module:core/editor/editorconfig~EditorConfig#ckfinder\n */\n\n/**\n * The configuration of the {@link module:ckfinder/ckfinder~CKFinder CKFinder feature}\n * and its {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter upload adapter}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tckfinder: {\n *\t\t\t\t\toptions: {\n *\t\t\t\t\t\tresourceType: 'Images'\n *\t\t\t\t\t}\n *\t\t\t\t}\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 CKFinderConfig\n */\n\n/**\n * The configuration options passed to the CKFinder file manager instance.\n *\n * Check the file manager [documentation](https://ckeditor.com/docs/ckfinder/ckfinder3/#!/api/CKFinder.Config-cfg-language)\n * for the complete list of options.\n *\n * @member {Object} module:ckfinder/ckfinder~CKFinderConfig#options\n */\n\n/**\n * The type of the CKFinder opener method.\n *\n * Supported types are:\n *\n * * `'modal'` – Opens CKFinder in a modal,\n * * `'popup'` – Opens CKFinder in a new \"pop-up\" window.\n *\n * Defaults to `'modal'`.\n *\n * @member {String} module:ckfinder/ckfinder~CKFinderConfig#openerMethod\n */\n\n/**\n * The path (URL) to the connector which handles the file upload in CKFinder file manager.\n * When specified, it enables the automatic upload of resources such as images inserted into the content.\n *\n * For instance, to use CKFinder's\n * [quick upload](https://ckeditor.com/docs/ckfinder/ckfinder3-php/commands.html#command_quick_upload)\n * command, your can use the following (or similar) path:\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tckfinder: {\n *\t\t\t\t\tuploadUrl: '/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Files&responseType=json'\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * Used by the {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter upload adapter}.\n *\n * @member {String} module:ckfinder/ckfinder~CKFinderConfig#uploadUrl\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 easy-image/easyimage\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport CloudServicesUploadAdapter from './cloudservicesuploadadapter';\nimport Image from '@ckeditor/ckeditor5-image/src/image';\nimport ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload';\n\n/**\n * The Easy Image feature, which makes the image upload in CKEditor 5 possible with virtually zero\n * server setup. A part of the [CKEditor Cloud Services](https://ckeditor.com/ckeditor-cloud-services/)\n * family.\n *\n * This is a \"glue\" plugin which enables:\n *\n * * {@link module:image/image~Image},\n * * {@link module:image/imageupload~ImageUpload},\n * * {@link module:easy-image/cloudservicesuploadadapter~CloudServicesUploadAdapter}.\n *\n * See the {@glink features/image-upload/easy-image \"Easy Image integration\" guide} to learn how to configure\n * and use this feature.\n *\n * Check out the {@glink features/image-upload/image-upload comprehensive \"Image upload\" guide} to learn about\n * other ways to upload images into CKEditor 5.\n *\n * **Note**: After enabling the Easy Image plugin you need to configure the\n * [CKEditor Cloud Services](https://ckeditor.com/ckeditor-cloud-services/)\n * integration through {@link module:cloud-services/cloudservices~CloudServicesConfig `config.cloudServices`}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class EasyImage extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [\n\t\t\tCloudServicesUploadAdapter,\n\t\t\tImage,\n\t\t\tImageUpload\n\t\t];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'EasyImage';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 heading/heading\n */\n\nimport HeadingEditing from './headingediting';\nimport HeadingUI from './headingui';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport '../theme/heading.css';\n\n/**\n * The headings feature.\n *\n * For a detailed overview, check the {@glink features/headings Headings feature documentation}\n * and the {@glink api/heading package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:heading/headingediting~HeadingEditing heading editing feature}\n * and {@link module:heading/headingui~HeadingUI heading UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Heading extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ HeadingEditing, HeadingUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Heading';\n\t}\n}\n\n/**\n * The configuration of the heading feature. Introduced by the {@link module:heading/headingediting~HeadingEditing} feature.\n *\n * Read more in {@link module:heading/heading~HeadingConfig}.\n *\n * @member {module:heading/heading~HeadingConfig} module:core/editor/editorconfig~EditorConfig#heading\n */\n\n/**\n * The configuration of the heading feature.\n * The option is used by the {@link module:heading/headingediting~HeadingEditing} feature.\n *\n *\t\tClassicEditor\n *\t\t\t.create( {\n * \t\t\t\theading: ... // Heading feature config.\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 HeadingConfig\n */\n\n/**\n * The available heading options.\n *\n * The default value is:\n *\n *\t\tconst headingConfig = {\n *\t\t\toptions: [\n *\t\t\t\t{ model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },\n *\t\t\t\t{ model: 'heading1', view: 'h2', title: 'Heading 1', class: 'ck-heading_heading1' },\n *\t\t\t\t{ model: 'heading2', view: 'h3', title: 'Heading 2', class: 'ck-heading_heading2' },\n *\t\t\t\t{ model: 'heading3', view: 'h4', title: 'Heading 3', class: 'ck-heading_heading3' }\n *\t\t\t]\n *\t\t};\n *\n * It defines 3 levels of headings. In the editor model they will use `heading1`, `heading2`, and `heading3` elements.\n * Their respective view elements (so the elements output by the editor) will be: `h2`, `h3`, and `h4`. This means that\n * if you choose \"Heading 1\" in the headings dropdown the editor will turn the current block to `<heading1>` in the model\n * which will result in rendering (and outputting to data) the `<h2>` element.\n *\n * The `title` and `class` properties will be used by the `headings` dropdown to render available options.\n * Usually, the first option in the headings dropdown is the \"Paragraph\" option, hence it's also defined on the list.\n * However, you don't need to define its view representation because it's handled by\n * the {@link module:paragraph/paragraph~Paragraph} feature (which is required by\n * the {@link module:heading/headingediting~HeadingEditing} feature).\n *\n * You can **read more** about configuring heading levels and **see more examples** in\n * the {@glink features/headings Headings} guide.\n *\n * Note: In the model you should always start from `heading1`, regardless of how the headings are represented in the view.\n * That's assumption is used by features like {@link module:autoformat/autoformat~Autoformat} to know which element\n * they should use when applying the first level heading.\n *\n * The defined headings are also available as values passed to the `'heading'` command under their model names.\n * For example, the below code will apply `<heading1>` to the current selection:\n *\n *\t\teditor.execute( 'heading', { value: 'heading1' } );\n *\n * @member {Array.<module:heading/heading~HeadingOption>} module:heading/heading~HeadingConfig#options\n */\n\n/**\n * Heading option descriptor.\n *\n * @typedef {Object} module:heading/heading~HeadingOption\n * @property {String} model Name of the model element to convert.\n * @property {module:engine/view/elementdefinition~ElementDefinition} view Definition of a view element to convert from/to.\n * @property {String} title The user-readable title of the option.\n * @property {String} class The class which will be added to the dropdown item representing this option.\n * @property {String} [icon] Icon used by {@link module:heading/headingbuttonsui~HeadingButtonsUI}. It can be omitted when using\n * the default configuration.\n * @extends module:engine/conversion/conversion~ConverterDefinition\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 image/imagecaption\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageCaptionEditing from './imagecaption/imagecaptionediting';\n\nimport '../theme/imagecaption.css';\n\n/**\n * The image caption plugin.\n *\n * For a detailed overview, check the {@glink features/image#image-captions image caption} documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageCaption extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageCaptionEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageCaption';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 image/imagestyle\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageStyleEditing from './imagestyle/imagestyleediting';\nimport ImageStyleUI from './imagestyle/imagestyleui';\n\n/**\n * The image style plugin.\n *\n * For a detailed overview, check the {@glink features/image#image-styles image styles} documentation.\n *\n * This is a \"glue\" plugin which loads the {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing}\n * and {@link module:image/imagestyle/imagestyleui~ImageStyleUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageStyle extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageStyleEditing, ImageStyleUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageStyle';\n\t}\n}\n\n/**\n * Available image styles.\n *\n * The default value is:\n *\n *\t\tconst imageConfig = {\n *\t\t\tstyles: [ 'full', 'side' ]\n *\t\t};\n *\n * which configures two default styles:\n *\n * * the \"full\" style which does not apply any class, e.g. for images styled to span 100% width of the content,\n * * the \"side\" style with the `.image-style-side` CSS class.\n *\n * See {@link module:image/imagestyle/utils~defaultStyles} to learn more about default\n * styles provided by the image feature.\n *\n * The {@link module:image/imagestyle/utils~defaultStyles default styles} can be customized,\n * e.g. to change the icon, title or CSS class of the style. The feature also provides several\n * {@link module:image/imagestyle/utils~defaultIcons default icons} to choose from.\n *\n *\t\timport customIcon from 'custom-icon.svg';\n *\n *\t\t// ...\n *\n *\t\tconst imageConfig = {\n *\t\t\tstyles: [\n *\t\t\t\t// This will only customize the icon of the \"full\" style.\n *\t\t\t\t// Note: 'right' is one of default icons provided by the feature.\n *\t\t\t\t{ name: 'full', icon: 'right' },\n *\n *\t\t\t\t// This will customize the icon, title and CSS class of the default \"side\" style.\n *\t\t\t\t{ name: 'side', icon: customIcon, title: 'My side style', className: 'custom-side-image' }\n *\t\t\t]\n *\t\t};\n *\n * If none of the default styles is good enough, it is possible to define independent custom styles, too:\n *\n *\t\timport fullSizeIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/object-center.svg';\n *\t\timport sideIcon from '@ckeditor/ckeditor5-core/theme/assets/icons/object-right.svg';\n *\n *\t\t// ...\n *\n *\t\tconst imageConfig = {\n *\t\t\tstyles: [\n *\t\t\t\t// A completely custom full size style with no class, used as a default.\n *\t\t\t\t{ name: 'fullSize', title: 'Full size', icon: fullSizeIcon, isDefault: true },\n *\n *\t\t\t\t{ name: 'side', title: 'To the side', icon: sideIcon, className: 'side-image' }\n *\t\t\t]\n *\t\t};\n *\n * Note: Setting `title` to one of {@link module:image/imagestyle/imagestyleui~ImageStyleUI#localizedDefaultStylesTitles}\n * will automatically translate it to the language of the editor.\n *\n * Read more about styling images in the {@glink features/image#image-styles Image styles guide}.\n *\n * The feature creates commands based on defined styles, so you can change the style of a selected image by executing\n * the following command:\n *\n *\t\teditor.execute( 'imageStyle' { value: 'side' } );\n *\n * The feature also creates buttons that execute the commands. So, assuming that you use the\n * default image styles setting, you can {@link module:image/image~ImageConfig#toolbar configure the image toolbar}\n * (or any other toolbar) to contain these options:\n *\n *\t\tconst imageConfig = {\n *\t\t\ttoolbar: [ 'imageStyle:full', 'imageStyle:side' ]\n *\t\t};\n *\n * @member {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} module:image/image~ImageConfig#styles\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module image/imagetoolbar\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { getSelectedImageWidget } from './image/utils';\nimport WidgetToolbarRepository from '@ckeditor/ckeditor5-widget/src/widgettoolbarrepository';\n/**\n * The image toolbar plugin. It creates and manages the image toolbar (the toolbar displayed when an image is selected).\n *\n * For a detailed overview, check the {@glink features/image#image-contextual-toolbar image contextual toolbar} documentation.\n *\n * Instances of toolbar components (e.g. buttons) are created using the editor's\n * {@link module:ui/componentfactory~ComponentFactory component factory}\n * based on the {@link module:image/image~ImageConfig#toolbar `image.toolbar` configuration option}.\n *\n * The toolbar uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageToolbar extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get requires() {\n return [WidgetToolbarRepository];\n }\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'ImageToolbar';\n }\n /**\n\t * @inheritDoc\n\t */\n afterInit() {\n const editor = this.editor;\n const t = editor.t;\n const widgetToolbarRepository = editor.plugins.get(WidgetToolbarRepository);\n widgetToolbarRepository.register('image', {\n ariaLabel: t('b'),\n items: editor.config.get('image.toolbar') || [],\n getRelatedElement: getSelectedImageWidget\n });\n }\n} /**\n * Items to be placed in the image toolbar.\n * This option is used by the {@link module:image/imagetoolbar~ImageToolbar} feature.\n *\n * Assuming that you use the following features:\n *\n * * {@link module:image/imagestyle~ImageStyle} (with a default configuration),\n * * {@link module:image/imagetextalternative~ImageTextAlternative},\n *\n * three toolbar items will be available in {@link module:ui/componentfactory~ComponentFactory}:\n * `'imageStyle:full'`, `'imageStyle:side'`, and `'imageTextAlternative'` so you can configure the toolbar like this:\n *\n *\t\tconst imageConfig = {\n *\t\t\ttoolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ]\n *\t\t};\n *\n * Of course, the same buttons can also be used in the\n * {@link module:core/editor/editorconfig~EditorConfig#toolbar main editor toolbar}.\n *\n * Read more about configuring toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.<String>} module:image/image~ImageConfig#toolbar\n */","/**\n * @license Copyright (c) 2003-2020, 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 indent/indent\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport IndentEditing from './indentediting';\nimport IndentUI from './indentui';\n\n/**\n * The indent feature.\n *\n * This plugin acts as a single entry point plugin for other features that implement indentation of elements like lists or paragraphs.\n *\n * The compatible features are:\n *\n * * The {@link module:list/list~List} or {@link module:list/listediting~ListEditing} feature for list indentation.\n * * The {@link module:indent/indentblock~IndentBlock} feature for block indentation.\n *\n * This is a \"glue\" plugin that loads the following plugins:\n *\n * * The {@link module:indent/indentediting~IndentEditing indent editing feature}.\n * * The {@link module:indent/indentui~IndentUI indent UI feature}.\n *\n * The dependent plugins register the `'indent'` and `'outdent'` commands and introduce the `'indent'` and `'outdent'` buttons\n * that allow to increase or decrease text indentation of supported elements.\n *\n * **Note**: In order for the commands and buttons to work, at least one of compatible features is required.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Indent extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Indent';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ IndentEditing, IndentUI ];\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 link/link\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport LinkEditing from './linkediting';\nimport LinkUI from './linkui';\n\n/**\n * The link plugin.\n *\n * This is a \"glue\" plugin that loads the {@link module:link/linkediting~LinkEditing link editing feature}\n * and {@link module:link/linkui~LinkUI link UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Link extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ LinkEditing, LinkUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Link';\n\t}\n}\n\n/**\n * The configuration of the {@link module:link/link~Link} feature.\n *\n * Read more in {@link module:link/link~LinkConfig}.\n *\n * @member {module:link/link~LinkConfig} module:core/editor/editorconfig~EditorConfig#link\n */\n\n/**\n * The configuration of the {@link module:link/link~Link link feature}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\tlink: ... // Link feature configuration.\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 * @interface LinkConfig\n */\n\n/**\n * When set to `true`, the `target=\"blank\"` and `rel=\"noopener noreferrer\"` attributes are automatically added to all external links\n * in the editor. \"External links\" are all links in the editor content starting with `http`, `https`, or `//`.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tlink: {\n *\t\t\t\t\taddTargetToExternalLinks: true\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * Internally, this option activates a predefined {@link module:link/link~LinkConfig#decorators automatic link decorator}\n * that extends all external links with the `target` and `rel` attributes.\n *\n * **Note**: To control the `target` and `rel` attributes of specific links in the edited content, a dedicated\n * {@link module:link/link~LinkDecoratorManualDefinition manual} decorator must be defined in the\n * {@link module:link/link~LinkConfig#decorators `config.link.decorators`} array. In such scenario,\n * the `config.link.addTargetToExternalLinks` option should remain `undefined` or `false` to not interfere with the manual decorator.\n *\n * It is possible to add other {@link module:link/link~LinkDecoratorAutomaticDefinition automatic}\n * or {@link module:link/link~LinkDecoratorManualDefinition manual} link decorators when this option is active.\n *\n * More information about decorators can be found in the {@link module:link/link~LinkConfig#decorators decorators configuration}\n * reference.\n *\n * @default false\n * @member {Boolean} module:link/link~LinkConfig#addTargetToExternalLinks\n */\n\n/**\n * Decorators provide an easy way to configure and manage additional link attributes in the editor content. There are\n * two types of link decorators:\n *\n * * {@link module:link/link~LinkDecoratorAutomaticDefinition Automatic} – They match links against pre–defined rules and\n * manage their attributes based on the results.\n * * {@link module:link/link~LinkDecoratorManualDefinition Manual} – They allow users to control link attributes individually,\n * using the editor UI.\n *\n * Link decorators are defined as objects with key-value pairs, where the key is the name provided for a given decorator and the\n * value is the decorator definition.\n *\n * The name of the decorator also corresponds to the {@glink framework/guides/architecture/editing-engine#text-attributes text attribute}\n * in the model. For instance, the `isExternal` decorator below is represented as a `linkIsExternal` attribute in the model.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tlink: {\n *\t\t\t\t\tdecorators: {\n *\t\t\t\t\t\tisExternal: {\n *\t\t\t\t\t\t\tmode: 'automatic',\n *\t\t\t\t\t\t\tcallback: url => url.startsWith( 'http://' ),\n *\t\t\t\t\t\t\tattributes: {\n *\t\t\t\t\t\t\t\ttarget: '_blank',\n *\t\t\t\t\t\t\t\trel: 'noopener noreferrer'\n *\t\t\t\t\t\t\t}\n *\t\t\t\t\t\t},\n *\t\t\t\t\t\tisDownloadable: {\n *\t\t\t\t\t\t\tmode: 'manual',\n *\t\t\t\t\t\t\tlabel: 'Downloadable',\n *\t\t\t\t\t\t\tattributes: {\n *\t\t\t\t\t\t\t\tdownload: 'file.png',\n *\t\t\t\t\t\t\t}\n *\t\t\t\t\t\t},\n *\t\t\t\t\t\t// ...\n *\t\t\t\t\t}\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * To learn more about the configuration syntax, check out the {@link module:link/link~LinkDecoratorAutomaticDefinition automatic}\n * and {@link module:link/link~LinkDecoratorManualDefinition manual} decorator option reference.\n *\n * **Warning:** Currently, link decorators work independently of one another and no conflict resolution mechanism exists.\n * For example, configuring the `target` attribute using both an automatic and a manual decorator at the same time could end up with\n * quirky results. The same applies if multiple manual or automatic decorators were defined for the same attribute.\n *\n * **Note**: Since the `target` attribute management for external links is a common use case, there is a predefined automatic decorator\n * dedicated for that purpose which can be enabled by turning a single option on. Check out the\n * {@link module:link/link~LinkConfig#addTargetToExternalLinks `config.link.addTargetToExternalLinks`}\n * configuration description to learn more.\n *\n * See also the {@glink features/link#custom-link-attributes-decorators link feature guide} for more information.\n *\n * @member {Object.<String, module:link/link~LinkDecoratorDefinition>} module:link/link~LinkConfig#decorators\n */\n\n/**\n * Represents a link decorator definition ({@link module:link/link~LinkDecoratorManualDefinition `'manual'`}\n * or {@link module:link/link~LinkDecoratorAutomaticDefinition `'automatic'`}).\n *\n * @interface LinkDecoratorDefinition\n */\n\n/**\n * Link decorator type.\n *\n * Check out the {@glink features/link#custom-link-attributes-decorators link feature guide} for more information.\n *\n * @member {'manual'|'automatic'} module:link/link~LinkDecoratorDefinition#mode\n */\n\n/**\n * Describes an automatic {@link module:link/link~LinkConfig#decorators link decorator}. This decorator type matches\n * all links in the editor content against a function that decides whether the link should receive a pre–defined set of attributes.\n *\n * It takes an object with key-value pairs of attributes and a callback function that must return a Boolean value based on the link's\n * `href` (URL). When the callback returns `true`, attributes are applied to the link.\n *\n * For example, to add the `target=\"_blank\"` attribute to all links in the editor starting with `http://`, the\n * configuration could look like this:\n *\n *\t\t{\n *\t\t\tmode: 'automatic',\n *\t\t\tcallback: url => url.startsWith( 'http://' ),\n *\t\t\tattributes: {\n *\t\t\t\ttarget: '_blank'\n *\t\t\t}\n *\t\t}\n *\n * **Note**: Since the `target` attribute management for external links is a common use case, there is a predefined automatic decorator\n * dedicated for that purpose that can be enabled by turning a single option on. Check out the\n * {@link module:link/link~LinkConfig#addTargetToExternalLinks `config.link.addTargetToExternalLinks`}\n * configuration description to learn more.\n *\n * @typedef {Object} module:link/link~LinkDecoratorAutomaticDefinition\n * @property {'automatic'} mode Link decorator type. It is `'automatic'` for all automatic decorators.\n * @property {Function} callback Takes a `url` as a parameter and returns `true` if the `attributes` should be applied to the link.\n * @property {Object} attributes Key-value pairs used as link attributes added to the output during the\n * {@glink framework/guides/architecture/editing-engine#conversion downcasting}.\n * Attributes should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.\n */\n\n/**\n * Describes a manual {@link module:link/link~LinkConfig#decorators link decorator}. This decorator type is represented in\n * the link feature's {@link module:link/linkui user interface} as a switch that the user can use to control the presence\n * of a predefined set of attributes.\n *\n * For instance, to allow the users to manually control the presence of the `target=\"_blank\"` and\n * `rel=\"noopener noreferrer\"` attributes on specific links, the decorator could look as follows:\n *\n *\t\t{\n *\t\t\tmode: 'manual',\n *\t\t\tlabel: 'Open in a new tab',\n *\t\t\tattributes: {\n *\t\t\t\ttarget: '_blank',\n *\t\t\t\trel: 'noopener noreferrer'\n *\t\t\t}\n *\t\t}\n *\n * @typedef {Object} module:link/link~LinkDecoratorManualDefinition\n * @property {'manual'} mode Link decorator type. It is `'manual'` for all manual decorators.\n * @property {String} label The label of the UI button that the user can use to control the presence of link attributes.\n * @property {Object} attributes Key-value pairs used as link attributes added to the output during the\n * {@glink framework/guides/architecture/editing-engine#conversion downcasting}.\n * Attributes should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 list/list\n */\n\nimport ListEditing from './listediting';\nimport ListUI from './listui';\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * The list feature.\n *\n * This is a \"glue\" plugin that loads the {@link module:list/listediting~ListEditing list editing feature}\n * and {@link module:list/listui~ListUI list UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class List extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ListEditing, ListUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'List';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 media-embed/mediaembed\n */\n\nimport MediaEmbedEditing from './mediaembedediting';\nimport AutoMediaEmbed from './automediaembed';\nimport MediaEmbedUI from './mediaembedui';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Widget from '@ckeditor/ckeditor5-widget/src/widget';\n\nimport '../theme/mediaembed.css';\n\n/**\n * The media embed plugin.\n *\n * For a detailed overview, check the {@glink features/media-embed Media Embed feature documentation}.\n *\n * This is a \"glue\" plugin which loads the following plugins:\n *\n * * The {@link module:media-embed/mediaembedediting~MediaEmbedEditing media embed editing feature},\n * * The {@link module:media-embed/mediaembedui~MediaEmbedUI media embed UI feature} and\n * * The {@link module:media-embed/automediaembed~AutoMediaEmbed auto-media embed feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class MediaEmbed extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ MediaEmbedEditing, MediaEmbedUI, AutoMediaEmbed, Widget ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'MediaEmbed';\n\t}\n}\n\n/**\n * The media embed provider descriptor. Used in\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#providers `config.mediaEmbed.providers`} and\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#extraProviders `config.mediaEmbed.extraProviders`}.\n *\n * See {@link module:media-embed/mediaembed~MediaEmbedConfig} to learn more.\n *\n *\t\t{\n *\t\t\tname: 'example',\n *\n *\t\t\t// The following RegExp matches https://www.example.com/media/{media id},\n *\t\t\t// (either with \"http(s)://\" and \"www\" or without), so the valid URLs are:\n *\t\t\t//\n *\t\t\t// * https://www.example.com/media/{media id},\n *\t\t\t// * http://www.example.com/media/{media id},\n *\t\t\t// * www.example.com/media/{media id},\n *\t\t\t// * example.com/media/{media id}\n *\t\t\turl: /^example\\.com\\/media\\/(\\w+)/,\n *\n *\t\t\t// The rendering function of the provider.\n *\t\t\t// Used to represent the media when editing the content (i.e. in the view)\n *\t\t\t// and also in the data output of the editor if semantic data output is disabled.\n *\t\t\thtml: match => `The HTML representing the media with ID=${ match[ 1 ] }.`\n *\t\t}\n *\n * You can allow any sort of media in the editor using the \"allow–all\" `RegExp`.\n * But mind that, since URLs are processed in the order of configuration, if one of the previous\n * `RegExps` matches the URL, it will have a precedence over this one.\n *\n *\t\t{\n *\t\t\tname: 'allow-all',\n *\t\t\turl: /^.+/\n *\t\t}\n *\n * To implement responsive media, you can use the following HTML structure:\n *\n *\t\t{\n *\t\t\t...\n *\t\t\thtml: match =>\n *\t\t\t\t'<div style=\"position:relative; padding-bottom:100%; height:0\">' +\n *\t\t\t\t\t'<iframe src=\"...\" frameborder=\"0\" ' +\n *\t\t\t\t\t\t'style=\"position:absolute; width:100%; height:100%; top:0; left:0\">' +\n *\t\t\t\t\t'</iframe>' +\n *\t\t\t\t'</div>'\n *\t\t}\n *\n * @typedef {Object} module:media-embed/mediaembed~MediaEmbedProvider\n * @property {String} name The name of the provider. Used e.g. when\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#removeProviders removing providers}.\n * @property {RegExp|Array.<RegExp>} url The `RegExp` object (or array of objects) defining the URL of the media.\n * If any URL matches the `RegExp`, it becomes the media in the editor model, as defined by the provider. The result\n * of matching (output of `String.prototype.match()`) is passed to the `html` rendering function of the media.\n *\n * **Note:** You do not need to include the protocol (`http://`, `https://`) and `www` subdomain in your `RegExps`,\n * they are stripped from the URLs before matching anyway.\n * @property {Function} [html] (optional) The rendering function of the media. The function receives the entire matching\n * array from the corresponding `url` `RegExp` as an argument, allowing rendering a dedicated\n * preview of the media identified by a certain ID or a hash. When not defined, the media embed feature\n * will use a generic media representation in the view and output data.\n * Note that when\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#previewsInData `config.mediaEmbed.previewsInData`}\n * is `true`, the rendering function **will always** be used for the media in the editor data output.\n */\n\n/**\n * The configuration of the {@link module:media-embed/mediaembed~MediaEmbed} feature.\n *\n * Read more in {@link module:media-embed/mediaembed~MediaEmbedConfig}.\n *\n * @member {module:media-embed/mediaembed~MediaEmbedConfig} module:core/editor/editorconfig~EditorConfig#mediaEmbed\n */\n\n/**\n * The configuration of the media embed features.\n *\n * Read more about {@glink features/media-embed#configuration configuring the media embed feature}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\tmediaEmbed: ... // Media embed 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 MediaEmbedConfig\n */\n\n/**\n * The default media providers supported by the editor.\n *\n * The names of providers with rendering functions (previews):\n *\n * * \"dailymotion\",\n * * \"spotify\",\n * * \"youtube\",\n * * \"vimeo\"\n *\n * The names of providers without rendering functions:\n *\n * * \"instagram\",\n * * \"twitter\",\n * * \"googleMaps\",\n * * \"flickr\",\n * * \"facebook\"\n *\n * See the {@link module:media-embed/mediaembed~MediaEmbedProvider provider syntax} to learn more about\n * different kinds of media and media providers.\n *\n * **Note**: The default media provider configuration may not support all possible media URLs,\n * only the most common are included.\n *\n * Media without rendering functions are always represented in the data using the \"semantic\" markup. See\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#previewsInData `config.mediaEmbed.previewsInData`} to\n * learn more about possible data outputs.\n *\n * The priority of media providers corresponds to the order of configuration. The first provider\n * to match the URL is always used, even if there are other providers that support a particular URL.\n * The URL is never matched against the remaining providers.\n *\n * To discard **all** default media providers, simply override this configuration with your own\n * {@link module:media-embed/mediaembed~MediaEmbedProvider definitions}:\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tplugins: [ MediaEmbed, ... ],\n *\t\t\t\tmediaEmbed: {\n *\t\t\t\t\tproviders: [\n *\t\t\t\t\t\t{\n *\t\t\t\t\t\t\t name: 'myProvider',\n *\t\t\t\t\t\t\t url: /^example\\.com\\/media\\/(\\w+)/,\n *\t\t\t\t\t\t\t html: match => '...'\n *\t\t\t\t\t\t},\n *\t\t\t\t\t\t...\n * \t\t\t\t\t]\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * You can take inspiration from the default configuration of this feature which you can find in:\n * https://github.com/ckeditor/ckeditor5-media-embed/blob/master/src/mediaembedediting.js\n *\n * To **extend** the list of default providers, use\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#extraProviders `config.mediaEmbed.extraProviders`}.\n *\n * To **remove** certain providers, use\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#removeProviders `config.mediaEmbed.removeProviders`}.\n *\n * @member {Array.<module:media-embed/mediaembed~MediaEmbedProvider>} module:media-embed/mediaembed~MediaEmbedConfig#providers\n */\n\n/**\n * The additional media providers supported by the editor. This configuration helps extend the default\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#providers}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tplugins: [ MediaEmbed, ... ],\n *\t\t\t\tmediaEmbed: {\n *\t\t\t\t\textraProviders: [\n *\t\t\t\t\t\t{\n *\t\t\t\t\t\t\t name: 'extraProvider',\n *\t\t\t\t\t\t\t url: /^example\\.com\\/media\\/(\\w+)/,\n *\t\t\t\t\t\t\t html: match => '...'\n *\t\t\t\t\t\t},\n *\t\t\t\t\t\t...\n * \t\t\t\t\t]\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See the {@link module:media-embed/mediaembed~MediaEmbedProvider provider syntax} to learn more.\n *\n * @member {Array.<module:media-embed/mediaembed~MediaEmbedProvider>} module:media-embed/mediaembed~MediaEmbedConfig#extraProviders\n */\n\n/**\n * The list of media providers that should not be used despite being available in\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#providers `config.mediaEmbed.providers`} and\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#extraProviders `config.mediaEmbed.extraProviders`}\n *\n *\t\tmediaEmbed: {\n *\t\t\tremoveProviders: [ 'youtube', 'twitter' ]\n *\t\t}\n *\n * @member {Array.<String>} module:media-embed/mediaembed~MediaEmbedConfig#removeProviders\n */\n\n/**\n * Controls the data format produced by the feature.\n *\n * When `false` (default), the feature produces \"semantic\" data, i.e. it does not include the preview of\n * the media, just the `<oembed>` tag with the `url` attribute:\n *\n *\t\t<figure class=\"media\">\n *\t\t\t<oembed url=\"https://url\"></oembed>\n *\t\t</figure>\n *\n * When `true`, the media is represented in the output in the same way it looks in the editor,\n * i.e. the media preview is saved to the database:\n *\n *\t\t<figure class=\"media\">\n *\t\t\t<div data-oembed-url=\"https://url\">\n *\t\t\t\t<iframe src=\"https://preview\"></iframe>\n *\t\t\t</div>\n *\t\t</figure>\n *\n * **Note:** Media without preview are always represented in the data using the \"semantic\" markup\n * regardless of the value of the `previewsInData`. Learn more about different kinds of media\n * in the {@link module:media-embed/mediaembed~MediaEmbedConfig#providers `config.mediaEmbed.providers`}\n * configuration description.\n *\n * @member {Boolean} [module:media-embed/mediaembed~MediaEmbedConfig#previewsInData=false]\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 paste-from-office/pastefromoffice\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport GoogleDocsNormalizer from './normalizers/googledocsnormalizer';\nimport MSWordNormalizer from './normalizers/mswordnormalizer';\nimport Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';\n\n/**\n * The Paste from Office plugin.\n *\n * This plugin handles content pasted from Office apps and transforms it (if necessary)\n * to a valid structure which can then be understood by the editor features.\n *\n * Transformation is made by a set of predefined {@link module:paste-from-office/normalizer~Normalizer normalizers}.\n * This plugin includes following normalizers:\n * * {@link module:paste-from-office/normalizers/mswordnormalizer~MSWordNormalizer Microsoft Word normalizer}\n * * {@link module:paste-from-office/normalizers/googledocsnormalizer~GoogleDocsNormalizer Google Docs normalizer}\n *\n * For more information about this feature check the {@glink api/paste-from-office package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class PasteFromOffice extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'PasteFromOffice';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Clipboard ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst normalizers = [];\n\n\t\tnormalizers.push( new MSWordNormalizer() );\n\t\tnormalizers.push( new GoogleDocsNormalizer() );\n\n\t\teditor.plugins.get( 'Clipboard' ).on(\n\t\t\t'inputTransformation',\n\t\t\t( evt, data ) => {\n\t\t\t\tif ( data.isTransformedWithPasteFromOffice ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst htmlString = data.dataTransfer.getData( 'text/html' );\n\t\t\t\tconst activeNormalizer = normalizers.find( normalizer => normalizer.isActive( htmlString ) );\n\n\t\t\t\tif ( activeNormalizer ) {\n\t\t\t\t\tactiveNormalizer.execute( data );\n\n\t\t\t\t\tdata.isTransformedWithPasteFromOffice = true;\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ priority: 'high' }\n\t\t);\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 table/table\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport TableEditing from './tableediting';\nimport TableUI from './tableui';\nimport Widget from '@ckeditor/ckeditor5-widget/src/widget';\n\nimport '../theme/table.css';\n\n/**\n * The table plugin.\n *\n * For a detailed overview, check the {@glink features/table Table feature documentation}.\n *\n * This is a \"glue\" plugin that loads the {@link module:table/tableediting~TableEditing table editing feature}\n * and {@link module:table/tableui~TableUI table UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Table extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableEditing, TableUI, Widget ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Table';\n\t}\n}\n\n/**\n * The configuration of the table feature. Used by the table feature in the `@ckeditor/ckeditor5-table` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\ttable: ... // Table 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 TableConfig\n */\n\n/**\n * The configuration of the {@link module:table/table~Table} feature.\n *\n * Read more in {@link module:table/table~TableConfig}.\n *\n * @member {module:table/table~TableConfig} module:core/editor/editorconfig~EditorConfig#table\n */\n\n/**\n * An array of color definitions (either strings or objects).\n *\n *\t\tconst colors = [\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n *\t\t\t\tlabel: 'Grey'\n *\t\t\t},\n *\t\t\t'hsl(0, 0%, 80%)',\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n *\t\t\t\tlabel: 'Light grey'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n *\t\t\t\tlabel: 'White',\n *\t\t\t\thasBorder: true\n *\t\t\t},\n *\t\t\t'#FF0000'\n *\t\t]\n *\n * Usually used as a configuration parameter, for instance in\n * {@link module:table/table~TableConfig#tableProperties `config.table.tableProperties`}\n * or {@link module:table/table~TableConfig#tableCellProperties `config.table.tableCellProperties`}.\n *\n * @typedef {Array.<String|Object>} module:table/table~TableColorConfig\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n/**\n * @module table/tabletoolbar\n */\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport {\n getSelectedTableWidget,\n getTableWidgetAncestor\n} from './utils';\nimport WidgetToolbarRepository from '@ckeditor/ckeditor5-widget/src/widgettoolbarrepository';\n/**\n * The table toolbar class. It creates toolbars for the table feature and its content (for now only for the table cell content).\n *\n * The table toolbar shows up when a table widget is selected. Its components (e.g. buttons) are created based on the\n * {@link module:table/table~TableConfig#tableToolbar `table.tableToolbar` configuration option}.\n *\n * Table content toolbar shows up when the selection is inside the content of a table. It creates its component based on the\n * {@link module:table/table~TableConfig#contentToolbar `table.contentToolbar` configuration option}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableToolbar extends Plugin {\n /**\n\t * @inheritDoc\n\t */\n static get requires() {\n return [WidgetToolbarRepository];\n }\n /**\n\t * @inheritDoc\n\t */\n static get pluginName() {\n return 'TableToolbar';\n }\n /**\n\t * @inheritDoc\n\t */\n afterInit() {\n const editor = this.editor;\n const t = editor.t;\n const widgetToolbarRepository = editor.plugins.get(WidgetToolbarRepository);\n const tableContentToolbarItems = editor.config.get('table.contentToolbar');\n const tableToolbarItems = editor.config.get('table.tableToolbar');\n if (tableContentToolbarItems) {\n widgetToolbarRepository.register('tableContent', {\n ariaLabel: t('c'),\n items: tableContentToolbarItems,\n getRelatedElement: getTableWidgetAncestor\n });\n }\n if (tableToolbarItems) {\n widgetToolbarRepository.register('table', {\n ariaLabel: t('c'),\n items: tableToolbarItems,\n getRelatedElement: getSelectedTableWidget\n });\n }\n }\n} /**\n * Items to be placed in the table content toolbar.\n * The {@link module:table/tabletoolbar~TableToolbar} plugin is required to make this toolbar work.\n *\n * Assuming that you use the {@link module:table/tableui~TableUI} feature, the following toolbar items will be available\n * in {@link module:ui/componentfactory~ComponentFactory}:\n *\n * * `'tableRow'`,\n * * `'tableColumn'`,\n * * `'mergeTableCells'`.\n *\n * You can thus configure the toolbar like this:\n *\n *\t\tconst tableConfig = {\n *\t\t\tcontentToolbar: [ 'tableRow', 'tableColumn', 'mergeTableCells' ]\n *\t\t};\n *\n * Of course, the same buttons can also be used in the\n * {@link module:core/editor/editorconfig~EditorConfig#toolbar main editor toolbar}.\n *\n * Read more about configuring the toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.<String>} module:table/table~TableConfig#contentToolbar\n */\n /**\n * Items to be placed in the table toolbar.\n * The {@link module:table/tabletoolbar~TableToolbar} plugin is required to make this toolbar work.\n *\n * You can thus configure the toolbar like this:\n *\n *\t\tconst tableConfig = {\n *\t\t\ttableToolbar: [ 'blockQuote' ]\n *\t\t};\n *\n * Of course, the same buttons can also be used in the\n * {@link module:core/editor/editorconfig~EditorConfig#toolbar main editor toolbar}.\n *\n * Read more about configuring the toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.<String>} module:table/table~TableConfig#tableToolbar\n */","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/underline\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport UnderlineEditing from './underline/underlineediting';\nimport UnderlineUI from './underline/underlineui';\n\n/**\n * The underline feature.\n *\n * For a detailed overview check the {@glink features/basic-styles Basic styles feature documentation}\n * and the {@glink api/basic-styles package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:basic-styles/underline/underlineediting~UnderlineEditing} and\n * {@link module:basic-styles/underline/underlineui~UnderlineUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Underline extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ UnderlineEditing, UnderlineUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Underline';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/strikethrough\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport StrikethroughEditing from './strikethrough/strikethroughediting';\nimport StrikethroughUI from './strikethrough/strikethroughui';\n\n/**\n * The strikethrough feature.\n *\n * For a detailed overview check the {@glink features/basic-styles Basic styles feature documentation}\n * and the {@glink api/basic-styles package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:basic-styles/strikethrough/strikethroughediting~StrikethroughEditing} and\n * {@link module:basic-styles/strikethrough/strikethroughui~StrikethroughUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Strikethrough extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ StrikethroughEditing, StrikethroughUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Strikethrough';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/code\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport CodeEditing from './code/codeediting';\nimport CodeUI from './code/codeui';\n\nimport '../theme/code.css';\n\n/**\n * The code feature.\n *\n * For a detailed overview check the {@glink features/basic-styles Basic styles feature documentation}\n * and the {@glink api/basic-styles package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:basic-styles/code/codeediting~CodeEditing code editing feature}\n * and {@link module:basic-styles/code/codeui~CodeUI code UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Code extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ CodeEditing, CodeUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Code';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/subscript\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport SubscriptEditing from './subscript/subscriptediting';\nimport SubscriptUI from './subscript/subscriptui';\n\n/**\n * The subscript feature.\n *\n * It loads the {@link module:basic-styles/subscript/subscriptediting~SubscriptEditing} and\n * {@link module:basic-styles/subscript/subscriptui~SubscriptUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Subscript extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ SubscriptEditing, SubscriptUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Subscript';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 basic-styles/superscript\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport SuperscriptEditing from './superscript/superscriptediting';\nimport SuperscriptUI from './superscript/superscriptui';\n\n/**\n * The superscript feature.\n *\n * It loads the {@link module:basic-styles/superscript/superscriptediting~SuperscriptEditing} and\n * {@link module:basic-styles/superscript/superscriptui~SuperscriptUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Superscript extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ SuperscriptEditing, SuperscriptUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Superscript';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 remove-format/removeformat\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport RemoveFormatUI from './removeformatui';\nimport RemoveFormatEditing from './removeformatediting';\n\n/**\n * The remove format plugin.\n *\n * This is a \"glue\" plugin which loads the {@link module:remove-format/removeformatediting~RemoveFormatEditing}\n * and {@link module:remove-format/removeformatui~RemoveFormatUI} plugins.\n *\n * For a detailed overview, check out the {@glink features/remove-format remove format} feature documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class RemoveFormat extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ RemoveFormatEditing, RemoveFormatUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'RemoveFormat';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 horizontal-line/horizontalline\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport HorizontalLineEditing from './horizontallineediting';\nimport HorizontalLineUI from './horizontallineui';\n\n/**\n * The horizontal line feature.\n *\n * It provides the possibility to insert a horizontal line into the rich-text editor.\n *\n * For a detailed overview, check the {@glink features/horizontal-line Horizontal line feature} documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HorizontalLine extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ HorizontalLineEditing, HorizontalLineUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'HorizontalLine';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, 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 alignment/alignment\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport AlignmentEditing from './alignmentediting';\nimport AlignmentUI from './alignmentui';\n\n/**\n * The text alignment plugin.\n *\n * For a detailed overview, check the {@glink features/text-alignment Text alignment feature documentation}\n * and the {@glink api/alignment package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:alignment/alignmentediting~AlignmentEditing} and\n * {@link module:alignment/alignmentui~AlignmentUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Alignment extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ AlignmentEditing, AlignmentUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Alignment';\n\t}\n}\n\n/**\n * The configuration of the {@link module:alignment/alignment~Alignment alignment feature}.\n *\n * Read more in {@link module:alignment/alignment~AlignmentConfig}.\n *\n * @member {module:alignment/alignment~AlignmentConfig} module:core/editor/editorconfig~EditorConfig#alignment\n */\n\n/**\n * The configuration of the {@link module:alignment/alignment~Alignment alignment feature}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\talignment: {\n *\t\t\t\t\toptions: [ 'left', 'right' ]\n *\t\t\t\t}\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 configuration options}.\n *\n * @interface AlignmentConfig\n */\n\n/**\n * Available alignment options.\n *\n * The available options are: `'left'`, `'right'`, `'center'` and `'justify'`. Other values are ignored.\n *\n * **Note:** It is recommended to always use `'left'` or `'right'` as these are default values which the user should\n * normally be able to choose depending on the\n * {@glink features/ui-language#setting-the-language-of-the-content language of the editor content}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\talignment: {\n *\t\t\t\t\toptions: [ 'left', 'right' ]\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See the demo of {@glink features/text-alignment#configuring-alignment-options custom alignment options}.\n *\n * @member {Array.<String>} module:alignment/alignment~AlignmentConfig#options\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 image/imageresize\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport WidgetResize from '@ckeditor/ckeditor5-widget/src/widgetresize';\nimport ImageResizeCommand from './imageresize/imageresizecommand';\n\nimport '../theme/imageresize.css';\n\n/**\n * The image resize plugin.\n *\n * It adds a possibility to resize each image using handles.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageResize extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ WidgetResize ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageResize';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst command = new ImageResizeCommand( editor );\n\n\t\tthis._registerSchema();\n\t\tthis._registerConverters();\n\n\t\teditor.commands.add( 'imageResize', command );\n\n\t\teditor.editing.downcastDispatcher.on( 'insert:image', ( evt, data, conversionApi ) => {\n\t\t\tconst widget = conversionApi.mapper.toViewElement( data.item );\n\n\t\t\tconst resizer = editor.plugins\n\t\t\t\t.get( WidgetResize )\n\t\t\t\t.attachTo( {\n\t\t\t\t\tunit: editor.config.get( 'image.resizeUnit' ) || '%',\n\n\t\t\t\t\tmodelElement: data.item,\n\t\t\t\t\tviewElement: widget,\n\t\t\t\t\teditor,\n\n\t\t\t\t\tgetHandleHost( domWidgetElement ) {\n\t\t\t\t\t\treturn domWidgetElement.querySelector( 'img' );\n\t\t\t\t\t},\n\t\t\t\t\tgetResizeHost( domWidgetElement ) {\n\t\t\t\t\t\treturn domWidgetElement;\n\t\t\t\t\t},\n\t\t\t\t\t// TODO consider other positions.\n\t\t\t\t\tisCentered() {\n\t\t\t\t\t\tconst imageStyle = data.item.getAttribute( 'imageStyle' );\n\n\t\t\t\t\t\treturn !imageStyle || imageStyle == 'full' || imageStyle == 'alignCenter';\n\t\t\t\t\t},\n\n\t\t\t\t\tonCommit( newValue ) {\n\t\t\t\t\t\teditor.execute( 'imageResize', { width: newValue } );\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\tresizer.on( 'updateSize', () => {\n\t\t\t\tif ( !widget.hasClass( 'image_resized' ) ) {\n\t\t\t\t\teditor.editing.view.change( writer => {\n\t\t\t\t\t\twriter.addClass( 'image_resized', widget );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tresizer.bind( 'isEnabled' ).to( command );\n\t\t}, { priority: 'low' } );\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_registerSchema() {\n\t\tthis.editor.model.schema.extend( 'image', {\n\t\t\tallowAttributes: 'width'\n\t\t} );\n\t}\n\n\t/**\n\t * Registers image resize converters.\n\t *\n\t * @private\n\t */\n\t_registerConverters() {\n\t\tconst editor = this.editor;\n\n\t\t// Dedicated converter to propagate image's attribute to the img tag.\n\t\teditor.conversion.for( 'downcast' ).add( dispatcher =>\n\t\t\tdispatcher.on( 'attribute:width:image', ( evt, data, conversionApi ) => {\n\t\t\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst viewWriter = conversionApi.writer;\n\t\t\t\tconst figure = conversionApi.mapper.toViewElement( data.item );\n\n\t\t\t\tif ( data.attributeNewValue !== null ) {\n\t\t\t\t\tviewWriter.setStyle( 'width', data.attributeNewValue, figure );\n\t\t\t\t\tviewWriter.addClass( 'image_resized', figure );\n\t\t\t\t} else {\n\t\t\t\t\tviewWriter.removeStyle( 'width', figure );\n\t\t\t\t\tviewWriter.removeClass( 'image_resized', figure );\n\t\t\t\t}\n\t\t\t} )\n\t\t);\n\n\t\teditor.conversion.for( 'upcast' )\n\t\t\t.attributeToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'figure',\n\t\t\t\t\tstyles: {\n\t\t\t\t\t\twidth: /.+/\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tmodel: {\n\t\t\t\t\tkey: 'width',\n\t\t\t\t\tvalue: viewElement => viewElement.getStyle( 'width' )\n\t\t\t\t}\n\t\t\t} );\n\t}\n}\n\n/**\n * The available options are `'px'` or `'%'`.\n *\n * Determines the size unit applied to the resized image.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\timage: {\n *\t\t\t\t\tresizeUnit: 'px'\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n *\n * This option is used by the {@link module:image/imageresize~ImageResize} feature.\n *\n * @default '%'\n * @member {String} module:image/image~ImageConfig#resizeUnit\n */\n","/**\n * @license Copyright (c) 2003-2020, 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 font/font\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport FontFamily from './fontfamily';\nimport FontSize from './fontsize';\nimport FontColor from './fontcolor';\nimport FontBackgroundColor from './fontbackgroundcolor';\n\n/**\n * A plugin that enables a set of text styling features:\n *\n * * {@link module:font/fontsize~FontSize},\n * * {@link module:font/fontfamily~FontFamily}.\n * * {@link module:font/fontcolor~FontColor},\n * * {@link module:font/fontbackgroundcolor~FontBackgroundColor}.\n *\n * For a detailed overview, check the {@glink features/font Font feature} documentation\n * and the {@glink api/font package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Font extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FontFamily, FontSize, FontColor, FontBackgroundColor ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Font';\n\t}\n}\n"],"sourceRoot":""}
\ No newline at end of file |