diff --git a/bl-kernel/abstract/dblist.class.php b/bl-kernel/abstract/dblist.class.php index 1fabc6b6..3d7c8e4d 100644 --- a/bl-kernel/abstract/dblist.class.php +++ b/bl-kernel/abstract/dblist.class.php @@ -47,7 +47,6 @@ class dbList extends dbJSON // Returns all the items from the list if ($numberOfItems==-1) { // Invert keys to values, is necesary returns as key the key pages - $list = array_flip($list); return $list; } diff --git a/bl-kernel/functions.php b/bl-kernel/functions.php index 0360f2d4..89952054 100644 --- a/bl-kernel/functions.php +++ b/bl-kernel/functions.php @@ -123,6 +123,7 @@ function buildPagesFor($for, $categoryKey=false, $tagKey=false) { // continue } } + return $content; } diff --git a/bl-plugins/quill/css/medium-editor.min.css b/bl-plugins/quill/css/medium-editor.min.css new file mode 100755 index 00000000..e46f81c0 --- /dev/null +++ b/bl-plugins/quill/css/medium-editor.min.css @@ -0,0 +1 @@ +.medium-editor-anchor-preview,.medium-editor-toolbar{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:16px;z-index:2000}@-webkit-keyframes medium-editor-image-loading{0%{-webkit-transform:scale(0);transform:scale(0)}100%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes medium-editor-image-loading{0%{-webkit-transform:scale(0);transform:scale(0)}100%{-webkit-transform:scale(1);transform:scale(1)}}@-webkit-keyframes medium-editor-pop-upwards{0%{opacity:0;-webkit-transform:matrix(.97,0,0,1,0,12);transform:matrix(.97,0,0,1,0,12)}20%{opacity:.7;-webkit-transform:matrix(.99,0,0,1,0,2);transform:matrix(.99,0,0,1,0,2)}40%{opacity:1;-webkit-transform:matrix(1,0,0,1,0,-1);transform:matrix(1,0,0,1,0,-1)}100%{-webkit-transform:matrix(1,0,0,1,0,0);transform:matrix(1,0,0,1,0,0)}}@keyframes medium-editor-pop-upwards{0%{opacity:0;-webkit-transform:matrix(.97,0,0,1,0,12);transform:matrix(.97,0,0,1,0,12)}20%{opacity:.7;-webkit-transform:matrix(.99,0,0,1,0,2);transform:matrix(.99,0,0,1,0,2)}40%{opacity:1;-webkit-transform:matrix(1,0,0,1,0,-1);transform:matrix(1,0,0,1,0,-1)}100%{-webkit-transform:matrix(1,0,0,1,0,0);transform:matrix(1,0,0,1,0,0)}}.medium-editor-anchor-preview{left:0;line-height:1.4;max-width:280px;position:absolute;text-align:center;top:0;word-break:break-all;word-wrap:break-word;visibility:hidden}.medium-editor-anchor-preview a{color:#fff;display:inline-block;margin:5px 5px 10px}.medium-editor-placeholder-relative:after,.medium-editor-placeholder:after{content:attr(data-placeholder)!important;white-space:pre;padding:inherit;margin:inherit;font-style:italic}.medium-editor-anchor-preview-active{visibility:visible}.medium-editor-dragover{background:#ddd}.medium-editor-image-loading{-webkit-animation:medium-editor-image-loading 1s infinite ease-in-out;animation:medium-editor-image-loading 1s infinite ease-in-out;background-color:#333;border-radius:100%;display:inline-block;height:40px;width:40px}.medium-editor-placeholder{position:relative}.medium-editor-placeholder:after{position:absolute;left:0;top:0}.medium-editor-placeholder-relative,.medium-editor-placeholder-relative:after{position:relative}.medium-toolbar-arrow-over:before,.medium-toolbar-arrow-under:after{border-style:solid;content:'';display:block;height:0;left:50%;margin-left:-8px;position:absolute;width:0}.medium-toolbar-arrow-under:after{border-width:8px 8px 0}.medium-toolbar-arrow-over:before{border-width:0 8px 8px;top:-8px}.medium-editor-toolbar{left:0;position:absolute;top:0;visibility:hidden}.medium-editor-toolbar ul{margin:0;padding:0}.medium-editor-toolbar li{float:left;list-style:none;margin:0;padding:0}.medium-editor-toolbar li button{box-sizing:border-box;cursor:pointer;display:block;font-size:14px;line-height:1.33;margin:0;padding:15px;text-decoration:none}.medium-editor-toolbar li button:focus{outline:0}.medium-editor-toolbar li .medium-editor-action-underline{text-decoration:underline}.medium-editor-toolbar li .medium-editor-action-pre{font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:12px;font-weight:100;padding:15px 0}.medium-editor-toolbar-active{visibility:visible}.medium-editor-sticky-toolbar{position:fixed;top:1px}.medium-editor-relative-toolbar{position:relative}.medium-editor-toolbar-active.medium-editor-stalker-toolbar{-webkit-animation:medium-editor-pop-upwards 160ms forwards linear;animation:medium-editor-pop-upwards 160ms forwards linear}.medium-editor-action-bold{font-weight:bolder}.medium-editor-action-italic{font-style:italic}.medium-editor-toolbar-form{display:none}.medium-editor-toolbar-form a,.medium-editor-toolbar-form input{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.medium-editor-toolbar-form .medium-editor-toolbar-form-row{line-height:14px;margin-left:5px;padding-bottom:5px}.medium-editor-toolbar-form .medium-editor-toolbar-input,.medium-editor-toolbar-form label{border:none;box-sizing:border-box;font-size:14px;margin:0;padding:6px;width:316px;display:inline-block}.medium-editor-toolbar-form .medium-editor-toolbar-input:focus,.medium-editor-toolbar-form label:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;box-shadow:none;outline:0}.medium-editor-toolbar-form a{display:inline-block;font-size:24px;font-weight:bolder;margin:0 10px;text-decoration:none}.medium-editor-toolbar-form-active{display:block}.medium-editor-toolbar-actions:after{clear:both;content:"";display:table}.medium-editor-element{word-wrap:break-word;min-height:30px}.medium-editor-element img{max-width:100%}.medium-editor-element sub{vertical-align:sub}.medium-editor-element sup{vertical-align:super}.medium-editor-hidden{display:none} \ No newline at end of file diff --git a/bl-plugins/quill/css/themes/default.css b/bl-plugins/quill/css/themes/default.css new file mode 100755 index 00000000..02668c6b --- /dev/null +++ b/bl-plugins/quill/css/themes/default.css @@ -0,0 +1,63 @@ +.medium-toolbar-arrow-under:after { + border-color: #242424 transparent transparent transparent; + top: 50px; } + +.medium-toolbar-arrow-over:before { + border-color: transparent transparent #242424 transparent; + top: -8px; } + +.medium-editor-toolbar { + background-color: #242424; + background: -webkit-linear-gradient(top, #242424, rgba(36, 36, 36, 0.75)); + background: linear-gradient(to bottom, #242424, rgba(36, 36, 36, 0.75)); + border: 1px solid #000; + border-radius: 5px; + box-shadow: 0 0 3px #000; } + .medium-editor-toolbar li button { + background-color: #242424; + background: -webkit-linear-gradient(top, #242424, rgba(36, 36, 36, 0.89)); + background: linear-gradient(to bottom, #242424, rgba(36, 36, 36, 0.89)); + border: 0; + border-right: 1px solid #000; + border-left: 1px solid #333; + border-left: 1px solid rgba(255, 255, 255, 0.1); + box-shadow: 0 2px 2px rgba(0, 0, 0, 0.3); + color: #fff; + height: 50px; + min-width: 50px; + -webkit-transition: background-color .2s ease-in; + transition: background-color .2s ease-in; } + .medium-editor-toolbar li button:hover { + background-color: #000; + color: yellow; } + .medium-editor-toolbar li .medium-editor-button-first { + border-bottom-left-radius: 5px; + border-top-left-radius: 5px; } + .medium-editor-toolbar li .medium-editor-button-last { + border-bottom-right-radius: 5px; + border-top-right-radius: 5px; } + .medium-editor-toolbar li .medium-editor-button-active { + background-color: #000; + background: -webkit-linear-gradient(top, #242424, rgba(0, 0, 0, 0.89)); + background: linear-gradient(to bottom, #242424, rgba(0, 0, 0, 0.89)); + color: #fff; } + +.medium-editor-toolbar-form { + background: #242424; + border-radius: 5px; + color: #999; } + .medium-editor-toolbar-form .medium-editor-toolbar-input { + background: #242424; + box-sizing: border-box; + color: #ccc; + height: 50px; } + .medium-editor-toolbar-form a { + color: #fff; } + +.medium-editor-toolbar-anchor-preview { + background: #242424; + border-radius: 5px; + color: #fff; } + +.medium-editor-placeholder:after { + color: #b3b3b1; } diff --git a/bl-plugins/quill/css/themes/default.min.css b/bl-plugins/quill/css/themes/default.min.css new file mode 100755 index 00000000..ac584784 --- /dev/null +++ b/bl-plugins/quill/css/themes/default.min.css @@ -0,0 +1 @@ +.medium-toolbar-arrow-under:after{border-color:#242424 transparent transparent;top:50px}.medium-toolbar-arrow-over:before{border-color:transparent transparent #242424;top:-8px}.medium-editor-toolbar{background-color:#242424;background:-webkit-linear-gradient(top,#242424,rgba(36,36,36,.75));background:linear-gradient(to bottom,#242424,rgba(36,36,36,.75));border:1px solid #000;border-radius:5px;box-shadow:0 0 3px #000}.medium-editor-toolbar li button{background-color:#242424;background:-webkit-linear-gradient(top,#242424,rgba(36,36,36,.89));background:linear-gradient(to bottom,#242424,rgba(36,36,36,.89));border:0;border-right:1px solid #000;border-left:1px solid #333;border-left:1px solid rgba(255,255,255,.1);box-shadow:0 2px 2px rgba(0,0,0,.3);color:#fff;height:50px;min-width:50px;-webkit-transition:background-color .2s ease-in;transition:background-color .2s ease-in}.medium-editor-toolbar li button:hover{background-color:#000;color:#ff0}.medium-editor-toolbar li .medium-editor-button-first{border-bottom-left-radius:5px;border-top-left-radius:5px}.medium-editor-toolbar li .medium-editor-button-last{border-bottom-right-radius:5px;border-top-right-radius:5px}.medium-editor-toolbar li .medium-editor-button-active{background-color:#000;background:-webkit-linear-gradient(top,#242424,rgba(0,0,0,.89));background:linear-gradient(to bottom,#242424,rgba(0,0,0,.89));color:#fff}.medium-editor-toolbar-form{background:#242424;border-radius:5px;color:#999}.medium-editor-toolbar-form .medium-editor-toolbar-input{background:#242424;box-sizing:border-box;color:#ccc;height:50px}.medium-editor-toolbar-form a{color:#fff}.medium-editor-toolbar-anchor-preview{background:#242424;border-radius:5px;color:#fff}.medium-editor-placeholder:after{color:#b3b3b1} \ No newline at end of file diff --git a/bl-plugins/quill/js/medium-editor.min.js b/bl-plugins/quill/js/medium-editor.min.js new file mode 100755 index 00000000..38678160 --- /dev/null +++ b/bl-plugins/quill/js/medium-editor.min.js @@ -0,0 +1,4 @@ +"classList"in document.createElement("_")||!function(a){"use strict";if("Element"in a){var b="classList",c="prototype",d=a.Element[c],e=Object,f=String[c].trim||function(){return this.replace(/^\s+|\s+$/g,"")},g=Array[c].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1},h=function(a,b){this.name=a,this.code=DOMException[a],this.message=b},i=function(a,b){if(""===b)throw new h("SYNTAX_ERR","An invalid or illegal string was specified");if(/\s/.test(b))throw new h("INVALID_CHARACTER_ERR","String contains an invalid character");return g.call(a,b)},j=function(a){for(var b=f.call(a.getAttribute("class")||""),c=b?b.split(/\s+/):[],d=0,e=c.length;e>d;d++)this.push(c[d]);this._updateClassName=function(){a.setAttribute("class",this.toString())}},k=j[c]=[],l=function(){return new j(this)};if(h[c]=Error[c],k.item=function(a){return this[a]||null},k.contains=function(a){return a+="",-1!==i(this,a)},k.add=function(){var a,b=arguments,c=0,d=b.length,e=!1;do a=b[c]+"",-1===i(this,a)&&(this.push(a),e=!0);while(++ci;i++)e+=String.fromCharCode(f[i]);c.push(e)}else if("Blob"===b(a)||"File"===b(a)){if(!g)throw new h("NOT_READABLE_ERR");var k=new g;c.push(k.readAsBinaryString(a))}else a instanceof d?"base64"===a.encoding&&p?c.push(p(a.data)):"URI"===a.encoding?c.push(decodeURIComponent(a.data)):"raw"===a.encoding&&c.push(a.data):("string"!=typeof a&&(a+=""),c.push(unescape(encodeURIComponent(a))))},e.getBlob=function(a){return arguments.length||(a=null),new d(this.data.join(""),a,"raw")},e.toString=function(){return"[object BlobBuilder]"},f.slice=function(a,b,c){var e=arguments.length;return 3>e&&(c=null),new d(this.data.slice(a,e>1?b:this.data.length),c,this.encoding)},f.toString=function(){return"[object Blob]"},f.close=function(){this.size=0,delete this.data},c}(a);a.Blob=function(a,b){var d=b?b.type||"":"",e=new c;if(a)for(var f=0,g=a.length;g>f;f++)Uint8Array&&a[f]instanceof Uint8Array?e.append(a[f].buffer):e.append(a[f]);var h=e.getBlob(d);return!h.slice&&h.webkitSlice&&(h.slice=h.webkitSlice),h};var d=Object.getPrototypeOf||function(a){return a.__proto__};a.Blob.prototype=d(new a.Blob)}("undefined"!=typeof self&&self||"undefined"!=typeof window&&window||this.content||this),function(a,b){"use strict";var c="object"==typeof module&&"undefined"!=typeof process&&process&&process.versions&&process.versions.electron;c||"object"!=typeof module?"function"==typeof define&&define.amd?define(function(){return b}):a.MediumEditor=b:module.exports=b}(this,function(){"use strict";function a(a,b){return this.init(a,b)}return a.extensions={},function(b){function c(a,b){var c,d=Array.prototype.slice.call(arguments,2);b=b||{};for(var e=0;e-1,isMac:b.navigator.platform.toUpperCase().indexOf("MAC")>=0,keyCode:{BACKSPACE:8,TAB:9,ENTER:13,ESCAPE:27,SPACE:32,DELETE:46,K:75,M:77,V:86},isMetaCtrlKey:function(a){return!!(h.isMac&&a.metaKey||!h.isMac&&a.ctrlKey)},isKey:function(a,b){var c=h.getKeyCode(a);return!1===Array.isArray(b)?c===b:-1!==b.indexOf(c)},getKeyCode:function(a){var b=a.which;return null===b&&(b=null!==a.charCode?a.charCode:a.keyCode),b},blockContainerElementNames:["p","h1","h2","h3","h4","h5","h6","blockquote","pre","ul","li","ol","address","article","aside","audio","canvas","dd","dl","dt","fieldset","figcaption","figure","footer","form","header","hgroup","main","nav","noscript","output","section","video","table","thead","tbody","tfoot","tr","th","td"],emptyElementNames:["br","col","colgroup","hr","img","input","source","wbr"],extend:function(){var a=[!0].concat(Array.prototype.slice.call(arguments));return c.apply(this,a)},defaults:function(){var a=[!1].concat(Array.prototype.slice.call(arguments));return c.apply(this,a)},createLink:function(a,b,c,d){var e=a.createElement("a");return h.moveTextRangeIntoElement(b[0],b[b.length-1],e),e.setAttribute("href",c),d&&("_blank"===d&&e.setAttribute("rel","noopener noreferrer"),e.setAttribute("target",d)),e},findOrCreateMatchingTextNodes:function(a,b,c){for(var d=a.createTreeWalker(b,NodeFilter.SHOW_ALL,null,!1),e=[],f=0,g=!1,i=null,j=null;null!==(i=d.nextNode());)if(!(i.nodeType>3))if(3===i.nodeType){if(!g&&c.startc.end+1)throw new Error("PerformLinking overshot the target!");g&&e.push(j||i),f+=i.nodeValue.length,null!==j&&(f+=j.nodeValue.length,d.nextNode()),j=null}else"img"===i.tagName.toLowerCase()&&(!g&&c.start<=f&&(g=!0),g&&e.push(i));return e},splitStartNodeIfNeeded:function(a,b,c){return b!==c?a.splitText(b-c):null},splitEndNodeIfNeeded:function(a,b,c,d){var e,f;e=d+a.nodeValue.length+(b?b.nodeValue.length:0)-1,f=c-d-(b?a.nodeValue.length:0),e>=c&&d!==e&&0!==f&&(b||a).splitText(f)},splitByBlockElements:function(b){if(3!==b.nodeType&&1!==b.nodeType)return[];var c=[],d=a.util.blockContainerElementNames.join(",");if(3===b.nodeType||0===b.querySelectorAll(d).length)return[b];for(var e=0;e0)break;d=f.nextNode()}return d},findPreviousSibling:function(a){if(!a||h.isMediumEditorElement(a))return!1;for(var b=a.previousSibling;!b&&!h.isMediumEditorElement(a.parentNode);)a=a.parentNode,b=a.previousSibling;return b},isDescendant:function(a,b,c){if(!a||!b)return!1;if(a===b)return!!c;if(1!==a.nodeType)return!1;if(d||3!==b.nodeType)return a.contains(b);for(var e=b.parentNode;null!==e;){if(e===a)return!0;e=e.parentNode}return!1},isElement:function(a){return!(!a||1!==a.nodeType)},throttle:function(a,b){var c,d,e,f=50,g=null,h=0,i=function(){h=Date.now(),g=null,e=a.apply(c,d),g||(c=d=null)};return b||0===b||(b=f),function(){var f=Date.now(),j=b-(f-h);return c=this,d=arguments,0>=j||j>b?(g&&(clearTimeout(g),g=null),h=f,e=a.apply(c,d),g||(c=d=null)):g||(g=setTimeout(i,j)),e}},traverseUp:function(a,b){if(!a)return!1;do{if(1===a.nodeType){if(b(a))return a;if(h.isMediumEditorElement(a))return!1}a=a.parentNode}while(a);return!1},htmlEntities:function(a){return String(a).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")},insertHTMLCommand:function(b,c){var d,e,f,g,i,j,k,l=!1,m=["insertHTML",!1,c];if(!a.util.isEdge&&b.queryCommandSupported("insertHTML"))try{return b.execCommand.apply(b,m)}catch(n){}if(d=b.getSelection(),d.rangeCount){if(e=d.getRangeAt(0),k=e.commonAncestorContainer,h.isMediumEditorElement(k)&&!k.firstChild)e.selectNode(k.appendChild(b.createTextNode("")));else if(3===k.nodeType&&0===e.startOffset&&e.endOffset===k.nodeValue.length||3!==k.nodeType&&k.innerHTML===e.toString()){for(;!h.isMediumEditorElement(k)&&k.parentNode&&1===k.parentNode.childNodes.length&&!h.isMediumEditorElement(k.parentNode);)k=k.parentNode;e.selectNode(k)}for(e.deleteContents(),f=b.createElement("div"),f.innerHTML=c,g=b.createDocumentFragment();f.firstChild;)i=f.firstChild,j=g.appendChild(i);e.insertNode(g),j&&(e=e.cloneRange(),e.setStartAfter(j),e.collapse(!0),a.selection.selectRange(b,e)),l=!0}return b.execCommand.callListeners&&b.execCommand.callListeners(m,l),l},execFormatBlock:function(b,c){var d,e=h.getTopBlockContainer(a.selection.getSelectionStart(b));if("blockquote"===c){if(e&&(d=Array.prototype.slice.call(e.childNodes),d.some(function(a){return h.isBlockContainer(a)})))return b.execCommand("outdent",!1,null);if(h.isIE)return b.execCommand("indent",!1,c)}if(e&&c===e.nodeName.toLowerCase()&&(c="p"),h.isIE&&(c="<"+c+">"),e&&"blockquote"===e.nodeName.toLowerCase()){if(h.isIE&&"

"===c)return b.execCommand("outdent",!1,c);if((h.isFF||h.isEdge)&&"p"===c)return d=Array.prototype.slice.call(e.childNodes),d.some(function(a){return!h.isBlockContainer(a)})&&b.execCommand("formatBlock",!1,c),b.execCommand("outdent",!1,c)}return b.execCommand("formatBlock",!1,c)},setTargetBlank:function(a,b){var c,d=b||!1;if("a"===a.nodeName.toLowerCase())a.target="_blank",a.rel="noopener noreferrer";else for(a=a.getElementsByTagName("a"),c=0;cd?(e=e.parentNode,c-=1):(f=f.parentNode,d-=1);for(;e!==f;)e=e.parentNode,f=f.parentNode;return e},isElementAtBeginningOfBlock:function(a){for(var b,c;!h.isBlockContainer(a)&&!h.isMediumEditorElement(a);){for(c=a;c=c.previousSibling;)if(b=3===c.nodeType?c.nodeValue:c.textContent,b.length>0)return!1;a=a.parentNode}return!0},isMediumEditorElement:function(a){return a&&a.getAttribute&&!!a.getAttribute("data-medium-editor-element")},getContainerEditorElement:function(a){return h.traverseUp(a,function(a){return h.isMediumEditorElement(a)})},isBlockContainer:function(a){return a&&3!==a.nodeType&&-1!==h.blockContainerElementNames.indexOf(a.nodeName.toLowerCase())},getClosestBlockContainer:function(a){return h.traverseUp(a,function(a){return h.isBlockContainer(a)||h.isMediumEditorElement(a)})},getTopBlockContainer:function(a){var b=h.isBlockContainer(a)?a:!1;return h.traverseUp(a,function(a){return h.isBlockContainer(a)&&(b=a),!b&&h.isMediumEditorElement(a)?(b=a,!0):!1}),b},getFirstSelectableLeafNode:function(a){for(;a&&a.firstChild;)a=a.firstChild;if(a=h.traverseUp(a,function(a){return-1===h.emptyElementNames.indexOf(a.nodeName.toLowerCase())}),"table"===a.nodeName.toLowerCase()){var b=a.querySelector("th, td");b&&(a=b)}return a},getFirstTextNode:function(a){return h.warn("getFirstTextNode is deprecated and will be removed in version 6.0.0"),h._getFirstTextNode(a)},_getFirstTextNode:function(a){if(3===a.nodeType)return a;for(var b=0;b0){var e,f=d.getRangeAt(0),g=f.cloneRange();g.selectNodeContents(a),g.setEnd(f.startContainer,f.startOffset),e=g.toString().length,c={start:e,end:e+f.toString().length},this.doesRangeStartWithImages(f,b)&&(c.startsWithImage=!0);var h=this.getTrailingImageCount(a,c,f.endContainer,f.endOffset);if(h&&(c.trailingImageCount=h),0!==e){var i=this.getIndexRelativeToAdjacentEmptyBlocks(b,a,f.startContainer,f.startOffset);-1!==i&&(c.emptyBlocksIndex=i)}}return c},importSelection:function(a,b,c,d){if(a&&b){var e=c.createRange();e.setStart(b,0),e.collapse(!0);var f,g=b,h=[],i=0,j=!1,k=!1,l=0,m=!1,n=!1,o=null;for((d||a.startsWithImage||"undefined"!=typeof a.emptyBlocksIndex)&&(n=!0);!m&&g;)if(g.nodeType>3)g=h.pop();else{if(3!==g.nodeType||k){if(a.trailingImageCount&&k&&("img"===g.nodeName.toLowerCase()&&l++,l===a.trailingImageCount)){for(var p=0;g.parentNode.childNodes[p]!==g;)p++;e.setEnd(g.parentNode,p+1),m=!0}if(!m&&1===g.nodeType)for(var q=g.childNodes.length-1;q>=0;)h.push(g.childNodes[q]),q-=1}else f=i+g.length,!j&&a.start>=i&&a.start<=f&&(n||a.start=i&&a.end<=f&&(a.trailingImageCount?k=!0:(e.setEnd(g,a.end-i),m=!0)),i=f;m||(g=h.pop())}!j&&o&&(e.setStart(o,o.length),e.setEnd(o,o.length)),"undefined"!=typeof a.emptyBlocksIndex&&(e=this.importSelectionMoveCursorPastBlocks(c,b,a.emptyBlocksIndex,e)),d&&(e=this.importSelectionMoveCursorPastAnchor(a,e)),this.selectRange(c,e)}},importSelectionMoveCursorPastAnchor:function(b,c){var d=function(a){return"a"===a.nodeName.toLowerCase()};if(b.start===b.end&&3===c.startContainer.nodeType&&c.startOffset===c.startContainer.nodeValue.length&&a.util.traverseUp(c.startContainer,d)){for(var e=c.startContainer,f=c.startContainer.parentNode;null!==f&&"a"!==f.nodeName.toLowerCase();)f.childNodes[f.childNodes.length-1]!==e?f=null:(e=f,f=f.parentNode);if(null!==f&&"a"===f.nodeName.toLowerCase()){for(var g=null,h=0;null===g&&h0)break}else g===i.currentNode&&(h=i.currentNode);return h||(h=g),f.setStart(a.util.getFirstSelectableLeafNode(h),0),f},getIndexRelativeToAdjacentEmptyBlocks:function(c,d,e,f){if(e.textContent.length>0&&f>0)return-1;var g=e;if(3!==g.nodeType&&(g=e.childNodes[f]),g){if(!a.util.isElementAtBeginningOfBlock(g))return-1;var h=a.util.findPreviousSibling(g);if(!h)return-1;if(h.nodeValue)return-1}for(var i=a.util.getClosestBlockContainer(e),j=c.createTreeWalker(d,NodeFilter.SHOW_ELEMENT,b,!1),k=0;j.nextNode();){var l=""===j.currentNode.textContent;if((l||k>0)&&(k+=1),j.currentNode===i)return k;l||(k=0)}return k},doesRangeStartWithImages:function(a,b){if(0!==a.startOffset||1!==a.startContainer.nodeType)return!1;if("img"===a.startContainer.nodeName.toLowerCase())return!0;var c=a.startContainer.querySelector("img");if(!c)return!1;for(var d=b.createTreeWalker(a.startContainer,NodeFilter.SHOW_ALL,null,!1);d.nextNode();){var e=d.currentNode;if(e===c)break;if(e.nodeValue)return!1}return!0},getTrailingImageCount:function(a,b,c,d){if(0===d||1!==c.nodeType)return 0;if("img"!==c.nodeName.toLowerCase()&&!c.querySelector("img"))return 0;for(var e=c.childNodes[d-1];e.hasChildNodes();)e=e.lastChild;for(var f,g=a,h=[],i=0,j=!1,k=!1,l=!1,m=0;!l&&g;)if(g.nodeType>3)g=h.pop();else{if(3!==g.nodeType||k){if("img"===g.nodeName.toLowerCase()&&m++,g===e)l=!0;else if(1===g.nodeType)for(var n=g.childNodes.length-1;n>=0;)h.push(g.childNodes[n]),n-=1}else m=0,f=i+g.length,!j&&b.start>=i&&b.start<=f&&(j=!0),j&&b.end>=i&&b.end<=f&&(k=!0),i=f;l||(g=h.pop())}return m},selectionContainsContent:function(a){var b=a.getSelection();if(!b||b.isCollapsed||!b.rangeCount)return!1;if(""!==b.toString().trim())return!0;var c=this.getSelectedParentElement(b.getRangeAt(0));return!(!c||!("img"===c.nodeName.toLowerCase()||1===c.nodeType&&c.querySelector("img")))},selectionInContentEditableFalse:function(a){var b,c=this.findMatchingSelectionParent(function(a){var c=a&&a.getAttribute("contenteditable");return"true"===c&&(b=!0),"#text"!==a.nodeName&&"false"===c},a);return!b&&c},getSelectionHtml:function(a){var b,c,d,e="",f=a.getSelection();if(f.rangeCount){for(d=a.createElement("div"),b=0,c=f.rangeCount;c>b;b+=1)d.appendChild(f.getRangeAt(b).cloneContents());e=d.innerHTML}return e},getCaretOffsets:function(a,b){var c,d;return b||(b=window.getSelection().getRangeAt(0)),c=b.cloneRange(),d=b.cloneRange(),c.selectNodeContents(a),c.setEnd(b.endContainer,b.endOffset),d.selectNodeContents(a),d.setStart(b.endContainer,b.endOffset),{left:c.toString().length,right:d.toString().length}},rangeSelectsSingleNode:function(a){var b=a.startContainer;return b===a.endContainer&&b.hasChildNodes()&&a.endOffset===a.startOffset+1},getSelectedParentElement:function(a){return a?this.rangeSelectsSingleNode(a)&&3!==a.startContainer.childNodes[a.startOffset].nodeType?a.startContainer.childNodes[a.startOffset]:3===a.startContainer.nodeType?a.startContainer.parentNode:a.startContainer:null},getSelectedElements:function(a){var b,c,d,e=a.getSelection();if(!e.rangeCount||e.isCollapsed||!e.getRangeAt(0).commonAncestorContainer)return[];if(b=e.getRangeAt(0),3===b.commonAncestorContainer.nodeType){for(c=[],d=b.commonAncestorContainer;d.parentNode&&1===d.parentNode.childNodes.length;)c.push(d.parentNode),d=d.parentNode;return c}return[].filter.call(b.commonAncestorContainer.getElementsByTagName("*"),function(a){return"function"==typeof e.containsNode?e.containsNode(a,!0):!0})},selectNode:function(a,b){var c=b.createRange();c.selectNodeContents(a),this.selectRange(b,c)},select:function(a,b,c,d,e){var f=a.createRange();return f.setStart(b,c),d?f.setEnd(d,e):f.collapse(!0),this.selectRange(a,f),f},clearSelection:function(a,b){b?a.getSelection().collapseToStart():a.getSelection().collapseToEnd()},moveCursor:function(a,b,c){this.select(a,b,c)},getSelectionRange:function(a){var b=a.getSelection();return 0===b.rangeCount?null:b.getRangeAt(0)},selectRange:function(a,b){var c=a.getSelection();c.removeAllRanges(),c.addRange(b)},getSelectionStart:function(a){var b=a.getSelection().anchorNode,c=b&&3===b.nodeType?b.parentNode:b;return c}};a.selection=c}(),function(){function b(b,c){return b?b.some(function(b){if("function"!=typeof b.getInteractionElements)return!1;var d=b.getInteractionElements();return d?(Array.isArray(d)||(d=[d]),d.some(function(b){return a.util.isDescendant(b,c,!0)})):!1}):!1}var c=function(a){this.base=a,this.options=this.base.options,this.events=[],this.disabledEvents={},this.customEvents={},this.listeners={}};c.prototype={InputEventOnContenteditableSupported:!a.util.isIE&&!a.util.isEdge,attachDOMEvent:function(b,c,d,e){var f=this.base.options.contentWindow,g=this.base.options.ownerDocument;b=a.util.isElement(b)||[f,g].indexOf(b)>-1?[b]:b,Array.prototype.forEach.call(b,function(a){a.addEventListener(c,d,e),this.events.push([a,c,d,e])}.bind(this))},detachDOMEvent:function(b,c,d,e){var f,g,h=this.base.options.contentWindow,i=this.base.options.ownerDocument;b&&(b=a.util.isElement(b)||[h,i].indexOf(b)>-1?[b]:b,Array.prototype.forEach.call(b,function(a){f=this.indexOfListener(a,c,d,e),-1!==f&&(g=this.events.splice(f,1)[0],g[0].removeEventListener(g[1],g[2],g[3]))}.bind(this)))},indexOfListener:function(a,b,c,d){var e,f,g;for(e=0,f=this.events.length;f>e;e+=1)if(g=this.events[e],g[0]===a&&g[1]===b&&g[2]===c&&g[3]===d)return e;return-1},detachAllDOMEvents:function(){for(var a=this.events.pop();a;)a[0].removeEventListener(a[1],a[2],a[3]),a=this.events.pop()},detachAllEventsFromElement:function(a){for(var b=this.events.filter(function(b){return b&&b[0].getAttribute&&b[0].getAttribute("medium-editor-index")===a.getAttribute("medium-editor-index")}),c=0,d=b.length;d>c;c++){var e=b[c];this.detachDOMEvent(e[0],e[1],e[2],e[3])}},attachAllEventsToElement:function(a){this.listeners.editableInput&&(this.contentCache[a.getAttribute("medium-editor-index")]=a.innerHTML),this.eventsCache&&this.eventsCache.forEach(function(b){this.attachDOMEvent(a,b.name,b.handler.bind(this))},this)},enableCustomEvent:function(a){void 0!==this.disabledEvents[a]&&delete this.disabledEvents[a]},disableCustomEvent:function(a){this.disabledEvents[a]=!0},attachCustomEvent:function(a,b){this.setupListener(a),this.customEvents[a]||(this.customEvents[a]=[]),this.customEvents[a].push(b)},detachCustomEvent:function(a,b){var c=this.indexOfCustomListener(a,b);-1!==c&&this.customEvents[a].splice(c,1)},indexOfCustomListener:function(a,b){return this.customEvents[a]&&this.customEvents[a].length?this.customEvents[a].indexOf(b):-1},detachAllCustomEvents:function(){this.customEvents={}},triggerCustomEvent:function(a,b,c){this.customEvents[a]&&!this.disabledEvents[a]&&this.customEvents[a].forEach(function(a){a(b,c)})},destroy:function(){this.detachAllDOMEvents(),this.detachAllCustomEvents(),this.detachExecCommand(),this.base.elements&&this.base.elements.forEach(function(a){a.removeAttribute("data-medium-focused")})},attachToExecCommand:function(){this.execCommandListener||(this.execCommandListener=function(a){this.handleDocumentExecCommand(a)}.bind(this),this.wrapExecCommand(),this.options.ownerDocument.execCommand.listeners.push(this.execCommandListener))},detachExecCommand:function(){var a=this.options.ownerDocument;if(this.execCommandListener&&a.execCommand.listeners){var b=a.execCommand.listeners.indexOf(this.execCommandListener);-1!==b&&a.execCommand.listeners.splice(b,1),a.execCommand.listeners.length||this.unwrapExecCommand()}},wrapExecCommand:function(){var a=this.options.ownerDocument;if(!a.execCommand.listeners){var b=function(b,c){a.execCommand.listeners&&a.execCommand.listeners.forEach(function(a){a({command:b[0],value:b[2],args:b,result:c})})},c=function(){var c=a.execCommand.orig.apply(this,arguments);if(!a.execCommand.listeners)return c;var d=Array.prototype.slice.call(arguments);return b(d,c),c};c.orig=a.execCommand,c.listeners=[],c.callListeners=b,a.execCommand=c}},unwrapExecCommand:function(){var a=this.options.ownerDocument;a.execCommand.orig&&(a.execCommand=a.execCommand.orig)},setupListener:function(a){if(!this.listeners[a]){switch(a){case"externalInteraction":this.attachDOMEvent(this.options.ownerDocument.body,"mousedown",this.handleBodyMousedown.bind(this),!0),this.attachDOMEvent(this.options.ownerDocument.body,"click",this.handleBodyClick.bind(this),!0),this.attachDOMEvent(this.options.ownerDocument.body,"focus",this.handleBodyFocus.bind(this),!0);break;case"blur":this.setupListener("externalInteraction");break;case"focus":this.setupListener("externalInteraction");break;case"editableInput":this.contentCache={},this.base.elements.forEach(function(a){this.contentCache[a.getAttribute("medium-editor-index")]=a.innerHTML},this),this.InputEventOnContenteditableSupported&&this.attachToEachElement("input",this.handleInput),this.InputEventOnContenteditableSupported||(this.setupListener("editableKeypress"),this.keypressUpdateInput=!0,this.attachDOMEvent(document,"selectionchange",this.handleDocumentSelectionChange.bind(this)),this.attachToExecCommand());break;case"editableClick":this.attachToEachElement("click",this.handleClick);break;case"editableBlur":this.attachToEachElement("blur",this.handleBlur);break;case"editableKeypress":this.attachToEachElement("keypress",this.handleKeypress);break;case"editableKeyup":this.attachToEachElement("keyup",this.handleKeyup);break;case"editableKeydown":this.attachToEachElement("keydown",this.handleKeydown);break;case"editableKeydownSpace":this.setupListener("editableKeydown");break;case"editableKeydownEnter":this.setupListener("editableKeydown");break;case"editableKeydownTab":this.setupListener("editableKeydown");break;case"editableKeydownDelete":this.setupListener("editableKeydown");break;case"editableMouseover":this.attachToEachElement("mouseover",this.handleMouseover);break;case"editableDrag":this.attachToEachElement("dragover",this.handleDragging),this.attachToEachElement("dragleave",this.handleDragging);break;case"editableDrop":this.attachToEachElement("drop",this.handleDrop);break;case"editablePaste":this.attachToEachElement("paste",this.handlePaste)}this.listeners[a]=!0}},attachToEachElement:function(a,b){this.eventsCache||(this.eventsCache=[]),this.base.elements.forEach(function(c){this.attachDOMEvent(c,a,b.bind(this))},this),this.eventsCache.push({name:a,handler:b})},cleanupElement:function(a){var b=a.getAttribute("medium-editor-index");b&&(this.detachAllEventsFromElement(a),this.contentCache&&delete this.contentCache[b])},focusElement:function(a){a.focus(),this.updateFocus(a,{target:a,type:"focus"})},updateFocus:function(c,d){var e,f=this.base.getFocusedElement();f&&"click"===d.type&&this.lastMousedownTarget&&(a.util.isDescendant(f,this.lastMousedownTarget,!0)||b(this.base.extensions,this.lastMousedownTarget))&&(e=f),e||this.base.elements.some(function(b){return!e&&a.util.isDescendant(b,c,!0)&&(e=b),!!e},this);var g=!a.util.isDescendant(f,c,!0)&&!b(this.base.extensions,c);e!==f&&(f&&g&&(f.removeAttribute("data-medium-focused"),this.triggerCustomEvent("blur",d,f)),e&&(e.setAttribute("data-medium-focused",!0),this.triggerCustomEvent("focus",d,e))),g&&this.triggerCustomEvent("externalInteraction",d)},updateInput:function(a,b){if(this.contentCache){var c=a.getAttribute("medium-editor-index"),d=a.innerHTML;d!==this.contentCache[c]&&this.triggerCustomEvent("editableInput",b,a),this.contentCache[c]=d}},handleDocumentSelectionChange:function(b){if(b.currentTarget&&b.currentTarget.activeElement){var c,d=b.currentTarget.activeElement;this.base.elements.some(function(b){return a.util.isDescendant(b,d,!0)?(c=b,!0):!1},this),c&&this.updateInput(c,{target:d,currentTarget:c})}},handleDocumentExecCommand:function(){var a=this.base.getFocusedElement();a&&this.updateInput(a,{target:a,currentTarget:a})},handleBodyClick:function(a){this.updateFocus(a.target,a)},handleBodyFocus:function(a){this.updateFocus(a.target,a); +},handleBodyMousedown:function(a){this.lastMousedownTarget=a.target},handleInput:function(a){this.updateInput(a.currentTarget,a)},handleClick:function(a){this.triggerCustomEvent("editableClick",a,a.currentTarget)},handleBlur:function(a){this.triggerCustomEvent("editableBlur",a,a.currentTarget)},handleKeypress:function(a){if(this.triggerCustomEvent("editableKeypress",a,a.currentTarget),this.keypressUpdateInput){var b={target:a.target,currentTarget:a.currentTarget};setTimeout(function(){this.updateInput(b.currentTarget,b)}.bind(this),0)}},handleKeyup:function(a){this.triggerCustomEvent("editableKeyup",a,a.currentTarget)},handleMouseover:function(a){this.triggerCustomEvent("editableMouseover",a,a.currentTarget)},handleDragging:function(a){this.triggerCustomEvent("editableDrag",a,a.currentTarget)},handleDrop:function(a){this.triggerCustomEvent("editableDrop",a,a.currentTarget)},handlePaste:function(a){this.triggerCustomEvent("editablePaste",a,a.currentTarget)},handleKeydown:function(b){return this.triggerCustomEvent("editableKeydown",b,b.currentTarget),a.util.isKey(b,a.util.keyCode.SPACE)?this.triggerCustomEvent("editableKeydownSpace",b,b.currentTarget):a.util.isKey(b,a.util.keyCode.ENTER)||b.ctrlKey&&a.util.isKey(b,a.util.keyCode.M)?this.triggerCustomEvent("editableKeydownEnter",b,b.currentTarget):a.util.isKey(b,a.util.keyCode.TAB)?this.triggerCustomEvent("editableKeydownTab",b,b.currentTarget):a.util.isKey(b,[a.util.keyCode.DELETE,a.util.keyCode.BACKSPACE])?this.triggerCustomEvent("editableKeydownDelete",b,b.currentTarget):void 0}},a.Events=c}(),function(){var b=a.Extension.extend({action:void 0,aria:void 0,tagNames:void 0,style:void 0,useQueryState:void 0,contentDefault:void 0,contentFA:void 0,classList:void 0,attrs:void 0,constructor:function(c){b.isBuiltInButton(c)?a.Extension.call(this,this.defaults[c]):a.Extension.call(this,c)},init:function(){a.Extension.prototype.init.apply(this,arguments),this.button=this.createButton(),this.on(this.button,"click",this.handleClick.bind(this))},getButton:function(){return this.button},getAction:function(){return"function"==typeof this.action?this.action(this.base.options):this.action},getAria:function(){return"function"==typeof this.aria?this.aria(this.base.options):this.aria},getTagNames:function(){return"function"==typeof this.tagNames?this.tagNames(this.base.options):this.tagNames},createButton:function(){var a=this.document.createElement("button"),b=this.contentDefault,c=this.getAria(),d=this.getEditorOption("buttonLabels");return a.classList.add("medium-editor-action"),a.classList.add("medium-editor-action-"+this.name),this.classList&&this.classList.forEach(function(b){a.classList.add(b)}),a.setAttribute("data-action",this.getAction()),c&&(a.setAttribute("title",c),a.setAttribute("aria-label",c)),this.attrs&&Object.keys(this.attrs).forEach(function(b){a.setAttribute(b,this.attrs[b])},this),"fontawesome"===d&&this.contentFA&&(b=this.contentFA),a.innerHTML=b,a},handleClick:function(a){a.preventDefault(),a.stopPropagation();var b=this.getAction();b&&this.execAction(b)},isActive:function(){return this.button.classList.contains(this.getEditorOption("activeButtonClass"))},setInactive:function(){this.button.classList.remove(this.getEditorOption("activeButtonClass")),delete this.knownState},setActive:function(){this.button.classList.add(this.getEditorOption("activeButtonClass")),delete this.knownState},queryCommandState:function(){var a=null;return this.useQueryState&&(a=this.base.queryCommandState(this.getAction())),a},isAlreadyApplied:function(a){var b,c,d=!1,e=this.getTagNames();return this.knownState===!1||this.knownState===!0?this.knownState:(e&&e.length>0&&(d=-1!==e.indexOf(a.nodeName.toLowerCase())),!d&&this.style&&(b=this.style.value.split("|"),c=this.window.getComputedStyle(a,null).getPropertyValue(this.style.prop),b.forEach(function(a){this.knownState||(d=-1!==c.indexOf(a),(d||"text-decoration"!==this.style.prop)&&(this.knownState=d))},this)),d)}});b.isBuiltInButton=function(b){return"string"==typeof b&&a.extensions.button.prototype.defaults.hasOwnProperty(b)},a.extensions.button=b}(),function(){a.extensions.button.prototype.defaults={bold:{name:"bold",action:"bold",aria:"bold",tagNames:["b","strong"],style:{prop:"font-weight",value:"700|bold"},useQueryState:!0,contentDefault:"B",contentFA:''},italic:{name:"italic",action:"italic",aria:"italic",tagNames:["i","em"],style:{prop:"font-style",value:"italic"},useQueryState:!0,contentDefault:"I",contentFA:''},underline:{name:"underline",action:"underline",aria:"underline",tagNames:["u"],style:{prop:"text-decoration",value:"underline"},useQueryState:!0,contentDefault:"U",contentFA:''},strikethrough:{name:"strikethrough",action:"strikethrough",aria:"strike through",tagNames:["strike"],style:{prop:"text-decoration",value:"line-through"},useQueryState:!0,contentDefault:"A",contentFA:''},superscript:{name:"superscript",action:"superscript",aria:"superscript",tagNames:["sup"],contentDefault:"x1",contentFA:''},subscript:{name:"subscript",action:"subscript",aria:"subscript",tagNames:["sub"],contentDefault:"x1",contentFA:''},image:{name:"image",action:"image",aria:"image",tagNames:["img"],contentDefault:"image",contentFA:''},html:{name:"html",action:"html",aria:"evaluate html",tagNames:["iframe","object"],contentDefault:"html",contentFA:''},orderedlist:{name:"orderedlist",action:"insertorderedlist",aria:"ordered list",tagNames:["ol"],useQueryState:!0,contentDefault:"1.",contentFA:''},unorderedlist:{name:"unorderedlist",action:"insertunorderedlist",aria:"unordered list",tagNames:["ul"],useQueryState:!0,contentDefault:"",contentFA:''},indent:{name:"indent",action:"indent",aria:"indent",tagNames:[],contentDefault:"",contentFA:''},outdent:{name:"outdent",action:"outdent",aria:"outdent",tagNames:[],contentDefault:"",contentFA:''},justifyCenter:{name:"justifyCenter",action:"justifyCenter",aria:"center justify",tagNames:[],style:{prop:"text-align",value:"center"},contentDefault:"C",contentFA:''},justifyFull:{name:"justifyFull",action:"justifyFull",aria:"full justify",tagNames:[],style:{prop:"text-align",value:"justify"},contentDefault:"J",contentFA:''},justifyLeft:{name:"justifyLeft",action:"justifyLeft",aria:"left justify",tagNames:[],style:{prop:"text-align",value:"left"},contentDefault:"L",contentFA:''},justifyRight:{name:"justifyRight",action:"justifyRight",aria:"right justify",tagNames:[],style:{prop:"text-align",value:"right"},contentDefault:"R",contentFA:''},removeFormat:{name:"removeFormat",aria:"remove formatting",action:"removeFormat",contentDefault:"X",contentFA:''},quote:{name:"quote",action:"append-blockquote",aria:"blockquote",tagNames:["blockquote"],contentDefault:"",contentFA:''},pre:{name:"pre",action:"append-pre",aria:"preformatted text",tagNames:["pre"],contentDefault:"0101",contentFA:''},h1:{name:"h1",action:"append-h1",aria:"header type one",tagNames:["h1"],contentDefault:"H1",contentFA:'1'},h2:{name:"h2",action:"append-h2",aria:"header type two",tagNames:["h2"],contentDefault:"H2",contentFA:'2'},h3:{name:"h3",action:"append-h3",aria:"header type three",tagNames:["h3"],contentDefault:"H3",contentFA:'3'},h4:{name:"h4",action:"append-h4",aria:"header type four",tagNames:["h4"],contentDefault:"H4",contentFA:'4'},h5:{name:"h5",action:"append-h5",aria:"header type five",tagNames:["h5"],contentDefault:"H5",contentFA:'5'},h6:{name:"h6",action:"append-h6",aria:"header type six",tagNames:["h6"],contentDefault:"H6",contentFA:'6'}}}(),function(){var b=a.extensions.button.extend({init:function(){a.extensions.button.prototype.init.apply(this,arguments)},formSaveLabel:"✓",formCloseLabel:"×",activeClass:"medium-editor-toolbar-form-active",hasForm:!0,getForm:function(){},isDisplayed:function(){return this.hasForm?this.getForm().classList.contains(this.activeClass):!1},showForm:function(){this.hasForm&&this.getForm().classList.add(this.activeClass)},hideForm:function(){this.hasForm&&this.getForm().classList.remove(this.activeClass)},showToolbarDefaultActions:function(){var a=this.base.getExtensionByName("toolbar");a&&a.showToolbarDefaultActions()},hideToolbarDefaultActions:function(){var a=this.base.getExtensionByName("toolbar");a&&a.hideToolbarDefaultActions()},setToolbarPosition:function(){var a=this.base.getExtensionByName("toolbar");a&&a.setToolbarPosition()}});a.extensions.form=b}(),function(){var b=a.extensions.form.extend({customClassOption:null,customClassOptionText:"Button",linkValidation:!1,placeholderText:"Paste or type a link",targetCheckbox:!1,targetCheckboxText:"Open in new window",name:"anchor",action:"createLink",aria:"link",tagNames:["a"],contentDefault:"#",contentFA:'',init:function(){a.extensions.form.prototype.init.apply(this,arguments),this.subscribe("editableKeydown",this.handleKeydown.bind(this))},handleClick:function(b){b.preventDefault(),b.stopPropagation();var c=a.selection.getSelectionRange(this.document);return"a"===c.startContainer.nodeName.toLowerCase()||"a"===c.endContainer.nodeName.toLowerCase()||a.util.getClosestTag(a.selection.getSelectedParentElement(c),"a")?this.execAction("unlink"):(this.isDisplayed()||this.showForm(),!1)},handleKeydown:function(b){a.util.isKey(b,a.util.keyCode.K)&&a.util.isMetaCtrlKey(b)&&!b.shiftKey&&this.handleClick(b)},getForm:function(){return this.form||(this.form=this.createForm()),this.form},getTemplate:function(){var a=[''];return a.push('',"fontawesome"===this.getEditorOption("buttonLabels")?'':this.formSaveLabel,""),a.push('',"fontawesome"===this.getEditorOption("buttonLabels")?'':this.formCloseLabel,""),this.targetCheckbox&&a.push('

','','","
"),this.customClassOption&&a.push('
','',"","
"),a.join("")},isDisplayed:function(){return a.extensions.form.prototype.isDisplayed.apply(this)},hideForm:function(){a.extensions.form.prototype.hideForm.apply(this),this.getInput().value=""},showForm:function(b){var c=this.getInput(),d=this.getAnchorTargetCheckbox(),e=this.getAnchorButtonCheckbox();if(b=b||{value:""},"string"==typeof b&&(b={value:b}),this.base.saveSelection(),this.hideToolbarDefaultActions(),a.extensions.form.prototype.showForm.apply(this),this.setToolbarPosition(),c.value=b.value,c.focus(),d&&(d.checked="_blank"===b.target),e){var f=b.buttonClass?b.buttonClass.split(" "):[];e.checked=-1!==f.indexOf(this.customClassOption)}},destroy:function(){return this.form?(this.form.parentNode&&this.form.parentNode.removeChild(this.form),void delete this.form):!1},getFormOpts:function(){var a=this.getAnchorTargetCheckbox(),b=this.getAnchorButtonCheckbox(),c={value:this.getInput().value.trim()};return this.linkValidation&&(c.value=this.checkLinkFormat(c.value)),c.target="_self",a&&a.checked&&(c.target="_blank"),b&&b.checked&&(c.buttonClass=this.customClassOption),c},doFormSave:function(){var a=this.getFormOpts();this.completeFormSave(a)},completeFormSave:function(a){this.base.restoreSelection(),this.execAction(this.action,a),this.base.checkSelection()},ensureEncodedUri:function(a){return a===decodeURI(a)?encodeURI(a):a},ensureEncodedUriComponent:function(a){return a===decodeURIComponent(a)?encodeURIComponent(a):a},ensureEncodedParam:function(a){var b=a.split("="),c=b[0],d=b[1];return c+(void 0===d?"":"="+this.ensureEncodedUriComponent(d))},ensureEncodedQuery:function(a){return a.split("&").map(this.ensureEncodedParam.bind(this)).join("&")},checkLinkFormat:function(a){var b=/^([a-z]+:)?\/\/|^(mailto|tel|maps):|^\#/i,c=b.test(a),d="",e=/^\+?\s?\(?(?:\d\s?\-?\)?){3,20}$/,f=a.match(/^(.*?)(?:\?(.*?))?(?:#(.*))?$/),g=f[1],h=f[2],i=f[3];if(e.test(a))return"tel:"+a;if(!c){var j=g.split("/")[0];(j.match(/.+(\.|:).+/)||"localhost"===j)&&(d="http://")}return d+this.ensureEncodedUri(g)+(void 0===h?"":"?"+this.ensureEncodedQuery(h))+(void 0===i?"":"#"+i)},doFormCancel:function(){this.base.restoreSelection(),this.base.checkSelection()},attachFormEvents:function(a){var b=a.querySelector(".medium-editor-toolbar-close"),c=a.querySelector(".medium-editor-toolbar-save"),d=a.querySelector(".medium-editor-toolbar-input");this.on(a,"click",this.handleFormClick.bind(this)),this.on(d,"keyup",this.handleTextboxKeyup.bind(this)),this.on(b,"click",this.handleCloseClick.bind(this)),this.on(c,"click",this.handleSaveClick.bind(this),!0)},createForm:function(){var a=this.document,b=a.createElement("div");return b.className="medium-editor-toolbar-form",b.id="medium-editor-toolbar-form-anchor-"+this.getEditorId(),b.innerHTML=this.getTemplate(),this.attachFormEvents(b),b},getInput:function(){return this.getForm().querySelector("input.medium-editor-toolbar-input")},getAnchorTargetCheckbox:function(){return this.getForm().querySelector(".medium-editor-toolbar-anchor-target")},getAnchorButtonCheckbox:function(){return this.getForm().querySelector(".medium-editor-toolbar-anchor-button")},handleTextboxKeyup:function(b){return b.keyCode===a.util.keyCode.ENTER?(b.preventDefault(),void this.doFormSave()):void(b.keyCode===a.util.keyCode.ESCAPE&&(b.preventDefault(),this.doFormCancel()))},handleFormClick:function(a){a.stopPropagation()},handleSaveClick:function(a){a.preventDefault(),this.doFormSave()},handleCloseClick:function(a){a.preventDefault(),this.doFormCancel()}});a.extensions.anchor=b}(),function(){var b=a.Extension.extend({name:"anchor-preview",hideDelay:500,previewValueSelector:"a",showWhenToolbarIsVisible:!1,showOnEmptyLinks:!0,init:function(){this.anchorPreview=this.createPreview(),this.getEditorOption("elementsContainer").appendChild(this.anchorPreview),this.attachToEditables()},getInteractionElements:function(){return this.getPreviewElement()},getPreviewElement:function(){return this.anchorPreview},createPreview:function(){var a=this.document.createElement("div");return a.id="medium-editor-anchor-preview-"+this.getEditorId(),a.className="medium-editor-anchor-preview",a.innerHTML=this.getTemplate(),this.on(a,"click",this.handleClick.bind(this)),a},getTemplate:function(){return'
'},destroy:function(){this.anchorPreview&&(this.anchorPreview.parentNode&&this.anchorPreview.parentNode.removeChild(this.anchorPreview),delete this.anchorPreview)},hidePreview:function(){this.anchorPreview&&this.anchorPreview.classList.remove("medium-editor-anchor-preview-active"),this.activeAnchor=null},showPreview:function(a){return this.anchorPreview.classList.contains("medium-editor-anchor-preview-active")||a.getAttribute("data-disable-preview")?!0:(this.previewValueSelector&&(this.anchorPreview.querySelector(this.previewValueSelector).textContent=a.attributes.href.value,this.anchorPreview.querySelector(this.previewValueSelector).href=a.attributes.href.value),this.anchorPreview.classList.add("medium-toolbar-arrow-over"),this.anchorPreview.classList.remove("medium-toolbar-arrow-under"),this.anchorPreview.classList.contains("medium-editor-anchor-preview-active")||this.anchorPreview.classList.add("medium-editor-anchor-preview-active"),this.activeAnchor=a,this.positionPreview(),this.attachPreviewHandlers(),this)},positionPreview:function(a){a=a||this.activeAnchor;var b,c,d,e,f,g=this.window.innerWidth,h=this.anchorPreview.offsetHeight,i=a.getBoundingClientRect(),j=this.diffLeft,k=this.diffTop,l=this.getEditorOption("elementsContainer"),m=["absolute","fixed"].indexOf(window.getComputedStyle(l).getPropertyValue("position"))>-1,n={};b=this.anchorPreview.offsetWidth/2;var o=this.base.getExtensionByName("toolbar");o&&(j=o.diffLeft,k=o.diffTop),c=j-b,m?(e=l.getBoundingClientRect(),["top","left"].forEach(function(a){n[a]=i[a]-e[a]}),n.width=i.width,n.height=i.height,i=n,g=e.width,f=l.scrollTop):f=this.window.pageYOffset,d=i.left+i.width/2,f+=h+i.top+i.height-k-this.anchorPreview.offsetHeight,this.anchorPreview.style.top=Math.round(f)+"px",this.anchorPreview.style.right="initial",b>d?(this.anchorPreview.style.left=c+b+"px",this.anchorPreview.style.right="initial"):b>g-d?(this.anchorPreview.style.left="auto",this.anchorPreview.style.right=0):(this.anchorPreview.style.left=c+d+"px",this.anchorPreview.style.right="initial")},attachToEditables:function(){this.subscribe("editableMouseover",this.handleEditableMouseover.bind(this)),this.subscribe("positionedToolbar",this.handlePositionedToolbar.bind(this))},handlePositionedToolbar:function(){this.showWhenToolbarIsVisible||this.hidePreview()},handleClick:function(a){var b=this.base.getExtensionByName("anchor"),c=this.activeAnchor;b&&c&&(a.preventDefault(),this.base.selectElement(this.activeAnchor),this.base.delay(function(){if(c){var a={value:c.attributes.href.value,target:c.getAttribute("target"),buttonClass:c.getAttribute("class")};b.showForm(a),c=null}}.bind(this))),this.hidePreview()},handleAnchorMouseout:function(){this.anchorToPreview=null,this.off(this.activeAnchor,"mouseout",this.instanceHandleAnchorMouseout),this.instanceHandleAnchorMouseout=null},handleEditableMouseover:function(b){var c=a.util.getClosestTag(b.target,"a");if(!1!==c){if(!this.showOnEmptyLinks&&(!/href=["']\S+["']/.test(c.outerHTML)||/href=["']#\S+["']/.test(c.outerHTML)))return!0;var d=this.base.getExtensionByName("toolbar");if(!this.showWhenToolbarIsVisible&&d&&d.isDisplayed&&d.isDisplayed())return!0;this.activeAnchor&&this.activeAnchor!==c&&this.detachPreviewHandlers(),this.anchorToPreview=c,this.instanceHandleAnchorMouseout=this.handleAnchorMouseout.bind(this),this.on(this.anchorToPreview,"mouseout",this.instanceHandleAnchorMouseout),this.base.delay(function(){this.anchorToPreview&&this.showPreview(this.anchorToPreview)}.bind(this))}},handlePreviewMouseover:function(){this.lastOver=(new Date).getTime(),this.hovering=!0},handlePreviewMouseout:function(a){a.relatedTarget&&/anchor-preview/.test(a.relatedTarget.className)||(this.hovering=!1)},updatePreview:function(){if(this.hovering)return!0;var a=(new Date).getTime()-this.lastOver;a>this.hideDelay&&this.detachPreviewHandlers()},detachPreviewHandlers:function(){clearInterval(this.intervalTimer),this.instanceHandlePreviewMouseover&&(this.off(this.anchorPreview,"mouseover",this.instanceHandlePreviewMouseover),this.off(this.anchorPreview,"mouseout",this.instanceHandlePreviewMouseout),this.activeAnchor&&(this.off(this.activeAnchor,"mouseover",this.instanceHandlePreviewMouseover),this.off(this.activeAnchor,"mouseout",this.instanceHandlePreviewMouseout))),this.hidePreview(),this.hovering=this.instanceHandlePreviewMouseover=this.instanceHandlePreviewMouseout=null},attachPreviewHandlers:function(){this.lastOver=(new Date).getTime(),this.hovering=!0,this.instanceHandlePreviewMouseover=this.handlePreviewMouseover.bind(this),this.instanceHandlePreviewMouseout=this.handlePreviewMouseout.bind(this),this.intervalTimer=setInterval(this.updatePreview.bind(this),200),this.on(this.anchorPreview,"mouseover",this.instanceHandlePreviewMouseover),this.on(this.anchorPreview,"mouseout",this.instanceHandlePreviewMouseout),this.on(this.activeAnchor,"mouseover",this.instanceHandlePreviewMouseover),this.on(this.activeAnchor,"mouseout",this.instanceHandlePreviewMouseout)}});a.extensions.anchorPreview=b}(),function(){function b(b){return!a.util.getClosestTag(b,"a")}var c,d,e,f,g;c=[" "," ","\n","\r"," "," "," "," "," ","\u2028","\u2029"],d="com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw",e="(((?:(https?://|ftps?://|nntp://)|www\\d{0,3}[.]|[a-z0-9.\\-]+[.]("+d+")\\/)\\S+(?:[^\\s`!\\[\\]{};:'\".,?«»“”‘’])))|(([a-z0-9\\-]+\\.)?[a-z0-9\\-]+\\.("+d+"))",f=new RegExp("^("+d+")$","i"),g=new RegExp(e,"gi");var h=a.Extension.extend({init:function(){a.Extension.prototype.init.apply(this,arguments),this.disableEventHandling=!1,this.subscribe("editableKeypress",this.onKeypress.bind(this)),this.subscribe("editableBlur",this.onBlur.bind(this)),this.document.execCommand("AutoUrlDetect",!1,!1)},isLastInstance:function(){for(var a=0,b=0;b0&&null!==g;)e=c.currentNode,f=e.nodeValue,f.length>b?(g=e.splitText(f.length-b),b=0):(g=c.previousNode(),b-=f.length);return g},performLinkingWithinElement:function(b){for(var c=this.findLinkableText(b),d=!1,e=0;e1;)e.appendChild(d.childNodes[1])}});a.extensions.autoLink=h}(),function(){function b(b){var d=a.util.getContainerEditorElement(b),e=Array.prototype.slice.call(d.parentElement.querySelectorAll("."+c));e.forEach(function(a){a.classList.remove(c)})}var c="medium-editor-dragover",d=a.Extension.extend({name:"fileDragging",allowedTypes:["image"],init:function(){a.Extension.prototype.init.apply(this,arguments),this.subscribe("editableDrag",this.handleDrag.bind(this)),this.subscribe("editableDrop",this.handleDrop.bind(this))},handleDrag:function(a){a.preventDefault(),a.dataTransfer.dropEffect="copy";var d=a.target.classList?a.target:a.target.parentElement;b(d),"dragover"===a.type&&d.classList.add(c)},handleDrop:function(a){a.preventDefault(),a.stopPropagation(),this.base.selectElement(a.target);var c=this.base.exportSelection();c.start=c.end,this.base.importSelection(c),a.dataTransfer.files&&Array.prototype.slice.call(a.dataTransfer.files).forEach(function(a){this.isAllowedFile(a)&&a.type.match("image")&&this.insertImageFile(a)},this),b(a.target)},isAllowedFile:function(a){return this.allowedTypes.some(function(b){return!!a.type.match(b)})},insertImageFile:function(b){if("function"==typeof FileReader){var c=new FileReader;c.readAsDataURL(b),c.addEventListener("load",function(b){var c=this.document.createElement("img");c.src=b.target.result,a.util.insertHTMLCommand(this.document,c.outerHTML)}.bind(this))}}});a.extensions.fileDragging=d}(),function(){var b=a.Extension.extend({name:"keyboard-commands",commands:[{command:"bold",key:"B",meta:!0,shift:!1,alt:!1},{command:"italic",key:"I",meta:!0,shift:!1,alt:!1},{command:"underline",key:"U",meta:!0,shift:!1,alt:!1}],init:function(){a.Extension.prototype.init.apply(this,arguments),this.subscribe("editableKeydown",this.handleKeydown.bind(this)),this.keys={},this.commands.forEach(function(a){var b=a.key.charCodeAt(0);this.keys[b]||(this.keys[b]=[]),this.keys[b].push(a)},this)},handleKeydown:function(b){var c=a.util.getKeyCode(b);if(this.keys[c]){var d=a.util.isMetaCtrlKey(b),e=!!b.shiftKey,f=!!b.altKey;this.keys[c].forEach(function(a){a.meta!==d||a.shift!==e||a.alt!==f&&void 0!==a.alt||(b.preventDefault(),b.stopPropagation(),"function"==typeof a.command?a.command.apply(this):!1!==a.command&&this.execAction(a.command))},this)}}});a.extensions.keyboardCommands=b}(),function(){var b=a.extensions.form.extend({name:"fontname",action:"fontName",aria:"change font name",contentDefault:"±",contentFA:'',fonts:["","Arial","Verdana","Times New Roman"],init:function(){a.extensions.form.prototype.init.apply(this,arguments)},handleClick:function(a){if(a.preventDefault(),a.stopPropagation(),!this.isDisplayed()){var b=this.document.queryCommandValue("fontName")+"";this.showForm(b)}return!1},getForm:function(){return this.form||(this.form=this.createForm()),this.form},isDisplayed:function(){return"block"===this.getForm().style.display},hideForm:function(){this.getForm().style.display="none",this.getSelect().value=""},showForm:function(a){var b=this.getSelect();this.base.saveSelection(),this.hideToolbarDefaultActions(),this.getForm().style.display="block",this.setToolbarPosition(),b.value=a||"",b.focus()},destroy:function(){return this.form?(this.form.parentNode&&this.form.parentNode.removeChild(this.form),void delete this.form):!1},doFormSave:function(){this.base.restoreSelection(),this.base.checkSelection()},doFormCancel:function(){this.base.restoreSelection(),this.clearFontName(),this.base.checkSelection()},createForm:function(){var a,b=this.document,c=b.createElement("div"),d=b.createElement("select"),e=b.createElement("a"),f=b.createElement("a");c.className="medium-editor-toolbar-form",c.id="medium-editor-toolbar-form-fontname-"+this.getEditorId(),this.on(c,"click",this.handleFormClick.bind(this));for(var g=0;g
':"✓",c.appendChild(f),this.on(f,"click",this.handleSaveClick.bind(this),!0),e.setAttribute("href","#"),e.className="medium-editor-toobar-close",e.innerHTML="fontawesome"===this.getEditorOption("buttonLabels")?'':"×",c.appendChild(e),this.on(e,"click",this.handleCloseClick.bind(this)),c},getSelect:function(){return this.getForm().querySelector("select.medium-editor-toolbar-select")},clearFontName:function(){a.selection.getSelectedElements(this.document).forEach(function(a){"font"===a.nodeName.toLowerCase()&&a.hasAttribute("face")&&a.removeAttribute("face")})},handleFontChange:function(){var a=this.getSelect().value;""===a?this.clearFontName():this.execAction("fontName",{value:a})},handleFormClick:function(a){a.stopPropagation()},handleSaveClick:function(a){a.preventDefault(),this.doFormSave()},handleCloseClick:function(a){a.preventDefault(),this.doFormCancel()}});a.extensions.fontName=b}(),function(){var b=a.extensions.form.extend({name:"fontsize",action:"fontSize",aria:"increase/decrease font size",contentDefault:"±",contentFA:'',init:function(){a.extensions.form.prototype.init.apply(this,arguments)},handleClick:function(a){if(a.preventDefault(),a.stopPropagation(),!this.isDisplayed()){var b=this.document.queryCommandValue("fontSize")+"";this.showForm(b)}return!1},getForm:function(){return this.form||(this.form=this.createForm()),this.form},isDisplayed:function(){return"block"===this.getForm().style.display},hideForm:function(){this.getForm().style.display="none",this.getInput().value=""},showForm:function(a){var b=this.getInput();this.base.saveSelection(),this.hideToolbarDefaultActions(),this.getForm().style.display="block",this.setToolbarPosition(),b.value=a||"",b.focus()},destroy:function(){return this.form?(this.form.parentNode&&this.form.parentNode.removeChild(this.form),void delete this.form):!1},doFormSave:function(){this.base.restoreSelection(),this.base.checkSelection()},doFormCancel:function(){this.base.restoreSelection(),this.clearFontSize(),this.base.checkSelection()},createForm:function(){var a=this.document,b=a.createElement("div"),c=a.createElement("input"),d=a.createElement("a"),e=a.createElement("a");return b.className="medium-editor-toolbar-form",b.id="medium-editor-toolbar-form-fontsize-"+this.getEditorId(),this.on(b,"click",this.handleFormClick.bind(this)),c.setAttribute("type","range"),c.setAttribute("min","1"), +c.setAttribute("max","7"),c.className="medium-editor-toolbar-input",b.appendChild(c),this.on(c,"change",this.handleSliderChange.bind(this)),e.setAttribute("href","#"),e.className="medium-editor-toobar-save",e.innerHTML="fontawesome"===this.getEditorOption("buttonLabels")?'':"✓",b.appendChild(e),this.on(e,"click",this.handleSaveClick.bind(this),!0),d.setAttribute("href","#"),d.className="medium-editor-toobar-close",d.innerHTML="fontawesome"===this.getEditorOption("buttonLabels")?'':"×",b.appendChild(d),this.on(d,"click",this.handleCloseClick.bind(this)),b},getInput:function(){return this.getForm().querySelector("input.medium-editor-toolbar-input")},clearFontSize:function(){a.selection.getSelectedElements(this.document).forEach(function(a){"font"===a.nodeName.toLowerCase()&&a.hasAttribute("size")&&a.removeAttribute("size")})},handleSliderChange:function(){var a=this.getInput().value;"4"===a?this.clearFontSize():this.execAction("fontSize",{value:a})},handleFormClick:function(a){a.stopPropagation()},handleSaveClick:function(a){a.preventDefault(),this.doFormSave()},handleCloseClick:function(a){a.preventDefault(),this.doFormCancel()}});a.extensions.fontSize=b}(),function(){function b(){return[[new RegExp(/^[\s\S]*]*>\s*|\s*<\/body[^>]*>[\s\S]*$/g),""],[new RegExp(/|/g),""],[new RegExp(/
$/i),""],[new RegExp(/<[^>]*docs-internal-guid[^>]*>/gi),""],[new RegExp(/<\/b>(]*>)?$/gi),""],[new RegExp(/\s+<\/span>/g)," "],[new RegExp(/
/g),"
"],[new RegExp(/]*(font-style:italic;font-weight:(bold|700)|font-weight:(bold|700);font-style:italic)[^>]*>/gi),''],[new RegExp(/]*font-style:italic[^>]*>/gi),''],[new RegExp(/]*font-weight:(bold|700)[^>]*>/gi),''],[new RegExp(/<(\/?)(i|b|a)>/gi),"<$1$2>"],[new RegExp(/<a(?:(?!href).)+href=(?:"|”|“|"|“|”)(((?!"|”|“|"|“|”).)*)(?:"|”|“|"|“|”)(?:(?!>).)*>/gi),''],[new RegExp(/<\/p>\n+/gi),"

"],[new RegExp(/\n+

/gi),""],[new RegExp(/(((?!/gi),"$1"]]}function c(a,b,c){var d=a.clipboardData||b.clipboardData||c.dataTransfer,e={};if(!d)return e;if(d.getData){var f=d.getData("Text");f&&f.length>0&&(e["text/plain"]=f)}if(d.types)for(var g=0;g1)for(f=0;f"+a.util.htmlEntities(e[f])+"

");else g=a.util.htmlEntities(e[0]);a.util.insertHTMLCommand(this.document,g)}},handlePasteBinPaste:function(a){if(a.defaultPrevented)return void this.removePasteBin();var b=c(a,this.window,this.document),d=b["text/html"],e=b["text/plain"],g=f;return!this.cleanPastedHTML||d?(a.preventDefault(),this.removePasteBin(),this.doPaste(d,e,g),void this.trigger("editablePaste",{currentTarget:g,target:g},g)):void setTimeout(function(){this.cleanPastedHTML&&(d=this.getPasteBinHtml()),this.removePasteBin(),this.doPaste(d,e,g),this.trigger("editablePaste",{currentTarget:g,target:g},g)}.bind(this),0)},handleKeydown:function(b,c){a.util.isKey(b,a.util.keyCode.V)&&a.util.isMetaCtrlKey(b)&&(b.stopImmediatePropagation(),this.removePasteBin(),this.createPasteBin(c))},createPasteBin:function(b){var c,h=a.selection.getSelectionRange(this.document),i=this.window.pageYOffset;f=b,h&&(c=h.getClientRects(),i+=c.length?c[0].top:void 0!==h.startContainer.getBoundingClientRect?h.startContainer.getBoundingClientRect().top:h.getBoundingClientRect().top),e=h;var j=this.document.createElement("div");j.id=this.pasteBinId="medium-editor-pastebin-"+ +Date.now(),j.setAttribute("style","border: 1px red solid; position: absolute; top: "+i+"px; width: 10px; height: 10px; overflow: hidden; opacity: 0"),j.setAttribute("contentEditable",!0),j.innerHTML=d,this.document.body.appendChild(j),this.on(j,"focus",g),this.on(j,"focusin",g),this.on(j,"focusout",g),j.focus(),a.selection.selectNode(j,this.document),this.boundHandlePaste||(this.boundHandlePaste=this.handlePasteBinPaste.bind(this)),this.on(j,"paste",this.boundHandlePaste)},removePasteBin:function(){null!==e&&(a.selection.selectRange(this.document,e),e=null),null!==f&&(f=null);var b=this.getPasteBin();b&&b&&(this.off(b,"focus",g),this.off(b,"focusin",g),this.off(b,"focusout",g),this.off(b,"paste",this.boundHandlePaste),b.parentElement.removeChild(b))},getPasteBin:function(){return this.document.getElementById(this.pasteBinId)},getPasteBinHtml:function(){var a=this.getPasteBin();if(!a)return!1;if(a.firstChild&&"mcepastebin"===a.firstChild.id)return!1;var b=a.innerHTML;return b&&b!==d?b:!1},cleanPaste:function(a){var c,d,e,f,g=/"+a.split("

").join("

")+"

",d=e.querySelectorAll("a,p,div,br"),c=0;c"+d.innerHTML+"
":e.innerHTML=d.innerHTML,d.parentNode.replaceChild(e,d);for(f=b.querySelectorAll("span"),c=0;c0&&(d[0].classList.add(this.firstButtonClass),d[d.length-1].classList.add(this.lastButtonClass)),h},destroy:function(){this.toolbar&&(this.toolbar.parentNode&&this.toolbar.parentNode.removeChild(this.toolbar),delete this.toolbar)},getInteractionElements:function(){return this.getToolbarElement()},getToolbarElement:function(){return this.toolbar||(this.toolbar=this.createToolbar()),this.toolbar},getToolbarActionsElement:function(){return this.getToolbarElement().querySelector(".medium-editor-toolbar-actions")},initThrottledMethods:function(){this.throttledPositionToolbar=a.util.throttle(function(){this.base.isActive&&this.positionToolbarIfShown()}.bind(this))},attachEventHandlers:function(){this.subscribe("blur",this.handleBlur.bind(this)),this.subscribe("focus",this.handleFocus.bind(this)),this.subscribe("editableClick",this.handleEditableClick.bind(this)),this.subscribe("editableKeyup",this.handleEditableKeyup.bind(this)),this.on(this.document.documentElement,"mouseup",this.handleDocumentMouseup.bind(this)),this["static"]&&this.sticky&&this.on(this.window,"scroll",this.handleWindowScroll.bind(this),!0),this.on(this.window,"resize",this.handleWindowResize.bind(this))},handleWindowScroll:function(){this.positionToolbarIfShown()},handleWindowResize:function(){this.throttledPositionToolbar()},handleDocumentMouseup:function(b){return b&&b.target&&a.util.isDescendant(this.getToolbarElement(),b.target)?!1:void this.checkState()},handleEditableClick:function(){setTimeout(function(){this.checkState()}.bind(this),0)},handleEditableKeyup:function(){this.checkState()},handleBlur:function(){clearTimeout(this.hideTimeout),clearTimeout(this.delayShowTimeout),this.hideTimeout=setTimeout(function(){this.hideToolbar()}.bind(this),1)},handleFocus:function(){this.checkState()},isDisplayed:function(){return this.getToolbarElement().classList.contains("medium-editor-toolbar-active")},showToolbar:function(){clearTimeout(this.hideTimeout),this.isDisplayed()||(this.getToolbarElement().classList.add("medium-editor-toolbar-active"),this.trigger("showToolbar",{},this.base.getFocusedElement()))},hideToolbar:function(){this.isDisplayed()&&(this.getToolbarElement().classList.remove("medium-editor-toolbar-active"),this.trigger("hideToolbar",{},this.base.getFocusedElement()))},isToolbarDefaultActionsDisplayed:function(){return"block"===this.getToolbarActionsElement().style.display},hideToolbarDefaultActions:function(){this.isToolbarDefaultActionsDisplayed()&&(this.getToolbarActionsElement().style.display="none")},showToolbarDefaultActions:function(){this.hideExtensionForms(),this.isToolbarDefaultActionsDisplayed()||(this.getToolbarActionsElement().style.display="block"),this.delayShowTimeout=this.base.delay(function(){this.showToolbar()}.bind(this))},hideExtensionForms:function(){this.forEachExtension(function(a){a.hasForm&&a.isDisplayed()&&a.hideForm()})},multipleBlockElementsSelected:function(){var b=/<[^\/>][^>]*><\/[^>]+>/gim,c=new RegExp("<("+a.util.blockContainerElementNames.join("|")+")[^>]*>","g"),d=a.selection.getSelectionHtml(this.document).replace(b,""),e=d.match(c);return!!e&&e.length>1},modifySelection:function(){var b=this.window.getSelection(),c=b.getRangeAt(0);if(this.standardizeSelectionStart&&c.startContainer.nodeValue&&c.startOffset===c.startContainer.nodeValue.length){var d=a.util.findAdjacentTextNodeWithContent(a.selection.getSelectionElement(this.window),c.startContainer,this.document);if(d){for(var e=0;0===d.nodeValue.substr(e,1).trim().length;)e+=1;c=a.selection.select(this.document,d,e,c.endContainer,c.endOffset)}}},checkState:function(){if(!this.base.preventSelectionUpdates){if(!this.base.getFocusedElement()||a.selection.selectionInContentEditableFalse(this.window))return this.hideToolbar();var b=a.selection.getSelectionElement(this.window);return!b||-1===this.getEditorElements().indexOf(b)||b.getAttribute("data-disable-toolbar")?this.hideToolbar():this.updateOnEmptySelection&&this["static"]?this.showAndUpdateToolbar():!a.selection.selectionContainsContent(this.document)||this.allowMultiParagraphSelection===!1&&this.multipleBlockElementsSelected()?this.hideToolbar():void this.showAndUpdateToolbar()}},showAndUpdateToolbar:function(){this.modifySelection(),this.setToolbarButtonStates(),this.trigger("positionToolbar",{},this.base.getFocusedElement()),this.showToolbarDefaultActions(),this.setToolbarPosition()},setToolbarButtonStates:function(){this.forEachExtension(function(a){"function"==typeof a.isActive&&"function"==typeof a.setInactive&&a.setInactive()}),this.checkActiveButtons()},checkActiveButtons:function(){var b,c=[],d=null,e=a.selection.getSelectionRange(this.document),f=function(a){"function"==typeof a.checkState?a.checkState(b):"function"==typeof a.isActive&&"function"==typeof a.isAlreadyApplied&&"function"==typeof a.setActive&&!a.isActive()&&a.isAlreadyApplied(b)&&a.setActive()};if(e&&(this.forEachExtension(function(a){return"function"==typeof a.queryCommandState&&(d=a.queryCommandState(),null!==d)?void(d&&"function"==typeof a.setActive&&a.setActive()):void c.push(a)}),b=a.selection.getSelectedParentElement(e),this.getEditorElements().some(function(c){return a.util.isDescendant(c,b,!0)})))for(;b&&(c.forEach(f),!a.util.isMediumEditorElement(b));)b=b.parentNode},positionToolbarIfShown:function(){this.isDisplayed()&&this.setToolbarPosition()},setToolbarPosition:function(){var a=this.base.getFocusedElement(),b=this.window.getSelection();return a?void(!this["static"]&&b.isCollapsed||(this.showToolbar(),this.relativeContainer||(this["static"]?this.positionStaticToolbar(a):this.positionToolbar(b)),this.trigger("positionedToolbar",{},this.base.getFocusedElement()))):this},positionStaticToolbar:function(a){this.getToolbarElement().style.left="0";var b,c=this.document.documentElement&&this.document.documentElement.scrollTop||this.document.body.scrollTop,d=this.window.innerWidth,e=this.getToolbarElement(),f=a.getBoundingClientRect(),g=f.top+c,h=f.left+f.width/2,i=e.offsetHeight,j=e.offsetWidth,k=j/2;switch(this.sticky?c>g+a.offsetHeight-i-this.stickyTopOffset?(e.style.top=g+a.offsetHeight-i+"px",e.classList.remove("medium-editor-sticky-toolbar")):c>g-i-this.stickyTopOffset?(e.classList.add("medium-editor-sticky-toolbar"),e.style.top=this.stickyTopOffset+"px"):(e.classList.remove("medium-editor-sticky-toolbar"),e.style.top=g-i+"px"):e.style.top=g-i+"px",this.align){case"left":b=f.left;break;case"right":b=f.right-j;break;case"center":b=h-k}0>b?b=0:b+j>d&&(b=d-Math.ceil(j)-1),e.style.left=b+"px"},positionToolbar:function(a){this.getToolbarElement().style.left="0",this.getToolbarElement().style.right="initial";var b=a.getRangeAt(0),c=b.getBoundingClientRect();(!c||0===c.height&&0===c.width&&b.startContainer===b.endContainer)&&(c=1===b.startContainer.nodeType&&b.startContainer.querySelector("img")?b.startContainer.querySelector("img").getBoundingClientRect():b.startContainer.getBoundingClientRect());var d,e,f=this.window.innerWidth,g=this.getToolbarElement(),h=g.offsetHeight,i=g.offsetWidth,j=i/2,k=50,l=this.diffLeft-j,m=this.getEditorOption("elementsContainer"),n=["absolute","fixed"].indexOf(window.getComputedStyle(m).getPropertyValue("position"))>-1,o={},p={};n?(e=m.getBoundingClientRect(),["top","left"].forEach(function(a){p[a]=c[a]-e[a]}),p.width=c.width,p.height=c.height,c=p,f=e.width,o.top=m.scrollTop):o.top=this.window.pageYOffset,d=c.left+c.width/2,o.top+=c.top-h,c.topd?(o.left=l+j,o.right="initial"):j>f-d?(o.left="auto",o.right=0):(o.left=l+d,o.right="initial"),["top","left","right"].forEach(function(a){g.style[a]=o[a]+(isNaN(o[a])?"":"px")})}});a.extensions.toolbar=b}(),function(){var b=a.Extension.extend({init:function(){a.Extension.prototype.init.apply(this,arguments),this.subscribe("editableDrag",this.handleDrag.bind(this)),this.subscribe("editableDrop",this.handleDrop.bind(this))},handleDrag:function(a){var b="medium-editor-dragover";a.preventDefault(),a.dataTransfer.dropEffect="copy","dragover"===a.type?a.target.classList.add(b):"dragleave"===a.type&&a.target.classList.remove(b)},handleDrop:function(b){var c,d="medium-editor-dragover";b.preventDefault(),b.stopPropagation(),b.dataTransfer.files&&(c=Array.prototype.slice.call(b.dataTransfer.files,0),c.some(function(b){if(b.type.match("image")){var c,d;c=new FileReader,c.readAsDataURL(b),d="medium-img-"+ +new Date,a.util.insertHTMLCommand(this.document,''),c.onload=function(){var a=this.document.getElementById(d);a&&(a.removeAttribute("id"),a.removeAttribute("class"),a.src=c.result)}.bind(this)}}.bind(this))),b.target.classList.remove(d)}});a.extensions.imageDragging=b}(),function(){function b(b){var c=a.selection.getSelectionStart(this.options.ownerDocument),d=c.textContent,e=a.selection.getCaretOffsets(c);(void 0===d[e.left-1]||""===d[e.left-1].trim()||void 0!==d[e.left]&&""===d[e.left].trim())&&b.preventDefault()}function c(b,c){if(this.options.disableReturn||c.getAttribute("data-disable-return"))b.preventDefault();else if(this.options.disableDoubleReturn||c.getAttribute("data-disable-double-return")){var d=a.selection.getSelectionStart(this.options.ownerDocument);(d&&""===d.textContent.trim()&&"li"!==d.nodeName.toLowerCase()||d.previousElementSibling&&"br"!==d.previousElementSibling.nodeName.toLowerCase()&&""===d.previousElementSibling.textContent.trim())&&b.preventDefault()}}function d(b){var c=a.selection.getSelectionStart(this.options.ownerDocument),d=c&&c.nodeName.toLowerCase();"pre"===d&&(b.preventDefault(),a.util.insertHTMLCommand(this.options.ownerDocument," ")),a.util.isListItem(c)&&(b.preventDefault(),b.shiftKey?this.options.ownerDocument.execCommand("outdent",!1,null):this.options.ownerDocument.execCommand("indent",!1,null))}function e(b){var c,d=a.selection.getSelectionStart(this.options.ownerDocument),e=d.nodeName.toLowerCase(),f=/^(\s+|)?$/i,g=/h\d/i;a.util.isKey(b,[a.util.keyCode.BACKSPACE,a.util.keyCode.ENTER])&&d.previousElementSibling&&g.test(e)&&0===a.selection.getCaretOffsets(d).left?a.util.isKey(b,a.util.keyCode.BACKSPACE)&&f.test(d.previousElementSibling.innerHTML)?(d.previousElementSibling.parentNode.removeChild(d.previousElementSibling),b.preventDefault()):!this.options.disableDoubleReturn&&a.util.isKey(b,a.util.keyCode.ENTER)&&(c=this.options.ownerDocument.createElement("p"),c.innerHTML="
",d.previousElementSibling.parentNode.insertBefore(c,d),b.preventDefault()):a.util.isKey(b,a.util.keyCode.DELETE)&&d.nextElementSibling&&d.previousElementSibling&&!g.test(e)&&f.test(d.innerHTML)&&g.test(d.nextElementSibling.nodeName.toLowerCase())?(a.selection.moveCursor(this.options.ownerDocument,d.nextElementSibling),d.previousElementSibling.parentNode.removeChild(d),b.preventDefault()):a.util.isKey(b,a.util.keyCode.BACKSPACE)&&"li"===e&&f.test(d.innerHTML)&&!d.previousElementSibling&&!d.parentElement.previousElementSibling&&d.nextElementSibling&&"li"===d.nextElementSibling.nodeName.toLowerCase()?(c=this.options.ownerDocument.createElement("p"),c.innerHTML="
",d.parentElement.parentElement.insertBefore(c,d.parentElement),a.selection.moveCursor(this.options.ownerDocument,c),d.parentElement.removeChild(d),b.preventDefault()):a.util.isKey(b,a.util.keyCode.BACKSPACE)&&a.util.getClosestTag(d,"blockquote")!==!1&&0===a.selection.getCaretOffsets(d).left?(b.preventDefault(),a.util.execFormatBlock(this.options.ownerDocument,"p")):a.util.isKey(b,a.util.keyCode.ENTER)&&a.util.getClosestTag(d,"blockquote")!==!1&&0===a.selection.getCaretOffsets(d).right?(c=this.options.ownerDocument.createElement("p"),c.innerHTML="
",d.parentElement.insertBefore(c,d.nextSibling),a.selection.moveCursor(this.options.ownerDocument,c),b.preventDefault()):a.util.isKey(b,a.util.keyCode.BACKSPACE)&&a.util.isMediumEditorElement(d.parentElement)&&!d.previousElementSibling&&d.nextElementSibling&&f.test(d.innerHTML)&&(b.preventDefault(),a.selection.moveCursor(this.options.ownerDocument,d.nextSibling),d.parentElement.removeChild(d))}function f(b){var c,d=a.selection.getSelectionStart(this.options.ownerDocument);d&&(a.util.isMediumEditorElement(d)&&0===d.children.length&&!a.util.isBlockContainer(d)&&this.options.ownerDocument.execCommand("formatBlock",!1,"p"),!a.util.isKey(b,a.util.keyCode.ENTER)||a.util.isListItem(d)||a.util.isBlockContainer(d)||(c=d.nodeName.toLowerCase(),"a"===c?this.options.ownerDocument.execCommand("unlink",!1,null):b.shiftKey||b.ctrlKey||this.options.ownerDocument.execCommand("formatBlock",!1,"p")))}function g(a,b){var c=b.parentNode.querySelector('textarea[medium-editor-textarea-id="'+b.getAttribute("medium-editor-textarea-id")+'"]');c&&(c.value=b.innerHTML.trim())}function h(a){a._mediumEditors||(a._mediumEditors=[null]),this.id||(this.id=a._mediumEditors.length),a._mediumEditors[this.id]=this}function i(a){a._mediumEditors&&a._mediumEditors[this.id]&&(a._mediumEditors[this.id]=null)}function j(b,c,d){var e=[];if(b||(b=[]),"string"==typeof b&&(b=c.querySelectorAll(b)),a.util.isElement(b)&&(b=[b]),d)for(var f=0;ff;f++)b.hasAttribute(e[f].nodeName)||b.setAttribute(e[f].nodeName,e[f].value);return a.form&&this.on(a.form,"reset",function(a){a.defaultPrevented||this.resetContent(this.options.ownerDocument.getElementById(d))}.bind(this)),a.classList.add("medium-editor-hidden"),a.parentNode.insertBefore(b,a),b}function v(b,d){if(!b.getAttribute("data-medium-editor-element")){"textarea"===b.nodeName.toLowerCase()&&(b=u.call(this,b),this.instanceHandleEditableInput||(this.instanceHandleEditableInput=g.bind(this),this.subscribe("editableInput",this.instanceHandleEditableInput))),this.options.disableEditing||b.getAttribute("data-disable-editing")||(b.setAttribute("contentEditable",!0),b.setAttribute("spellcheck",this.options.spellcheck)),this.instanceHandleEditableKeydownEnter||(b.getAttribute("data-disable-return")||b.getAttribute("data-disable-double-return"))&&(this.instanceHandleEditableKeydownEnter=c.bind(this),this.subscribe("editableKeydownEnter",this.instanceHandleEditableKeydownEnter)),this.options.disableReturn||b.getAttribute("data-disable-return")||this.on(b,"keyup",f.bind(this));var e=a.util.guid();b.setAttribute("data-medium-editor-element",!0),b.classList.add("medium-editor-element"),b.setAttribute("role","textbox"),b.setAttribute("aria-multiline",!0),b.setAttribute("data-medium-editor-editor-index",d),b.setAttribute("medium-editor-index",e),B[e]=b.innerHTML,this.events.attachAllEventsToElement(b)}return b}function w(){this.subscribe("editableKeydownTab",d.bind(this)),this.subscribe("editableKeydownDelete",e.bind(this)),this.subscribe("editableKeydownEnter",e.bind(this)),this.options.disableExtraSpaces&&this.subscribe("editableKeydownSpace",b.bind(this)),this.instanceHandleEditableKeydownEnter||(this.options.disableReturn||this.options.disableDoubleReturn)&&(this.instanceHandleEditableKeydownEnter=c.bind(this),this.subscribe("editableKeydownEnter",this.instanceHandleEditableKeydownEnter))}function x(){if(this.extensions=[],Object.keys(this.options.extensions).forEach(function(a){"toolbar"!==a&&this.options.extensions[a]&&this.extensions.push(m(this.options.extensions[a],a,this))},this),t.call(this)){var b=this.options.fileDragging;b||(b={},r.call(this)||(b.allowedTypes=[])),this.addBuiltInExtension("fileDragging",b)}var c={paste:!0,"anchor-preview":o.call(this),autoLink:q.call(this),keyboardCommands:s.call(this),placeholder:p.call(this)};Object.keys(c).forEach(function(a){c[a]&&this.addBuiltInExtension(a)},this);var d=this.options.extensions.toolbar;if(!d&&n.call(this)){var e=a.util.extend({},this.options.toolbar,{allowMultiParagraphSelection:this.options.allowMultiParagraphSelection});d=new a.extensions.toolbar(e)}d&&this.extensions.push(m(d,"toolbar",this))}function y(b,c){var d=[["allowMultiParagraphSelection","toolbar.allowMultiParagraphSelection"]];return c&&d.forEach(function(b){c.hasOwnProperty(b[0])&&void 0!==c[b[0]]&&a.util.deprecated(b[0],b[1],"v6.0.0")}),a.util.defaults({},c,b)}function z(b,c){var d,e,f=/^append-(.+)$/gi,g=/justify([A-Za-z]*)$/g;if(d=f.exec(b))return a.util.execFormatBlock(this.options.ownerDocument,d[1]);if("fontSize"===b)return c.size&&a.util.deprecated(".size option for fontSize command",".value","6.0.0"),e=c.value||c.size,this.options.ownerDocument.execCommand("fontSize",!1,e);if("fontName"===b)return c.name&&a.util.deprecated(".name option for fontName command",".value","6.0.0"),e=c.value||c.name,this.options.ownerDocument.execCommand("fontName",!1,e);if("createLink"===b)return this.createLink(c);if("image"===b){var h=this.options.contentWindow.getSelection().toString().trim();return this.options.ownerDocument.execCommand("insertImage",!1,h)}if("html"===b){var i=this.options.contentWindow.getSelection().toString().trim();return a.util.insertHTMLCommand(this.options.ownerDocument,i)}if(g.exec(b)){var j=this.options.ownerDocument.execCommand(b,!1,null),k=a.selection.getSelectedParentElement(a.selection.getSelectionRange(this.options.ownerDocument));return k&&A.call(this,a.util.getTopBlockContainer(k)),j}return e=c&&c.value,this.options.ownerDocument.execCommand(b,!1,e)}function A(b){if(b){var c,d=Array.prototype.slice.call(b.childNodes).filter(function(a){var b="div"===a.nodeName.toLowerCase();return b&&!c&&(c=a.style.textAlign),b});d.length&&(this.saveSelection(),d.forEach(function(b){if(b.style.textAlign===c){var d=b.lastChild;if(d){a.util.unwrap(b,this.options.ownerDocument);var e=this.options.ownerDocument.createElement("BR");d.parentNode.insertBefore(e,d.nextSibling)}}},this),b.style.textAlign=c,this.restoreSelection())}}var B={};a.prototype={init:function(a,b){return this.options=y.call(this,this.defaults,b),this.origElements=a,this.options.elementsContainer||(this.options.elementsContainer=this.options.ownerDocument.body),this.setup()},setup:function(){this.isActive||(h.call(this,this.options.contentWindow),this.events=new a.Events(this),this.elements=[],this.addElements(this.origElements),0!==this.elements.length&&(this.isActive=!0,x.call(this),w.call(this))); +},destroy:function(){this.isActive&&(this.isActive=!1,this.extensions.forEach(function(a){"function"==typeof a.destroy&&a.destroy()},this),this.events.destroy(),this.elements.forEach(function(a){this.options.spellcheck&&(a.innerHTML=a.innerHTML),a.removeAttribute("contentEditable"),a.removeAttribute("spellcheck"),a.removeAttribute("data-medium-editor-element"),a.classList.remove("medium-editor-element"),a.removeAttribute("role"),a.removeAttribute("aria-multiline"),a.removeAttribute("medium-editor-index"),a.removeAttribute("data-medium-editor-editor-index"),a.getAttribute("medium-editor-textarea-id")&&k(a)},this),this.elements=[],this.instanceHandleEditableKeydownEnter=null,this.instanceHandleEditableInput=null,i.call(this,this.options.contentWindow))},on:function(a,b,c,d){return this.events.attachDOMEvent(a,b,c,d),this},off:function(a,b,c,d){return this.events.detachDOMEvent(a,b,c,d),this},subscribe:function(a,b){return this.events.attachCustomEvent(a,b),this},unsubscribe:function(a,b){return this.events.detachCustomEvent(a,b),this},trigger:function(a,b,c){return this.events.triggerCustomEvent(a,b,c),this},delay:function(a){var b=this;return setTimeout(function(){b.isActive&&a()},this.options.delay)},serialize:function(){var a,b,c={},d=this.elements.length;for(a=0;d>a;a+=1)b=""!==this.elements[a].id?this.elements[a].id:"element-"+a,c[b]={value:this.elements[a].innerHTML.trim()};return c},getExtensionByName:function(a){var b;return this.extensions&&this.extensions.length&&this.extensions.some(function(c){return c.name===a?(b=c,!0):!1}),b},addBuiltInExtension:function(b,c){var d,e=this.getExtensionByName(b);if(e)return e;switch(b){case"anchor":d=a.util.extend({},this.options.anchor,c),e=new a.extensions.anchor(d);break;case"anchor-preview":e=new a.extensions.anchorPreview(this.options.anchorPreview);break;case"autoLink":e=new a.extensions.autoLink;break;case"fileDragging":e=new a.extensions.fileDragging(c);break;case"fontname":e=new a.extensions.fontName(this.options.fontName);break;case"fontsize":e=new a.extensions.fontSize(c);break;case"keyboardCommands":e=new a.extensions.keyboardCommands(this.options.keyboardCommands);break;case"paste":e=new a.extensions.paste(this.options.paste);break;case"placeholder":e=new a.extensions.placeholder(this.options.placeholder);break;default:a.extensions.button.isBuiltInButton(b)&&(c?(d=a.util.defaults({},c,a.extensions.button.prototype.defaults[b]),e=new a.extensions.button(d)):e=new a.extensions.button(b))}return e&&this.extensions.push(m(e,b,this)),e},stopSelectionUpdates:function(){this.preventSelectionUpdates=!0},startSelectionUpdates:function(){this.preventSelectionUpdates=!1},checkSelection:function(){var a=this.getExtensionByName("toolbar");return a&&a.checkState(),this},queryCommandState:function(a){var b,c=/^full-(.+)$/gi,d=null;b=c.exec(a),b&&(a=b[1]);try{d=this.options.ownerDocument.queryCommandState(a)}catch(e){d=null}return d},execAction:function(b,c){var d,e,f=/^full-(.+)$/gi;return d=f.exec(b),d?(this.saveSelection(),this.selectAllContents(),e=z.call(this,d[1],c),this.restoreSelection()):e=z.call(this,b,c),"insertunorderedlist"!==b&&"insertorderedlist"!==b||a.util.cleanListDOM(this.options.ownerDocument,this.getSelectedParentElement()),this.checkSelection(),e},getSelectedParentElement:function(b){return void 0===b&&(b=this.options.contentWindow.getSelection().getRangeAt(0)),a.selection.getSelectedParentElement(b)},selectAllContents:function(){var b=a.selection.getSelectionElement(this.options.contentWindow);if(b){for(;1===b.children.length;)b=b.children[0];this.selectElement(b)}},selectElement:function(b){a.selection.selectNode(b,this.options.ownerDocument);var c=a.selection.getSelectionElement(this.options.contentWindow);c&&this.events.focusElement(c)},getFocusedElement:function(){var a;return this.elements.some(function(b){return!a&&b.getAttribute("data-medium-focused")&&(a=b),!!a},this),a},exportSelection:function(){var b=a.selection.getSelectionElement(this.options.contentWindow),c=this.elements.indexOf(b),d=null;return c>=0&&(d=a.selection.exportSelection(b,this.options.ownerDocument)),null!==d&&0!==c&&(d.editableElementIndex=c),d},saveSelection:function(){this.selectionState=this.exportSelection()},importSelection:function(b,c){if(b){var d=this.elements[b.editableElementIndex||0];a.selection.importSelection(b,d,this.options.ownerDocument,c)}},restoreSelection:function(){this.importSelection(this.selectionState)},createLink:function(b){var c,d=a.selection.getSelectionElement(this.options.contentWindow),e={};if(-1!==this.elements.indexOf(d)){try{if(this.events.disableCustomEvent("editableInput"),b.url&&a.util.deprecated(".url option for createLink",".value","6.0.0"),c=b.url||b.value,c&&c.trim().length>0){var f=this.options.contentWindow.getSelection();if(f){var g,h,i,j,k=f.getRangeAt(0),l=k.commonAncestorContainer;if(3===k.endContainer.nodeType&&3!==k.startContainer.nodeType&&0===k.startOffset&&k.startContainer.firstChild===k.endContainer&&(l=k.endContainer),h=a.util.getClosestBlockContainer(k.startContainer),i=a.util.getClosestBlockContainer(k.endContainer),3!==l.nodeType&&0!==l.textContent.length&&h===i){var m=h||d,n=this.options.ownerDocument.createDocumentFragment();this.execAction("unlink"),g=this.exportSelection(),n.appendChild(m.cloneNode(!0)),d===m?a.selection.select(this.options.ownerDocument,m.firstChild,0,m.lastChild,3===m.lastChild.nodeType?m.lastChild.nodeValue.length:m.lastChild.childNodes.length):a.selection.select(this.options.ownerDocument,m,0,m,m.childNodes.length);var o=this.exportSelection();j=a.util.findOrCreateMatchingTextNodes(this.options.ownerDocument,n,{start:g.start-o.start,end:g.end-o.start,editableElementIndex:g.editableElementIndex}),0===j.length&&(n=this.options.ownerDocument.createDocumentFragment(),n.appendChild(l.cloneNode(!0)),j=[n.firstChild.firstChild,n.firstChild.lastChild]),a.util.createLink(this.options.ownerDocument,j,c.trim());var p=(n.firstChild.innerHTML.match(/^\s+/)||[""])[0].length;a.util.insertHTMLCommand(this.options.ownerDocument,n.firstChild.innerHTML.replace(/^\s+/,"")),g.start-=p,g.end-=p,this.importSelection(g)}else this.options.ownerDocument.execCommand("createLink",!1,c);this.options.targetBlank||"_blank"===b.target?a.util.setTargetBlank(a.selection.getSelectionStart(this.options.ownerDocument),c):a.util.removeTargetBlank(a.selection.getSelectionStart(this.options.ownerDocument),c),b.buttonClass&&a.util.addClassToAnchors(a.selection.getSelectionStart(this.options.ownerDocument),b.buttonClass)}}if(this.options.targetBlank||"_blank"===b.target||b.buttonClass){e=this.options.ownerDocument.createEvent("HTMLEvents"),e.initEvent("input",!0,!0,this.options.contentWindow);for(var q=0,r=this.elements.length;r>q;q+=1)this.elements[q].dispatchEvent(e)}}finally{this.events.enableCustomEvent("editableInput")}this.events.triggerCustomEvent("editableInput",e,d)}},cleanPaste:function(a){this.getExtensionByName("paste").cleanPaste(a)},pasteHTML:function(a,b){this.getExtensionByName("paste").pasteHTML(a,b)},setContent:function(a,b){if(b=b||0,this.elements[b]){var c=this.elements[b];c.innerHTML=a,this.checkContentChanged(c)}},getContent:function(a){return a=a||0,this.elements[a]?this.elements[a].innerHTML.trim():null},checkContentChanged:function(b){b=b||a.selection.getSelectionElement(this.options.contentWindow),this.events.updateInput(b,{target:b,currentTarget:b})},resetContent:function(a){if(a){var b=this.elements.indexOf(a);return void(-1!==b&&this.setContent(B[a.getAttribute("medium-editor-index")],b))}this.elements.forEach(function(a,b){this.setContent(B[a.getAttribute("medium-editor-index")],b)},this)},addElements:function(a){var b=j(a,this.options.ownerDocument,!0);return 0===b.length?!1:void b.forEach(function(a){a=v.call(this,a,this.id),this.elements.push(a),this.trigger("addElement",{target:a,currentTarget:a},a)},this)},removeElements:function(a){var b=j(a,this.options.ownerDocument),c=b.map(function(a){return a.getAttribute("medium-editor-textarea-id")&&a.parentNode?a.parentNode.querySelector('div[medium-editor-textarea-id="'+a.getAttribute("medium-editor-textarea-id")+'"]'):a});this.elements=this.elements.filter(function(a){return-1!==c.indexOf(a)?(this.events.cleanupElement(a),a.getAttribute("medium-editor-textarea-id")&&k(a),this.trigger("removeElement",{target:a,currentTarget:a},a),!1):!0},this)}},a.getEditorFromElement=function(a){var b=a.getAttribute("data-medium-editor-editor-index"),c=a&&a.ownerDocument&&(a.ownerDocument.defaultView||a.ownerDocument.parentWindow);return c&&c._mediumEditors&&c._mediumEditors[b]?c._mediumEditors[b]:null}}(),function(){a.prototype.defaults={activeButtonClass:"medium-editor-button-active",buttonLabels:!1,delay:0,disableReturn:!1,disableDoubleReturn:!1,disableExtraSpaces:!1,disableEditing:!1,autoLink:!1,elementsContainer:!1,contentWindow:window,ownerDocument:document,targetBlank:!1,extensions:{},spellcheck:!0}}(),a.parseVersionString=function(a){var b=a.split("-"),c=b[0].split("."),d=b.length>1?b[1]:"";return{major:parseInt(c[0],10),minor:parseInt(c[1],10),revision:parseInt(c[2],10),preRelease:d,toString:function(){return[c[0],c[1],c[2]].join(".")+(d?"-"+d:"")}}},a.version=a.parseVersionString.call(this,{version:"5.23.3"}.version),a}()); \ No newline at end of file diff --git a/bl-plugins/quill/languages/en.json b/bl-plugins/quill/languages/en.json new file mode 100644 index 00000000..036ea846 --- /dev/null +++ b/bl-plugins/quill/languages/en.json @@ -0,0 +1,7 @@ +{ + "plugin-data": + { + "name": "Quilljs", + "description": "" + } +} \ No newline at end of file diff --git a/bl-plugins/quill/metadata.json b/bl-plugins/quill/metadata.json new file mode 100644 index 00000000..d0206766 --- /dev/null +++ b/bl-plugins/quill/metadata.json @@ -0,0 +1,10 @@ +{ + "author": "Quilljs", + "email": "", + "website": "https://quilljs.com/", + "version": "1.3.6", + "releaseDate": "2018-03-12", + "license": "", + "compatible": "3.2", + "notes": "" +} \ No newline at end of file diff --git a/bl-plugins/quill/plugin.php b/bl-plugins/quill/plugin.php new file mode 100644 index 00000000..18947224 --- /dev/null +++ b/bl-plugins/quill/plugin.php @@ -0,0 +1,109 @@ +dbFields = array( + 'toolbar1'=>'formatselect bold italic bullist numlist | blockquote alignleft aligncenter alignright | link unlink pagebreak image removeformat code', + 'toolbar2'=>'', + 'plugins'=>'code autolink image link pagebreak advlist lists textcolor colorpicker textpattern' + ); + } + + public function form() + { + global $L; + + $html = '
'; + $html .= ''; + $html .= ''; + $html .= '
'; + + $html .= '
'; + $html .= ''; + $html .= ''; + $html .= '
'; + + $html .= '
'; + $html .= ''; + $html .= ''; + $html .= '
'; + + return $html; + } + + public function adminHead() + { + if (!in_array($GLOBALS['ADMIN_CONTROLLER'], $this->loadOnController)) { + return false; + } + + $html = ''; + $html .= ''; + + return $html; + } + + public function adminBodyEnd() + { + if (!in_array($GLOBALS['ADMIN_CONTROLLER'], $this->loadOnController)) { + return false; + } + + $mediumJavascript = $this->htmlPath().'js/medium-editor.min.js'; + +$script = << + + +EOF; + return $script; + } + +} \ No newline at end of file diff --git a/bl-plugins/quill/quill-1.3.6.zip b/bl-plugins/quill/quill-1.3.6.zip new file mode 100644 index 00000000..a04182a5 Binary files /dev/null and b/bl-plugins/quill/quill-1.3.6.zip differ diff --git a/bl-plugins/quill/quill-1.3.6/CHANGELOG.md b/bl-plugins/quill/quill-1.3.6/CHANGELOG.md new file mode 100755 index 00000000..31ae3f30 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/CHANGELOG.md @@ -0,0 +1,734 @@ +# 1.3.6 + +- Make picker accessible [#1999](https://github.com/quilljs/quill/pull/1999) +- Fix Japanese composition in Chrome 65 [#2009](https://github.com/quilljs/quill/issues/2009) + +Thanks to [@berylw](https://github.com/berylw) and [@erinsinger93](https://github.com/erinsinger93) for contributions to this release! + + +# 1.3.5 + +- Fix indent preservation of a checked checklist item [#1818](https://github.com/quilljs/quill/issues/1818) +- * added as a shortcut to trigger bullet list formatting [#1819](https://github.com/quilljs/quill/pull/1819) +- Fix pasting text-align styles [#1873](https://github.com/quilljs/quill/issues/1873) +- Fix cursor position after dangerouslyPasteHTML [#1886](https://github.com/quilljs/quill/issues/1886) +- Fix value of history stack in text-change handler [#1906](https://github.com/quilljs/quill/pull/1906) +- Workaround for Webkit locking up when navigating around images using hotkeys [#1910](https://github.com/quilljs/quill/issues/1910) + +Thank you [@araruna](https://github.com/araruna), [@bryanrsmith](https://github.com/bryanrsmith), [@haugstrup](https://github.com/haugstrup), [@icylace](https://github.com/icylace), [@leimig](https://github.com/leimig), [@LFDM](https://github.com/LFDM), [@nikparo](https://github.com/nikparo), [@rafpaf](https://github.com/rafpaf) and [@vk2sky](https://github.com/vk2sky) for your contributions to this release. + + +# 1.3.4 + +- Loosen dependency specification [#1748](https://github.com/quilljs/quill/issues/1748) +- Loosen list autofill constraint [#1749](https://github.com/quilljs/quill/issues/1749) + +Thanks to [@danfuzz](https://github.com/danfuzz) and [@SoftVision-CarmenFat](https://github.com/SoftVision-CarmenFat) for contributions to this release! + + +# 1.3.3 + +- Fix `getFormat` with no parameters while editor is not focused [#1548](https://github.com/quilljs/quill/issues/1548) +- Remove automatic highlighting across embeds [#1691](https://github.com/quilljs/quill/issues/1691) +- Support checking checklist on mobile [#1693](https://github.com/quilljs/quill/pull/1711) +- Fix list creation keyboard shortcuts [#1723](https://github.com/quilljs/quill/issues/1723) +- Show KaTex rendering errors [#1738](https://github.com/quilljs/quill/pull/1738) + + +Thank you [@altschuler](https://github.com/altschuler), [@arrocke](https://github.com/arrocke), [@guillaumepotier](https://github.com/guillaumepotier), [@sferoze](https://github.com/sferoze) and [@volser](https://github.com/volser) for your contributions to this release. + + +# 1.3.2 + +- Pasting into code block should always paste as code [#1624](https://github.com/quilljs/quill/issues/1624) +- Fix removing embed selection when arrow keys change selection [#1633](https://github.com/quilljs/quill/issues/1633) +- Fix selection restoration after image insertion [#1649](https://github.com/quilljs/quill/issues/1649) +- Fix selection-change firing after dragging off screen [#1654](https://github.com/quilljs/quill/issues/1654) +- Fix placeholder text spacing [#1677](https://github.com/quilljs/quill/issues/1677) + +Thanks to [@abramz](https://github.com/abramz), [@amitm02](https://github.com/amitm02), [@eamodio](https://github.com/eamodio), [@HWliao](https://github.com/HWliao), [@mmitis](https://github.com/mmitis), [@nelsonpecora](https://github.com/nelsonpecora), [@nipunjain87](https://github.com/nipunjain87), and [@ValueBerry](https://github.com/ValueBerry) for contributions to this release! + + +# 1.3.1 + +- Fix placeholder when emptying text [#1594](https://github.com/quilljs/quill/issues/1594) +- Fix inserting newline after header [#1616](https://github.com/quilljs/quill/issues/1616) + +Thank you [@Natim](https://github.com/Natim) and [@stephenLYao](https://github.com/stephenLYao) for your contributions to this release. + + +# 1.3.0 + +Add `matchVisual` [configuration](https://quilljs.com/docs/modules/clipboard/#configuration) to Clipboard. + +- Use DOM API to determine selected `` without themes [#997](https://github.com/quilljs/quill/issues/997) +- Link `code` icon to `code-block` [#998](https://github.com/quilljs/quill/issues/998) +- Fix undo stack when at size limit [#1001](https://github.com/quilljs/quill/pull/1001) +- Fix bug where `formatLine` did not ignore inline formats [8a7190](https://github.com/quilljs/parchment/commit/8a71905b2dd02d003edb02a15fdc727b26914e49) + +Thanks to [@dropfen](https://github.com/dropfen), [@evansolomon](https://github.com/evansolomon), [@hallaathrad](https://github.com/hallaathrad), [@janyksteenbeek](https://github.com/janyksteenbeek), [@jackmu95](https://github.com/jackmu95), [@marktron](https://github.com/marktron), [@mcat-ee](https://github.com/mcat-ee), [@unhammer](https://github.com/unhammer), and [@zeke](https://github.com/zeke) for contributions to this release! + + +# 1.0.5 + +Became 1.0.6 with a build/deploy fix. + + +# 1.0.4 + +- Fix bubble theme defaults [#963](https://github.com/quilljs/quill/issues/963) +- Fix browsers modifying inline nesting order [#971](https://github.com/quilljs/quill/issues/971) +- Do not fire selection-change event on paste [#974](https://github.com/quilljs/quill/issues/974) +- Support alt attribute in images [#975](https://github.com/quilljs/quill/issues/975) +- Deprecate `pasteHTML` for removal in Quill 2.0 [#981](https://github.com/quilljs/quill/issues/981) + +Thank you [jackmu95](https://github.com/jackmu95), [kristeehan](https://github.com/kristeehan), [ruffle1986](https://github.com/ruffle1986), [sergop321](https://github.com/sergop321), [sferoze](https://github.com/sferoze), and [sijad](https://github.com/sijad) for contributions to this release. + + +# 1.0.3 + +- Fix [#928](https://github.com/quilljs/quill/issues/928) + +Thank you [@scottmessinger](https://github.com/scottmessinger) for the bug report. + + +# 1.0.2 + +- Fix building quill.core.js [docs #11](https://github.com/quilljs/quilljs.github.io/issues/11) +- Fix regression of [#793](https://github.com/quilljs/quill/issues/793) + +Thanks to [@eamodio](https://github.com/eamodio) and [@neandrake](https://github.com/neandrake) for their contributions to this release. + + +# 1.0.0 + +Quill 1.0 is released! Read the [official announcement](https://quilljs.com/blog/announcing-quill-1-0/). + + +# 1.0.0-rc.4 + +Fix one important bug [fdd920](https://github.com/quilljs/quill/commit/fdd920250c05403ed9e5d6d86826a00167ba0b09) + + +# 1.0.0-rc.3 + +A few bug fixes, one with with possibly significant implications. See the [issue #889](https://github.com/quilljs/quill/issues/889) and [commit fix](https://github.com/quilljs/quill/commit/be24c62a6234818548658fcb5e1935a0c07b4eb7) for more details. + +### Bug Fixes + +- Fix indenting beyond first level with toolbar [#882](https://github.com/quilljs/quill/issues/882) +- Fix toolbar font/size display on Safari [#884](https://github.com/quilljs/quill/issues/884) +- Fix pasting from Gmail from on different browser [#886](https://github.com/quilljs/quill/issues/886) +- Fix undo/redo consistency [#889](https://github.com/quilljs/quill/issues/889) +- Fix null error when selecting all on Firefox [#891](https://github.com/quilljs/quill/issues/891) +- Fix merging keyboard options twice [#897](https://github.com/quilljs/quill/issues/897) + +Thank you [@benbro](https://github.com/benbro), [@cgilboy](https://github.com/cgilboy), [@cutteroid](https://github.com/cutteroid), and [@routman](https://github.com/routman) for contributions to this release! + + +# 1.0.0-rc.2 + +A few bug fixes, including one significant [one](https://github.com/quilljs/quill/issues/883) + +### Bug Fixes + +- Fix icon picker rendering in MS Edge [#877](https://github.com/quilljs/quill/issues/877) +- Add back minified build to release [#881](https://github.com/quilljs/quill/issues/881) +- Fix optimized change calculation with preformatted text [#883](https://github.com/quilljs/quill/issues/883) + +Thanks to [benbro](https://github.com/benbro), [cutteroid](https://github.com/cutteroid), and [CapTec](https://github.com/CapTec) for their contributions to this release. + + +# 1.0.0-rc.1 + +A few bug fixes and performance improvements. + +### Features + +- Source maps now available from CDN for minified build + +### Bug Fixes + +- Fix scroll interaction between two Quill editors [#855](https://github.com/quilljs/quill/issues/855) +- Fix scroll on paste [#856](https://github.com/quilljs/quill/issues/856) +- Fix native iOS tooltip formatting [#862](https://github.com/quilljs/quill/issues/862) +- Remove comments from pasting from Word [#872](https://github.com/quilljs/quill/issues/872) +- Fix indent at all supported indent levels [#873](https://github.com/quilljs/quill/issues/873) +- Fix indent interaction with text direction [#874](https://github.com/quilljs/quill/issues/874) + +Thank you [@benbro](https://github.com/benbro), [@fernandogmar](https://github.com/fernandogmar), [@sachinrekhi](https://github.com/sachinrekhi), [@sferoze](https://github.com/sferoze), and [@stalniy](https://github.com/stalniy) for contributions to this release! + + +# 1.0.0-rc.0 + +Take a look at [Quill 1.0 Release Candidate](https://quilljs.com/blog/quill-1-0-release-candidate-released/) for more details. + +### Updates + +- Going forward the minimal stylesheet build will be named quill.core.css, instead of quill.css + +### Bug Fixes + +- Fix identifying ordered and bulletd lists [#846](https://github.com/quilljs/quill/issues/846) [#847](https://github.com/quilljs/quill/issues/847) +- Fix bullet interaction with text direction [#848](https://github.com/quilljs/quill/issues/848) + +A huge thank you to all contributors to through the beta! Special thanks goes to [@benbro](https://github.com/benbro) and [@sachinrekhi](https://github.com/sachinrekhi) who together submitted submitted almost 50 Issues and Pull Requests! + +- [@abejdaniels](https://github.com/abejdaniels) +- [@anovi](https://github.com/anovi) +- [@benbro](https://github.com/benbro) +- [@bram2w](https://github.com/bram2w) +- [@brynjagr](https://github.com/brynjagr) +- [@CapTec](https://github.com/CapTec) +- [@Cinamonas](https://github.com/Cinamonas) +- [@clemmy](https://github.com/clemmy) +- [@crisbeto](https://github.com/crisbeto) +- [@cutteroid](https://github.com/cutteroid) +- [@DadaMonad](https://github.com/DadaMonad) +- [@davelozier](https://github.com/davelozier) +- [@emanuelbsilva](https://github.com/emanuelbsilva) +- [@ersommer](https://github.com/ersommer) +- [@fernandogmar](https://github.com/fernandogmar) +- [@george-norris-salesforce](https://github.com/george-norris-salesforce) +- [@jackmu95](https://github.com/jackmu95) +- [@jasonmng](https://github.com/jasonmng) +- [@jbrowning](https://github.com/jbrowning) +- [@jonnolen](https://github.com/jonnolen) +- [@KameSama](https://github.com/KameSama) +- [@kei-ito](https://github.com/kei-ito) +- [@kylebragger](https://github.com/kylebragger) +- [@LucVanPelt](https://github.com/LucVanPelt) +- [@lukechapman](https://github.com/lukechapman) +- [@micimize](https://github.com/micimize) +- [@mmorearty](https://github.com/mmorearty) +- [@mshamaiev-intel471](https://github.com/mshamaiev-intel471) +- [@quentez](https://github.com/quentez) +- [@sachinrekhi](https://github.com/sachinrekhi) +- [@sagacitysite](https://github.com/sagacitysite) +- [@saw](https://github.com/saw) +- [@stalniy](https://github.com/stalniy) +- [@tOgg1](https://github.com/tOgg1) +- [@u9520107](https://github.com/u9520107) +- [@WriterStat](https://github.com/WriterStat) + + +# 1.0.0-beta.11 + +Fixed some regressive bugs from previous release. + +### Bug Fixes + +- Fix activating more than one format before typing [#841](https://github.com/quilljs/quill/issues/841) +- Run default matchers before before user defined ones [#843](https://github.com/quilljs/quill/issues/843) +- Fix merging theme configurations [#844](https://github.com/quilljs/quill/issues/844), [#845](845) + +Thanks [benbro](https://github.com/benbro), [jackmu95](https://github.com/jackmu95), and [george-norris-salesforce](https://github.com/george-norris-salesforce) for the bug reports. + + +# 1.0.0-beta.10 + +Lots of bug fixes and performance improvements. + +### Breaking Changes + +- Keyboard handler format in initial [configuration](beta.quilljs.com/docs/modules/keyboard/) has changed. `addBinding` is overloaded to be backwards compatible. + +### Bug Fixes + +- Preserve last bullet on paste [#696](https://github.com/quilljs/quill/issues/696) +- Fix getBounds calculation for lists [#765](https://github.com/quilljs/quill/issues/765) +- Escape quotes in font value [#769](https://github.com/quilljs/quill/issues/769) +- Fix spacing calculation on paste [#797](https://github.com/quilljs/quill/issues/797) +- Fix Snow tooltip label [#798](https://github.com/quilljs/quill/issues/798) +- Fix link tooltip showing up on long click [#799](https://github.com/quilljs/quill/issues/799) +- Fix entering code block in IE and Firefox [#803](https://github.com/quilljs/quill/issues/803) +- Fix opening image dialog on Firefox [#805](https://github.com/quilljs/quill/issues/805) +- Fix focus loss on updateContents [#809](https://github.com/quilljs/quill/issues/809) +- Reset toolbar of blur [#810](https://github.com/quilljs/quill/issues/810) +- Fix cursor position calculation on delete [#811](https://github.com/quilljs/quill/issues/811) +- Fix highlighting across different alignment values [#815](https://github.com/quilljs/quill/issues/815) +- Allow default active button [#816](https://github.com/quilljs/quill/issues/816) +- Fix deleting last character of formatted text on Firefox [#824](https://github.com/quilljs/quill/issues/824) +- Fix Youtube regex [#826](https://github.com/quilljs/quill/pull/826) +- Fix missing imports when Quill not global [#836](https://github.com/quilljs/quill/pull/836) + +Thanks to [benbro](https://github.com/benbro), [clemmy](https://github.com/clemmy), [crisbeto](https://github.com/crisbeto), [cutteroid](https://github.com/cutteroid), [jackmu95](https://github.com/jackmu95), [kylebragger](https://github.com/kylebragger), [sachinrekhi](https://github.com/sachinrekhi), [stalniy](https://github.com/stalniy), and [tOgg1](https://github.com/tOgg1) for their contributions to this release. + + +# 1.0.0-beta.9 + +Potentially the final beta before a release candidate, if no major issues are discovered. + +### Breaking Changes + +- No longer expose `ui/link-tooltip` through `import` as implementation is now Snow specific +- Significant refactoring of `ui/tooltip` +- Syntax module now autodetects language, instead of defaulting to Javascript + +### Features + +- Formula and video insertion UI added to Snow and Bubble themes + +### Bug Fixes + +- Fix toolbar active state after backspacing to previous line [#730](https://github.com/quilljs/quill/issues/730) +- User selection is now preserved various API calls [#731](https://github.com/quilljs/quill/issues/731) +- Fix long click on link-tooltip [#747](https://github.com/quilljs/quill/issues/747) +- Fix ordered list and text-align right interaction [#784](https://github.com/quilljs/quill/issues/784) +- Fix toggling code block off [#789](https://github.com/quilljs/quill/issues/789) +- Scroll position is now automatically preserved between editor blur and focus + +Thank you [@benbro](https://github.com/benbro), [@KameSama](https://github.com/KameSama), and [@sachinrekhi](https://github.com/sachinrekhi) for contributions to this release! + + +# 1.0.0-beta.8 + +Weekly beta preview release. The editor is almost ready for release candidacy but a couple cycles will be spent on the Snow and Bubble interfaces. + +### Work in Progress + +Image insertion is being reworked in the provided Snow and Bubble themes. The old image-tooltip has been removed in favor of a simpler and native interaction. By default clicking the image icon on the toolbar will open the OS file picker to convert and that into a base64 image. This will allow for a more natural hook to upload to a remote server instead. Some changes to the link tooltip is also being made to accommodate formula and video insertion, currently only available through the API. + +### Breaking Changes + +- Image tooltip UI has been removed, see above +- Code blocks now use a single `
` tag, instead of one per line [#723](https://github.com/quilljs/quill/issues/723)
+
+### Bug Fixes
+
+- Fix multiline syntax highlighting [#723](https://github.com/quilljs/quill/issues/723)
+- Keep pickers open on api text-change [#734](https://github.com/quilljs/quill/issues/734)
+- Emit correct source for text-change [#760](https://github.com/quilljs/quill/issues/760)
+- Emit correct parameters in selection-change [#762](https://github.com/quilljs/quill/issues/762)
+- Fix error redoing line insertion [#767](https://github.com/quilljs/quill/issues/767)
+- Better emitted Deltas for text-change [#768](https://github.com/quilljs/quill/issues/768)
+- Better Array.prototype.find polyfill for IE11 [#776](https://github.com/quilljs/quill/issues/776)
+- Fix Parchment errors in replacing text [#779](https://github.com/quilljs/quill/issues/779) [#783](https://github.com/quilljs/quill/issues/783)
+- Fix align button active state [#780](https://github.com/quilljs/quill/issues/780)
+- Fix format text on falsy value [#782](https://github.com/quilljs/quill/issues/782)
+- Use native cut [#785](https://github.com/quilljs/quill/issues/785)
+- Fix initializing document where last line is formatted [#786](https://github.com/quilljs/quill/issues/786)
+
+Thanks to [benbro](https://github.com/benbro), [bram2w](https://github.com/bram2w), [clemmy](https://github.com/clemmy), [DadaMonad](https://github.com/DadaMonad), [ersommer](https://github.com/ersommer), [michaeljosephrosenthal](https://github.com/michaeljosephrosenthal), [mmorearty](https://github.com/mmorearty), [mshamaiev-intel471](https://github.com/mshamaiev-intel471), and [sachinrekhi](https://github.com/sachinrekhi) for their contributions to this release.
+
+
+# 1.0.0-beta.7
+
+Became 1.0.0-beta.8 with a fix.
+
+
+# 1.0.0-beta.6
+
+Weekly beta preview release.
+
+### Features
+
+- Pickers can now be used and is styled in Bubble theme
+
+### Bug Fixes
+
+- Fix editing within formula [#702](https://github.com/quilljs/quill/issues/702)
+- Fix adding new line when deleting across lists [#741](https://github.com/quilljs/quill/issues/741)
+- Fix placeholder when default block tag is changed [#743](https://github.com/quilljs/quill/issues/743)
+- Keep Bubble tooltip open on format [#744](https://github.com/quilljs/quill/issues/744)
+- Fix format loss when copying from Quill [#748](https://github.com/quilljs/quill/issues/748) [#750](https://github.com/quilljs/quill/issues/750)
+- Break long lines in Firefox [#751](https://github.com/quilljs/quill/issues/751)
+- Fix cursor position being off after formatting and typing quickly [#752](https://github.com/quilljs/quill/issues/752)
+- Remove image resizing handles on Firefox [#753](https://github.com/quilljs/quill/issues/753)
+- Fix removing blockquote on initialization [#754](https://github.com/quilljs/quill/issues/754)
+- Fix adding blank lines on initialization [#756](https://github.com/quilljs/quill/issues/756)
+
+Thank you [abejdaniels](https://github.com/abejdaniels), [benbro](https://github.com/benbro), [davelozier](https://github.com/davelozier), [fernandogmar](https://github.com/fernandogmar), [KameSama](https://github.com/KameSama), and [WriterStat](https://github.com/WriterStat) for contributions to this release.
+
+
+# 1.0.0-beta.5
+
+Weekly beta preview release.
+
+### Features
+
+- Add blur() [#726](https://github.com/quilljs/quill/pull/726)
+
+### Bug Fixes
+
+- Fix null error [#728](https://github.com/quilljs/quill/issues/728)
+- Fix building with Node v6 [#732](https://github.com/quilljs/quill/issues/732)
+- Ensure button type for supplied buttons [#733](https://github.com/quilljs/quill/issues/733)
+- Fix line break pasting on Firefox [#735](https://github.com/quilljs/quill/issues/735)
+- Fix 'user' source on API calls [#739](https://github.com/quilljs/quill/issues/739)
+
+Thanks to [benbro](https://github.com/benbro), [lukechapman](https://github.com/lukechapman), [sachinrekhi](https://github.com/sachinrekhi), and [saw](https://github.com/saw) for their contributions to this release.
+
+
+# 1.0.0-beta.4
+
+Weekly beta preview release.
+
+### Breaking Changes
+
+- Headers no longer generates id attribute [#700](https://github.com/quilljs/quill/issues/700)
+- Add Control+Y hotkey on Windows [#705](https://github.com/quilljs/quill/issues/705)
+- BlockEmbed Blots are now length 1 and represented in a Delta the same as an inline embed
+  - value() used to return object and newline, newline is now removed
+  - formats used to be attributed on the newline character, it is now attributed on the object
+
+### Features
+
+- Enter on empty and indented list removes indent [#707](https://github.com/quilljs/quill/issues/707)
+- Allow base64 images to be inserted via APIs [#721](https://github.com/quilljs/quill/issues/721)
+
+### Bug Fixes
+
+- Fix typing after clearing inline format [#703](https://github.com/quilljs/quill/issues/703)
+- Correctly position Bubble tooltip when selecting multiple lines [#706](https://github.com/quilljs/quill/issues/706)
+- Fix typing after link format [#708](https://github.com/quilljs/quill/issues/708)
+- Fix loss of selection on using link tooltip [#709](https://github.com/quilljs/quill/issues/709)
+- Fix `setSelection(null)` [#722](https://github.com/quilljs/quill/issues/722)
+
+Thank you [@benbro](https://github.com/benbro), [@brynjagr](https://github.com/brynjagr), and [@sachinrekhi](https://github.com/sachinrekhi) for contributions to this release.
+
+
+# 1.0.0-beta.3
+
+Weekly beta preview release.
+
+### Breaking Changes
+
+- Keyboard was incorrectly using `metaKey` to refer to the control key on Windows. It now correctly refers to the Window key and `shortKey` has been added to refer the common platform specific modifier for hotkeys (metaKey for Mac, ctrlKey for Windows/Linux)
+- Formula is now a module, since it uses KaTeX
+
+### Features
+
+- Picker now uses text from original `
+
+
+
diff --git a/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-08-12-an-official-cdn-for-quill.md b/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-08-12-an-official-cdn-for-quill.md
new file mode 100755
index 00000000..18eed943
--- /dev/null
+++ b/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-08-12-an-official-cdn-for-quill.md
@@ -0,0 +1,20 @@
+---
+layout: post
+permalink: /blog/an-official-cdn-for-quill/
+title: An Offical CDN for Quill
+---
+
+Quill now has an offical Content Distribution Network so you can have access to a reliable, high-speed host for the library. To include a file:
+
+```html
+
+```
+```html
+
+```
+
+You can also use "latest" as the version:
+
+```html
+
+```
diff --git a/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-08-14-building-a-custom-module.md b/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-08-14-building-a-custom-module.md
new file mode 100755
index 00000000..fc719884
--- /dev/null
+++ b/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-08-14-building-a-custom-module.md
@@ -0,0 +1,154 @@
+---
+layout: post
+permalink: /blog/building-a-custom-module/
+---
+
+*Note: An updated guide for 1.0 and ES6 is available [here](/guides/building-a-custom-module/).*
+
+Quill's core strength as an editor is its rich API and powerful customization capabilities. One of the best ways to customize Quill is with a module. A module is a simple way to augment Quill's functionality. For the purpose of this guide, we will walk through one way to build a word counter module, a commonly found feature in many word processors.
+
+### Counting Words
+
+At its core a word counter simply counts the number of words in the editor and displays this value in some UI. Thus we need to:
+
+1. Listen on text changes in Quill.
+1. Count the number of words.
+1. Display this value.
+
+Let's jump straight in with a complete example!
+
+
+
+

+// Implement and register module
+Quill.registerModule('counter', function(quill, options) {
+  var container = document.querySelector('#counter');
+  quill.on('text-change', function() {
+    var text = quill.getText();
+    // There are a couple issues with counting
+    // this way but we'll fix this later
+    container.innerHTML = text.split(/\s+/).length;
+  });
+});
+
+// We can now initialize Quill with something like this:
+var quill = new Quill('#editor', {
+  modules: {
+    counter: true
+  }
+});
+
+ +That's all it takes to add a custom module to Quill! A function can be [registered](/docs/api/#quillregistermodule/) as a module and it will be passed the corresponding Quill editor object along with any options. + +### Using Options + +Modules are passed an options object that can be used to fine tune the desired behavior. We can use this to accept a selector for the counter container instead of a hard-coded string. Let's also customize the counter to either count words or characters: + +

+Quill.registerModule('counter', function(quill, options) {
+  var container = document.querySelector(options.container);
+  quill.on('text-change', function() {
+    var text = quill.getText();
+    if (options.unit === 'word') {
+      container.innerHTML = text.split(/\s+/).length + ' words';
+    } else {
+      container.innerHTML = text.length + ' characters';
+    }
+  });
+});
+
+var quill = new Quill('#editor', {
+  modules: {
+    counter: {
+      container: '#counter',
+      unit: 'word'
+    }
+  }
+});
+
+ +### Constructors + +Since any function can be registered as a Quill module, we could have implemented our counter as a constructor. This allows us to access and utilize the module directly. + +

+var Counter = function(quill, options) {
+  this.quill = quill;
+  this.options = options;
+  var container = document.querySelector(options.container);
+  var _this = this;
+  quill.on('text-change', function() {
+    var length = _this.calculate();
+    container.innerHTML = length + ' ' + options.unit + 's';
+  });
+};
+
+Counter.prototype.calculate = function() {
+  var text = this.quill.getText();
+  if (this.options.unit === 'word') {
+    return text.split(/\s+/).length;
+  } else {
+    return text.length;
+  }
+};
+
+Quill.registerModule('counter', Counter);
+
+var quill = new Quill('#editor');
+var counter = quill.addModule('counter', {
+  container: '#counter',
+  unit: 'word'
+});
+
+// We can now access calculate() directly
+console.log(counter.calculate(), 'words');
+
+ +### Wrapping It All Up + +Now let's polish off the module and fix a few pesky bugs. + +

+var Counter = function(quill, options) {
+  this.quill = quill;
+  this.options = options;
+  this.container = document.querySelector(options.container);
+  quill.on('text-change', this.update.bind(this));
+  this.update();  // Account for initial contents
+};
+
+Counter.prototype.calculate = function() {
+  var text = this.quill.getText();
+  if (this.options.unit === 'word') {
+    text = text.trim();
+    // Splitting empty text returns a non-empty array
+    return text.length > 0 ? text.split(/\s+/).length : 0;
+  } else {
+    return text.length;
+  }
+};
+
+Counter.prototype.update = function() {
+  var length = this.calculate();
+  var label = this.options.unit;
+  if (length !== 1) {
+    label += 's';
+  }
+  this.container.innerHTML = length + ' ' + label;
+}
+
+Quill.registerModule('counter', Counter);
+
+var quill = new Quill('#editor');
+var counter = quill.addModule('counter', {
+  container: '#counter',
+  unit: 'word'
+});
+
+ +That's all there is to it! Stay tuned for more guides on common types of modules you can build. + + + + diff --git a/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-09-29-a-new-delta.md b/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-09-29-a-new-delta.md new file mode 100755 index 00000000..7897ed13 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-09-29-a-new-delta.md @@ -0,0 +1,73 @@ +--- +layout: post +permalink: /blog/a-new-delta/ +title: A New Delta +--- + +Part of providing a complete API in Quill is providing events for when and what changes occur in the editor. Those changes are currently represented by a [Delta](/guides/working-with-deltas/) object, which aims to be intuitive, human-readable, and expressive for any change or document that might need to represented. Over the past few weeks I’ve been working on a new format that better fulfills those goals and addresses the challenges in the current format. + +Documentation for the new Delta format can be found in its own [Github repository](https://github.com/ottypes/rich-text) but I will go over some of the rationale behind some of the changes in this post. + + + +### Reduced Complexity + +When the Delta format was originally designed, it had ambitious goals of being general purpose and being able to represent any kind of document. The new format reduces the scope to just rich text documents, allowing for a much tighter implementation[^1]. + +Quill is not specifically built to be a collaborative editor but the ability to be used as one is a good benchmark of the API. The new Delta format maintains this capability and fulfills the specifications of an [ottype](https://github.com/ottypes/docs), making it compatible with [ShareJS](https://github.com/share/ShareJS). + + +### Explicit Deletes + +In the current Delta format, a delete operation is implied by a lack of a retain operation. Basically everything is deleted unless you say it should be kept. This has some nice properties from an implementation perspective[^2] but was probably the largest source of confusion for users trying to work with Deltas and challenged the human-readability goal. It is very difficult to keep track of indexes to figure out what was not accounted for, to figure out what should be deleted. + +The new format has an explicit delete operation and by default everything is kept. Here’s a comparison of the two formats both representing removing the ‘b’ in ‘abc’. + +```javascript +var oldFormat = { + startLength: 3, + endLength: 2, + ops: [ + { start: 0, end: 1 }, + { start: 2, end: 3 } + ] +}; + +var newFormat = { + ops: [ + { retain: 1 }, + { delete: 1 } + ] +}; +``` + +A side effect of having explicit deletes and defaulting to keeping text is that in practice the representation for new Deltas will usually be smaller. + +### Embed Support + +The new Delta format provides native support for embeds, which can be used to represent images, video, etc. There is no support for this in the current format and implementation is hackily achieved by representing an ‘!’ with a image key in the attributes (which will break when video support is added). + +```javascript +var oldFormat = { + startLength: 0, + endLength: 1, + ops: [{ + text: '!', + attributes: { image: 'https://octodex.github.com/images/labtocat.png' } + }] +}; + +var newFormat = { + ops: [{ + insert: 1, attributes: { image: 'https://octodex.github.com/images/labtocat.png' } + }] +}; +``` + +### Going Forward + +This new format will be the finalized representation for changes and state in Quill going forward and is one of the major steps toward a 1.0 release (a topic for another post). + + +[^1]: Currently 28658 vs 9507 lines of code (though in practice is less relevant due to minification and gzip). +[^2]: Minimizes number of operations to support, and easy to calculate the length of text of the resulting document which is useful for sanity checks. diff --git a/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-10-19-upgrading-to-rich-text-deltas.md b/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-10-19-upgrading-to-rich-text-deltas.md new file mode 100755 index 00000000..61287451 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-10-19-upgrading-to-rich-text-deltas.md @@ -0,0 +1,96 @@ +--- +layout: post +permalink: /blog/upgrading-to-rich-text-deltas/ +title: Upgrading to Rich Text Deltas +--- + +The new rich text type is now live and being used in Quill v0.18.0. It is a big step towards 1.0 and will be the way documents and changes are represented going forward. In most cases this update is non-disruptive and an upgrade can be a simple increment of the version number[^1]. + +However, if you happened to be storing the old Delta format, here's a short guide on how to migrate. + +The main relevant differences between the old and new Deltas are: + +1. Explicit deletes - We need to go through the old Delta, find the implied deletes and insert explicit delete operations into the new Delta +2. Support for embeds - If we see the hacky representation of embeds, replace with the new representation + + + +```javascript +var richText = require('rich-text'); + +var newDelta = new richText.Delta(); +var index = 0; +var changeLength = 0; +oldDelta.ops.forEach(function (op) { + if (_.isString(op.value)) { + // Insert operation + if (op.value === '!' && op.attributes && _.isString(op.attributes.src)) { + // Found the old hacky representation for an embed + // Quill only supports images so far so we can be confident this is an image + // which is represented by 1 + newDelta.insert(1, op.attributes); + } else { + newDelta.insert(op.value, op.attributes); + } + changeLength += op.value.length; + } else if (_.isNumber(op.start) && _.isNumber(op.end)) { + // Retain operation + if (op.start > index) { + // Delete operation was implied by the current retain operation + var length = op.start - index; + newDelta.delete(length); + changeLength -= length; + } + // Now handle or retain operation + newDelta.retain(op.end - op.start, op.attributes); + index = op.end; + } else { + throw new Error('You have a misformed delta'); + } +}); + +// Handle implied deletes at the end of the document +if (oldDelta.endLength < oldDelta.startLength + changeLength) { + var length = oldDelta.startLength + changeLength - oldDelta.endLength; + newDelta.delete(length); +} +``` + +If you cannot use the rich-text module or if you are using this as a general guide for another language, the following might be helpful in crafting insert, delete and retain operations. + +```javascript + +var nweDelta = { ops: [] }; +oldDelta.ops.forEach(function () { + // Following a similar logic to the earlier snippet + // except replacing .insert(), .retain(), .delete() with: + // insertOp(newDelta.ops, value, formats) + // retainOp(newDelta.ops, length, formats) + // deleteOp(newDelta.ops, length) +}); + +function insertOp(opsArr, text, formats) { + var op = { insert: text }; + if (formats && Object.keys(formats).length > 0) { + op.attributes = formats; + } + opsArr.push(op); +}; + +function deleteOp(opsArr, length) { + opsArr.push({ delete: length }); +} + +function retainOp(opsArr, length, formats) { + var op = { retain: length }; + if (formats && Object.keys(formats).length > 0) { + op.attributes = formats; + } + opsArr.push(op); +} +``` + +There are some optimizations performed by rich-text such as excluding no-ops (delete 0 characters) and merging two adjacent operations of the same type (insert 'A' followed by insert 'B' is merged to be a single insert 'AB' operation). But you should not have to worry about these cases since the old Delta format had similar optimizations. + + +[^1]: All it took to upgrade the examples on quilljs.com was: [2580c2](https://github.com/quilljs/quill/commit/2580c2a5d440622d226fbef407df7a5a5e9dcf61) diff --git a/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-11-06-quill-v0-19-no-more-iframes.md b/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-11-06-quill-v0-19-no-more-iframes.md new file mode 100755 index 00000000..00b5139d --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/_posts/2014-11-06-quill-v0-19-no-more-iframes.md @@ -0,0 +1,47 @@ +--- +layout: post +permalink: /blog/quill-v0-19-no-more-iframes/ +title: Quill v0.19 - No More Iframes +--- + +Customizability is core to Quill's ethos and the new [v0.19 release](https://github.com/quilljs/quill/releases/tag/v0.19.0) is a big step towards fulfilling that mission. In previous versions Quill utilized an iframe to contain the editor. This unfortunately prevented expected browser behaviors and made it difficult for developers to access and extend Quill[^1]. Its removal is the biggest change in v0.19 and some rippling effects are expected. They, and other changes for v0.19, are summarized here. + + +### Styles + +With iframes gone it is now much easier to customize the styling of the Quill editor and unecessary for Quill to do so on your behalf in most cases. This leads to a few changes: + +You can now pass `false` into the [style config](/docs/configuration/#styles) to prevent Quill from injecting any ` \ No newline at end of file diff --git a/bl-plugins/quill/quill-1.3.6/docs/assets/images/users.png b/bl-plugins/quill/quill-1.3.6/docs/assets/images/users.png new file mode 100755 index 00000000..041b133f Binary files /dev/null and b/bl-plugins/quill/quill-1.3.6/docs/assets/images/users.png differ diff --git a/bl-plugins/quill/quill-1.3.6/docs/blog.html b/bl-plugins/quill/quill-1.3.6/docs/blog.html new file mode 100755 index 00000000..65125965 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/blog.html @@ -0,0 +1,40 @@ +--- +layout: blog +title: Blog +permalink: /blog/ +--- + +
+

The State of Quill and 2.0

+ +

The 2.0 branch of Quill has officially been opened and development commenced. One design principle Quill embraces is to first make it possible, then make it easy. This allows the technical challenges to be proved out and provides clarity around use cases so that the right audience is designed for. Quill 1.0 pushed the boundaries on the former, and now 2.0 will focus on the latter.

+

+ Let’s take a look at how we got here and where Quill is going! +

+ Read more +
+
+ +{% for post in site.posts %} + {% unless post.draft %} +
+

{{ post.title }}

+ + {% if post.content contains '' %} + {{ post.content | split: '' | first }} + Read more + {% else %} + {{ post.content }} + {% endif %} + {% if forloop.last == false %} +
+ {% endif %} +
+ {% endunless %} +{% endfor %} diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/api.md b/bl-plugins/quill/quill-1.3.6/docs/docs/api.md new file mode 100755 index 00000000..68258d97 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/api.md @@ -0,0 +1,32 @@ +--- +layout: docs +title: API +permalink: /docs/api/ +redirect_from: + - /docs/api/events/ + - /docs/api/manipulation/ + - /docs/editor/ + - /docs/editor/api/ + - /docs/events/ +--- + +
+{% for hash in site.data.api %} + +{% endfor %} +
+ +{% include_relative api/contents.md %} +{% include_relative api/formatting.md %} +{% include_relative api/selection.md %} +{% include_relative api/editor.md %} +{% include_relative api/events.md %} +{% include_relative api/model.md %} +{% include_relative api/extension.md %} diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/api/contents.md b/bl-plugins/quill/quill-1.3.6/docs/docs/api/contents.md new file mode 100755 index 00000000..66c80142 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/api/contents.md @@ -0,0 +1,176 @@ +## Content + +### deleteText + +Deletes text from the editor, returning a [Delta](/guides/working-with-deltas/) representing the change. [Source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. Calls where the `source` is `"user"` when the editor is [disabled](#disable) are ignored. + +**Methods** + +```javascript +deleteText(index: Number, length: Number, source: String = 'api'): Delta +``` + +**Examples** + +```javascript +quill.deleteText(6, 4); +``` + +### getContents + +Retrieves contents of the editor, with formatting data, represented by a [Delta](/docs/delta/) object. + +**Methods** + +```javascript +getContents(index: Number = 0, length: Number = remaining): Delta +``` + +**Examples** + +```javascript +var delta = quill.getContents(); +``` + +### getLength + +Retrieves the length of the editor contents. Note even when Quill is empty, there is still a blank line represented by '\n', so `getLength` will return 1. + +**Methods** + +```javascript +getLength(): Number +``` + +**Examples** + +```javascript +var length = quill.getLength(); +``` + +### getText + +Retrieves the string contents of the editor. Non-string content are omitted, so the returned string's length may be shorter than the editor's as returned by [`getLength`](#getlength). Note even when Quill is empty, there is still a blank line in the editor, so in these cases `getText` will return '\n'. + +The `length` parameter defaults to the length of the remaining document. + +**Methods** + +```javascript +getText(index: Number = 0, length: Number = remaining): String +``` + +**Examples** + +```javascript +var text = quill.getText(0, 10); +``` + +### insertEmbed + +Insert embedded content into the editor, returning a [Delta](/guides/working-with-deltas/) representing the change. [Source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. Calls where the `source` is `"user"` when the editor is [disabled](#disable) are ignored. + +**Methods** + +```javascript +insertEmbed(index: Number, type: String, value: any, source: String = 'api'): Delta +``` + +**Examples** + +```javascript +quill.insertEmbed(10, 'image', 'https://quilljs.com/images/cloud.png'); +``` + +### insertText + +Inserts text into the editor, optionally with a specified format or multiple [formats](/docs/formats/). Returns a [Delta](/guides/working-with-deltas/) representing the change. [Source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. Calls where the `source` is `"user"` when the editor is [disabled](#disable) are ignored. + +**Methods** + +```javascript +insertText(index: Number, text: String, source: String = 'api'): Delta +insertText(index: Number, text: String, format: String, value: any, + source: String = 'api'): Delta +insertText(index: Number, text: String, formats: { [String]: any }, + source: String = 'api'): Delta +``` + +**Examples** + +```javascript +quill.insertText(0, 'Hello', 'bold', true); + +quill.insertText(5, 'Quill', { + 'color': '#ffff00', + 'italic': true +}); +``` + +### pasteHTML + +***Deprecated*** + +This API has been moved into [Clipboard](/docs/modules/clipboard/#dangerouslypastehtml) and renamed. It will be removed as a top level API in 2.0. + +### setContents + +Overwrites editor with given contents. Contents should end with a [newline](/docs/delta/#line-formatting). Returns a Delta representing the change. This will be the same as the Delta passed in, if given Delta had no invalid operations. [Source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. Calls where the `source` is `"user"` when the editor is [disabled](#disable) are ignored. + +**Methods** + +```javascript +setContents(delta: Delta, source: String = 'api'): Delta +``` + +**Examples** + +```javascript +quill.setContents([ + { insert: 'Hello ' }, + { insert: 'World!', attributes: { bold: true } }, + { insert: '\n' } +]); +``` + +### setText + +Sets contents of editor with given text, returing a [Delta](/guides/working-with-deltas/) representing the change. Note Quill documents must end with a newline so one will be added for you if omitted. [Source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. Calls where the `source` is `"user"` when the editor is [disabled](#disable) are ignored. + +**Methods** + +```javascript +setText(text: String, source: String = 'api'): Delta +``` + +**Examples** + +```javascript +quill.setText('Hello\n'); +``` + +### updateContents + +Applies Delta to editor contents, returing a [Delta](/guides/working-with-deltas/) representing the change. These Deltas will be the same if the Delta passed in had no invalid operations. [Source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. Calls where the `source` is `"user"` when the editor is [disabled](#disable) are ignored. + +**Methods** + +```javascript +updateContents(delta: Delta, source: String = 'api'): Delta +``` + +**Examples** + +```javascript +// Assuming editor currently contains [{ insert: 'Hello World!' }] +quill.updateContents(new Delta() + .retain(6) // Keep 'Hello ' + .delete(5) // 'World' is deleted + .insert('Quill') + .retain(1, { bold: true }) // Apply bold to exclamation mark +}); +// Editor should now be [ +// { insert: 'Hello Quill' }, +// { insert: '!', attributes: { bold: true} } +// ] +``` diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/api/editor.md b/bl-plugins/quill/quill-1.3.6/docs/docs/api/editor.md new file mode 100755 index 00000000..5d91bf64 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/api/editor.md @@ -0,0 +1,86 @@ +## Editor + +### blur + +Removes focus from the editor. + +**Methods** + +```javascript +blur() +``` + +**Examples** + +```javascript +quill.blur(); +``` + +### disable + +Shorthand for [`enable(false)`](#enable). + +### enable + +Set ability for user to edit, via input devices like the mouse or keyboard. Does not affect capabilities of API calls, when the `source` is `"api"` or `"silent". + +**Methods** + +```javascript +enable(enabled: boolean = true) +``` + +**Examples** + +```javascript +quill.enable(); +quill.enable(false); // Disables user input +``` + +### focus + +Focuses the editor and restores its last range. + +**Methods** + +```javascript +focus() +``` + +**Examples** + +```javascript +quill.focus(); +``` + +### hasFocus + +Checks if editor has focus. Note focus on toolbar, tooltips, does not count as the editor. + +**Methods** + +```javascript +hasFocus(): Boolean +``` + +**Examples** + +```javascript +quill.hasFocus(); +``` + +### update + +Synchronously check editor for user updates and fires events, if changes have occurred. Useful for collaborative use cases during conflict resolution requiring the latest up to date state. [Source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. + +**Methods** + +```javascript +update(source: String = 'user') +``` + +**Examples** + +```javascript +quill.update(); +``` diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/api/events.md b/bl-plugins/quill/quill-1.3.6/docs/docs/api/events.md new file mode 100755 index 00000000..6aef1482 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/api/events.md @@ -0,0 +1,145 @@ +## Events + +### text-change + +Emitted when the contents of Quill have changed. Details of the change, representation of the editor contents before the change, along with the source of the change are provided. The source will be `"user"` if it originates from the users. For example: + +- User types into the editor +- User formats text using the toolbar +- User uses a hotkey to undo +- User uses OS spelling correction + +Changes may occur through an API but as long as they originate from the user, the provided source should still be `"user"`. For example, when a user clicks on the toolbar, technically the toolbar module calls a Quill API to effect the change. But source is still `"user"` since the origin of the change was the user's click. + +APIs causing text to change may also be called with a `"silent"` source, in which case `text-change` will not be emitted. This is not recommended as it will likely break the undo stack and other functions that rely on a full record of text changes. + +Changes to text may cause changes to the selection (ex. typing advances the cursor), however during the `text-change` handler, the selection is not yet updated, and native browser behavior may place it in an inconsistent state. Use [`selection-change`](#selection-change) or [`editor-change`](#editor-change) for reliable selection updates. + +**Callback Signature** + +```javascript +handler(delta: Delta, oldContents: Delta, source: String) +``` + +**Examples** + +```javascript +quill.on('text-change', function(delta, oldDelta, source) { + if (source == 'api') { + console.log("An API call triggered this change."); + } else if (source == 'user') { + console.log("A user action triggered this change."); + } +}); +``` + +### selection-change + +Emitted when a user or API causes the selection to change, with a range representing the selection boundaries. A null range indicates selection loss (usually caused by loss of focus from the editor). You can also use this event as a focus change event by just checking if the emitted range is null or not. + +APIs causing the selection to change may also be called with a `"silent"` source, in which case `selection-change` will not be emitted. This is useful if `selection-change` is a side effect. For example, typing causes the selection to change but would be very noisy to also emit a `selection-change` event on every character. + +**Callback Signature** + +```javascript +handler(range: { index: Number, length: Number }, + oldRange: { index: Number, length: Number }, + source: String) +``` + +**Examples** + +```javascript +quill.on('selection-change', function(range, oldRange, source) { + if (range) { + if (range.length == 0) { + console.log('User cursor is on', range.index); + } else { + var text = quill.getText(range.index, range.length); + console.log('User has highlighted', text); + } + } else { + console.log('Cursor not in the editor'); + } +}); +``` + +### editor-change + +Emitted when either `text-change` or `selection-change` would be emitted, even when the source is `"silent"`. The first parameter is the event name, either `text-change` or `selection-change`, followed by the arguments normally passed to those respective handlers. + +**Callback Signature** + +```javascript +handler(name: String, ...args) +``` + +**Examples** + +```javascript +quill.on('editor-change', function(eventName, ...args) { + if (eventName === 'text-change') { + // args[0] will be delta + } else if (eventName === 'selection-change') { + // args[0] will be old range + } +}); +``` + +### on + +Adds event handler. See [text-change](#text-change) or [selection-change](#selection-change) for more details on the events themselves. + +**Methods** + +```javascript +on(name: String, handler: Function): Quill +``` + +**Examples** + +```javascript +quill.on('text-change', function() { + console.log('Text change!'); +}); +``` + +### once + +Adds handler for one emission of an event. See [text-change](#text-change) or [selection-change](#selection-change) for more details on the events themselves. + + +**Methods** + +```javascript +once(name: String, handler: Function): Quill +``` + +**Examples** + +```javascript +quill.once('text-change', function() { + console.log('First text change!'); +}); +``` + +### off + +Removes event handler. + +**Methods** + +```javascript +off(name: String, handler: Function): Quill +``` + +**Examples** + +```javascript +function handler() { + console.log('Hello!'); +} + +quill.on('text-change', handler); +quill.off('text-change', handler); +``` diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/api/extension.md b/bl-plugins/quill/quill-1.3.6/docs/docs/api/extension.md new file mode 100755 index 00000000..c5dce790 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/api/extension.md @@ -0,0 +1,129 @@ +## Extension + +### debug + +Static method enabling logging messages at a given level: `'error'`, `'warn'`, `'log'`, or `'info'`. Passing `true` is equivalent to passing `'log'`. Passing `false` disables all messages. + +**Methods** + +```javascript +Quill.debug(level: String | Boolean) +``` + +**Examples** + +```javascript +Quill.debug('info'); +``` + +### import + +Static method returning Quill library, format, module, or theme. In general the path should map exactly to Quill source code directory structure. Unless stated otherwise, modification of returned entities may break required Quill functionality and is strongly discouraged. + +**Methods** + +```javascript +Quill.import(path): any +``` + +**Examples** + +```javascript +var Parchment = Quill.import('parchment'); +var Delta = Quill.import('delta'); + +var Toolbar = Quill.import('modules/toolbar'); +var Link = Quill.import('formats/link'); +// Similar to ES6 syntax `import Link from 'quill/formats/link';` +``` + +### register + +Registers a module, theme, or format(s), making them available to be added to an editor. Can later be retrieved with [`Quill.import`](/docs/api/#import). Use the path prefix of `'formats/'`, `'modules/'`, or `'themes/'` for registering formats, modules or themes, respectively. For formats specifically there is a shortand to just pass in the format directly and the path will be autogenerated. Will overwrite existing definitions with the same path. + +**Methods** + +```javascript +Quill.register(format: Attributor | BlotDefinintion, supressWarning: Boolean = false) +Quill.register(path: String, def: any, supressWarning: Boolean = false) +Quill.register(defs: { [String]: any }, supressWarning: Boolean = false) +``` + +**Examples** + +```javascript +var Module = Quill.import('core/module'); + +class CustomModule extends Module {} + +Quill.register('modules/custom-module', CustomModule); +``` + +```javascript +Quill.register({ + 'formats/custom-format': CustomFormat, + 'modules/custom-module-a': CustomModuleA, + 'modules/custom-module-b': CustomModuleB, +}); + +Quill.register(CustomFormat); +// You cannot do Quill.register(CustomModuleA); as CustomModuleA is not a format +``` + +### addContainer + +Adds and returns a container element inside the Quill container, sibling to the editor itself. By convention, Quill modules should have a class name prefixed with `ql-`. Optionally include a refNode where container should be inserted before. + +**Methods** + +```javascript +addContainer(className: String, refNode?: Node): Element +addContainer(domNode: Node, refNode?: Node): Element +``` + +**Examples** + +```javascript +var container = quill.addContainer('ql-custom'); +``` + + +### getModule + +Retrieves a module that has been added to the editor. + +**Methods** + +```javascript +getModule(name: String): any +``` + +**Examples** + +```javascript +var toolbar = quill.getModule('toolbar'); +``` + + +### disable + +Shorthand for [`enable(false)`](#enable). + + +### enable + +Set ability for user to edit, via input devices like the mouse or keyboard. Does not affect capabilities of API calls. + +**Methods** + +```javascript +enable(value: Boolean = true) +``` + +**Examples** + +```javascript +quill.enable(); +quill.enable(false); // Disables user input +``` + diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/api/formatting.md b/bl-plugins/quill/quill-1.3.6/docs/docs/api/formatting.md new file mode 100755 index 00000000..e4d158d3 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/api/formatting.md @@ -0,0 +1,138 @@ +## Formatting + +### format + +Format text at user's current selection, returning a [Delta](/guides/working-with-deltas/) representing the change. If the user's selection length is 0, i.e. it is a cursor, the format will be set active, so the next character the user types will have that formatting. [Source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. Calls where the `source` is `"user"` when the editor is [disabled](#disable) are ignored. + +**Methods** + +```javascript +format(name: String, value: any, source: String = 'api'): Delta +``` + +**Examples** + +```javascript +quill.format('color', 'red'); +quill.format('align', 'right'); +``` + +### formatLine + +Formats all lines in given range, returning a [Delta](/guides/working-with-deltas/) representing the change. See [formats](/docs/formats/) for a list of available formats. Has no effect when called with inline formats. To remove formatting, pass `false` for the value argument. The user's selection may not be preserved. [Source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. Calls where the `source` is `"user"` when the editor is [disabled](#disable) are ignored. + +**Methods** + +```javascript +formatLine(index: Number, length: Number, source: String = 'api'): Delta +formatLine(index: Number, length: Number, format: String, value: any, + source: String = 'api'): Delta +formatLine(index: Number, length: Number, formats: { [String]: any }, + source: String = 'api'): Delta +``` + +**Examples** + +```javascript +quill.setText('Hello\nWorld!\n'); + +quill.formatLine(1, 2, 'align', 'right'); // right aligns the first line +quill.formatLine(4, 4, 'align', 'center'); // center aligns both lines +``` + +### formatText + +Formats text in the editor, returning a [Delta](/guides/working-with-deltas/) representing the change. For line level formats, such as text alignment, target the newline character or use the [`formatLine`](#formatline) helper. See [formats](/docs/formats/) for a list of available formats. To remove formatting, pass `false` for the value argument. The user's selection may not be preserved. [Source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. Calls where the `source` is `"user"` when the editor is [disabled](#disable) are ignored. + +**Methods** + +```javascript +formatText(index: Number, length: Number, source: String = 'api'): Delta +formatText(index: Number, length: Number, format: String, value: any, + source: String = 'api'): Delta +formatText(index: Number, length: Number, formats: { [String]: any }, + source: String = 'api'): Delta +``` + +**Examples** + +```javascript +quill.setText('Hello\nWorld!\n'); + +quill.formatText(0, 5, 'bold', true); // bolds 'hello' + +quill.formatText(0, 5, { // unbolds 'hello' and set its color to blue + 'bold': false, + 'color': 'rgb(0, 0, 255)' +}); + +quill.formatText(5, 1, 'align', 'right'); // right aligns the 'hello' line +``` + +### getFormat + +Retrieves common formatting of the text in the given range. For a format to be reported, all text within the range must have a truthy value. If there are different truthy values, an array with all truthy values will be reported. If no range is supplied, the user's current selection range is used. May be used to show which formats have been set on the cursor. If called with no arguments, the user's current selection range will be used. + +**Methods** + +```javascript +getFormat(range: Range = current): { [String]: any } +getFormat(index: Number, length: Number = 0): { [String]: any } +``` + +**Examples** + +```javascript +quill.setText('Hello World!'); +quill.formatText(0, 2, 'bold', true); +quill.formatText(1, 2, 'italic', true); +quill.getFormat(0, 2); // { bold: true } +quill.getFormat(1, 1); // { bold: true, italic: true } + +quill.formatText(0, 2, 'color', 'red'); +quill.formatText(2, 1, 'color', 'blue'); +quill.getFormat(0, 3); // { color: ['red', 'blue'] } + +quill.setSelection(3); +quill.getFormat(); // { italic: true, color: 'blue' } + +quill.format('strike', true); +quill.getFormat(); // { italic: true, color: 'blue', strike: true } + +quill.formatLine(0, 1, 'align', 'right'); +quill.getFormat(); // { italic: true, color: 'blue', strike: true, + // align: 'right' } +``` + +### removeFormat + +Removes all formatting and embeds within given range, returning a [Delta](/guides/working-with-deltas/) representing the change. Line formatting will be removed if any part of the line is included in the range. The user's selection may not be preserved. [Source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. Calls where the `source` is `"user"` when the editor is [disabled](#disable) are ignored. + +**Methods** + +```javascript +removeFormat(index: Number, length: Number, source: String = 'api'): Delta +``` + +**Examples** + +```javascript +quill.setContents([ + { insert: 'Hello', { bold: true } }, + { insert: '\n', { align: 'center' } }, + { insert: { formula: 'x^2' } }, + { insert: '\n', { align: 'center' } }, + { insert: 'World', { italic: true }}, + { insert: '\n', { align: 'center' } } +]); + +quill.removeFormat(3, 7); +// Editor contents are now +// [ +// { insert: 'Hel', { bold: true } }, +// { insert: 'lo\n\nWo' }, +// { insert: 'rld', { italic: true }}, +// { insert: '\n', { align: 'center' } } +// ] + +``` diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/api/model.md b/bl-plugins/quill/quill-1.3.6/docs/docs/api/model.md new file mode 100755 index 00000000..4bcfa94e --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/api/model.md @@ -0,0 +1,104 @@ +## Model + +### find experimental {#find-experimental} + +Static method returning the Quill or [Blot](https://github.com/quilljs/parchment) instance for the given DOM node. In the latter case, passing in true for the `bubble` parameter will search up the given DOM's ancestors until it finds a corresponding [Blot](https://github.com/quilljs/parchment). + +**Methods** + +```javascript +Quill.find(domNode: Node, bubble: boolean = false): Blot | Quill +``` + +**Examples** + +```javascript +var container = document.querySelector("#container"); +var quill = new Quill(container); +console.log(Quill.find(container) === quill); // Should be true + +quill.insertText(0, 'Hello', 'link', 'https://world.com'); +var linkNode = document.querySelector('#container a'); +var linkBlot = Quill.find(linkNode); +``` + +### getIndex experimental {#getindex-experimental} + +Returns the distance between the beginning of document to the occurrence of the given [Blot](https://github.com/quilljs/parchment). + +**Methods** + +```javascript +getIndex(blot: Blot): Number +``` + +**Examples** + +```javascript +let [line, offset] = quill.getLine(10); +let index = quill.getIndex(line); // index + offset should == 10 +``` + +### getLeaf experimental {#getleaf-experimental} + +Returns the leaf [Blot](https://github.com/quilljs/parchment) at the specified index within the document. + +**Methods** + +```javascript +getLeaf(index: Number): Blot +``` + +**Examples** + +```javascript +quill.setText('Hello Good World!'); +quill.formatText(6, 4, "bold", true); + +let [leaf, offset] = quill.getLeaf(7); +// leaf should be a Text Blot with value "Good" +// offset should be 1, since the returned leaf started at index 6 +``` + +### getLine experimental {#getline-experimental} + +Returns the line [Blot](https://github.com/quilljs/parchment) at the specified index within the document. + +**Methods** + +```javascript +getLine(index: Number): [Blot, Number] +``` + + +**Examples** + +```javascript +quill.setText('Hello\nWorld!'); + +let [line, offset] = quill.getLine(7); +// line should be a Block Blot representing the 2nd "World!" line +// offset should be 1, since the returned line started at index 6 +``` + +### getLines experimental {#getlines-experimental} + +Returns the lines contained within the specified location. + +**Methods** + +```javascript +getLines(index: Number = 0, length: Number = remaining): Blot[] +getLines(range: Range): Blot[] +``` + +**Examples** + +```javascript +quill.setText('Hello\nGood\nWorld!'); +quill.formatLine(1, 1, 'list', 'bullet'); + +let lines = quill.getLines(2, 5); +// array witha a ListItem and Block Blot, +// representing the first two lines +``` diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/api/selection.md b/bl-plugins/quill/quill-1.3.6/docs/docs/api/selection.md new file mode 100755 index 00000000..6f133137 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/api/selection.md @@ -0,0 +1,63 @@ +## Selection + +### getBounds + +Retrieves the pixel position (relative to the editor container) and dimensions of a selection at a given location. The user's current selection need not be at that index. Useful for calculating where to place tooltips. + +**Methods** + +```javascript +getBounds(index: Number, length: Number = 0): + { left: Number, top: Number, height: Number, width: Number } +``` + +**Examples** + +```javascript +quill.setText('Hello\nWorld\n'); +quill.getBounds(7); // Returns { height: 15, width: 0, left: 27, top: 31 } +``` + +### getSelection + +Retrieves the user's selection range, optionally to focus the editor first. Otherwise `null` may be returned if editor does not have focus. + +**Methods** + +```javascript +getSelection(focus = false): { index: Number, length: Number } +``` + +**Examples** + +```javascript +var range = quill.getSelection(); +if (range) { + if (range.length == 0) { + console.log('User cursor is at index', range.index); + } else { + var text = quill.getText(range.index, range.length); + console.log('User has highlighted: ', text); + } +} else { + console.log('User cursor is not in editor'); +} +``` + +### setSelection + +Sets user selection to given range, which will also focus the editor. Providing `null` as the selection range will blur the editor. [Source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. + +**Methods** + +```javascript +setSelection(index: Number, length: Number, source: String = 'api') +setSelection(range: { index: Number, length: Number }, + souce: String = 'api') +``` + +**Examples** + +```javascript +quill.setSelection(0, 5); +``` diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/configuration.md b/bl-plugins/quill/quill-1.3.6/docs/docs/configuration.md new file mode 100755 index 00000000..9e5d12ed --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/configuration.md @@ -0,0 +1,99 @@ +--- +layout: docs +title: Configuration +permalink: /docs/configuration/ +redirect_from: + - /docs/editor/configuration/ +--- + +Quill allows several ways to customize it to suit your needs. This section is dedicated to tweaking existing functionality. See the [Modules](/docs/modules/) section for adding new functionality and the [Themes](/docs/themes/) section for styling. + + +### Container + +Quill requires a container where the editor will be appended. You can pass in either a CSS selector or a DOM object. + +```javascript +var editor = new Quill('.editor'); // First matching element will be used +``` + +```javascript +var container = document.getElementById('editor'); +var editor = new Quill(container); +``` + +```javascript +var container = $('.editor').get(0); +var editor = new Quill(container); +``` + +### Options + +To configure Quill, pass in an options object: + +```javascript +var options = { + debug: 'info', + modules: { + toolbar: '#toolbar' + }, + placeholder: 'Compose an epic...', + readOnly: true, + theme: 'snow' +}; +var editor = new Quill('#editor', options); +``` + +The following keys are recognized: + +#### bounds + +Default: `document.body` + +DOM Element or a CSS selector for a DOM Element, within which the editor's ui elements (i.e. tooltips, etc.) should be confined. Currently, it only considers left and right boundaries. + +#### debug + +Default: `warn` + +Shortcut for [debug](/docs/api/#debug). Note `debug` is a static method and will affect other instances of Quill editors on the page. Only warning and error messages are enabled by default. + +#### formats + +Default: All formats + +Whitelist of formats to allow in the editor. See [Formats](/docs/formats/) for a complete list. + +#### modules + +Collection of modules to include and respective options. See [Modules](/docs/modules/) for more information. + +#### placeholder + +Default: None + +Placeholder text to show when editor is empty. + +#### readOnly + +Default: `false` + +Whether to instantiate the editor to read-only mode. + +#### scrollingContainer + +Default: `null` + +DOM Element or a CSS selector for a DOM Element, specifying which container has the scrollbars (i.e. `overflow-y: auto`), if is has been changed from the default `ql-editor` with custom CSS. Necessary to fix scroll jumping bugs when Quill is set to [auto grow](/playground/#autogrow) its height, and another ancestor container is responsible from the scrolling. + +*Note: Some browsers will still jump when this value is `body`. Use a separate child `div` to avoid this.* + +#### strict + +Default: `true` + +Some improvements and modifications, under a strict interpretation of semver, would warrant a major version bump. To prevent small changes from inflating Quill's version number, they are disabled by this `strict` flag. Specific changes can be found in the [Changelog](https://github.com/quilljs/quill/blob/master/CHANGELOG.md) and searching for "strict". Setting this to `false` opts into potential future improvements. + +#### theme + +Name of theme to use. The builtin options are "bubble" or "snow". An invalid or falsy value will load a default minimal theme. Note the theme's specific stylesheet still needs to be included manually. See [Themes](/docs/themes/) for more information. diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/delta.md b/bl-plugins/quill/quill-1.3.6/docs/docs/delta.md new file mode 100755 index 00000000..ead61468 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/delta.md @@ -0,0 +1,140 @@ +--- +layout: docs +title: Delta +permalink: /docs/delta/ +redirect_from: + - /docs/deltas/ + - /docs/api/deltas/ + - /guides/working-with-deltas/ +--- + +Deltas are a simple, yet expressive format that can be used to describe Quill's contents and changes. The format is essentially JSON, and is human readable, yet easily parsible by machines. Deltas can describe any Quill document, includes all text and formatting information, without the ambiguity and complexity of HTML. + +Don't be confused by its name Delta—Deltas represents both documents and changes to documents. If you think of Deltas as the instructions from going from one document to another, the way Deltas represent a document is by expressing the instructions starting from an empty document. + +Deltas are implemented as a separate [standalone library](https://github.com/quilljs/delta/), allowing its use outside of Quill. It is suitable for [Operational Transform](https://en.wikipedia.org/wiki/Operational_transformation) and can be used in realtime, Google Docs like applications. For a more in depth explanation behind Deltas, see [Designing the Delta Format](/guides/designing-the-delta-format/). + +**Note:** It is not recommended to construct Deltas by hand—rather use the chainable [`insert()`](https://github.com/quilljs/delta#insert), [`delete()`](https://github.com/quilljs/delta#delete), and [`retain()`](https://github.com/quilljs/delta#retain) methods to create new Deltas. + + +## Document + +The Delta format is almost entirely self-explanatory—the example below describes the string "Gandalf the Grey" where "Gandalf" is bolded and "Grey" is colored #cccccc. + +```javascript +{ + ops: [ + { insert: 'Gandalf', attributes: { bold: true } }, + { insert: ' the ' }, + { insert: 'Grey', attributes: { color: '#cccccc' } } + ] +} +``` + +As its name would imply, describing content is actually a special case for Deltas. The above example is more specifically instructions to insert a bolded string "Gandalf", an unformatted string " the ", followed by the string "Grey" colored #cccccc. When Deltas are used to describe content, it can be thought of as the content that would be created if the Delta was applied to an empty document. + +Since Deltas are a data format, there is no inherent meaning to the values of `attribute` keypairs. For example, there is nothing in the Delta format that dictates color value must be in hex—this is a choice that Quill makes, and can be modified if desired with [Parchment](https://github.com/quilljs/parchment/). + + +### Embeds + +For non-text content such as images or formulas, the insert key can be an object. The object should have one key, which will be used to determine its type. This is the `blotName` if you are building custom content with [Parchment](https://github.com/quilljs/parchment/). Like text, embeds can still have an `attributes` key to describe formatting to be applied to the embed. All embeds have a length of one. + +```javascript +{ + ops: [{ + // An image link + insert: { + image: 'https://quilljs.com/assets/images/icon.png' + }, + attributes: { + link: 'https://quilljs.com' + } + }] +} +``` + + +### Line Formatting + +Attributes associated with a newline character describes formatting for that line. + +```javascript +{ + ops: [ + { insert: 'The Two Towers' }, + { insert: '\n', attributes: { header: 1 } }, + { insert: 'Aragorn sped on up the hill.\n' } + ] +} +``` + +All Quill documents must end with a newline character, even if there is no formatting applied to the last line. This way, you will always have a character position to apply line formatting to. + +Many line formats are exclusive. For example Quill does not allow a line to simultaneously be both a header and a list, despite being possible to represent in the Delta format. + + +## Changes + +When you register a listener for Quill's [`text-change`](/docs/api/#text-change) event, one of the arguments you will get is a Delta describing what changed. In addition to `insert` operations, this Delta might also have `delete` or `retain` operations. + +### Delete + +The `delete` operation instructs exactly what it implies: delete the next number of characters. + +```javascript +{ + ops: [ + { delete: 10 } // Delete the next 10 characters + ] +} +``` + +Since `delete` operations do not include *what* was deleted, a Delta is not reversible. + + +### Retain + +A `retain` operation simply means keep the next number of characters, without modification. If `attributes` is specified, it still means keep those characters, but apply the formatting specified by the `attributes` object. A `null` value for an attributes key is used to specify format removal. + +Starting with the above "Gandalf the Grey" example: + +```javascript +// { +// ops: [ +// { insert: 'Gandalf', attributes: { bold: true } }, +// { insert: ' the ' }, +// { insert: 'Grey', attributes: { color: '#cccccc' } } +// ] +// } + +{ + ops: [ + // Unbold and italicize "Gandalf" + { retain: 7, attributes: { bold: null, italic: true } }, + + // Keep " the " as is + { retain: 5 }, + + // Insert "White" formatted with color #fff + { insert: "White", attributes: { color: '#fff' } }, + + // Delete "Grey" + { delete: 4 } + ] +} +``` + +Note that a Delta's instructions always starts at the beginning of the document. And because of plain `retain` operations, we never need to specify an index for a `delete` or `insert` operation. + + +### Playground + +Play around Quill and take a look at how its content and changes look. Open your developer console for another view into the Deltas. + +
+ + + + + diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/download.md b/bl-plugins/quill/quill-1.3.6/docs/docs/download.md new file mode 100755 index 00000000..d9f4156e --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/download.md @@ -0,0 +1,49 @@ +--- +layout: docs +title: Download +permalink: /docs/download/ +--- + +Quill comes ready to use in several convenient forms. + + +### CDN + +A globally distributed and available CDN is provided, backed by [Amazon Cloudfront](https://aws.amazon.com/cloudfront/). + +```html + + + + + + + + + + + +``` + + +### NPM + +Add Quill as an [NPM](//www.npmjs.org/) dependency and add it your own build workflow, or use the included built options. Compiled stylesheets are also included in `dist/` folder. + +```bash +npm install quill@{{site.version}} +``` + + +### Direct Download + +Quill builds are also available for direct download on every [release](https://github.com/quilljs/quill/releases/tag/v{{site.version}}). + + +### Source + +And of course the complete source code is always available on [Github](https://github.com/quilljs/quill). + +```bash +git clone git@github.com:quilljs/quill.git +``` diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/formats.md b/bl-plugins/quill/quill-1.3.6/docs/docs/formats.md new file mode 100755 index 00000000..bd929dbd --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/formats.md @@ -0,0 +1,43 @@ +--- +layout: docs +title: Formats +permalink: /docs/formats/ +--- + +Quill supports a number of formats, both in UI controls and API calls. + +By default all formats are enabled and allowed to exist within a Quill editor and can be configured with the [formats](/docs/configuration/#formats) option. This is separate from adding a control in the [Toolbar](/docs/modules/toolbar/). For example, you can configure Quill to allow bolded content to be pasted into an editor that has no bold button in the toolbar. + +{% include standalone/full.html %} + +Standalone + +#### Inline + + - Background Color - `background` + - Bold - `bold` + - Color - `color` + - Font - `font` + - Inline Code - `code` + - Italic - `italic` + - Link - `link` + - Size - `size` + - Strikethrough - `strike` + - Superscript/Subscript - `script` + - Underline - `underline` + +#### Block + + - Blockquote - `blockquote` + - Header - `header` + - Indent - `indent` + - List - `list` + - Text Alignment - `align` + - Text Direction - `direction` + - Code Block - `code-block` + +#### Embeds + + - Formula - `formula` + - Image - `image` + - Video - `video` diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/modules.md b/bl-plugins/quill/quill-1.3.6/docs/docs/modules.md new file mode 100755 index 00000000..404425d7 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/modules.md @@ -0,0 +1,54 @@ +--- +layout: docs +title: Modules +permalink: /docs/modules/ +redirect_from: + - /docs/modules/authorship/ + - /docs/modules/multi-cursors/ +--- + +Modules allow Quill's behavior and functionality to be customized. Several officially supported modules are available to pick and choose from, some with additional configuration options and APIs. Refer to their respective documentation pages for more details. + +To enable a module, simply include it in Quill's configuration. + +```javascript +var quill = new Quill('#editor', { + modules: { + 'history': { // Enable with custom configurations + 'delay': 2500, + 'userOnly': true + }, + 'syntax': true // Enable with default configuration + } +}); +``` + +The [Clipboard](/docs/modules/clipboard/), [Keyboard](/docs/modules/keyboard/), and [History](/docs/modules/history/) modules are required by Quill and do not need to be included explictly, but may be configured like any other module. + + +## Extending + +Modules may also be extended and re-registered, replacing the original module. Even required modules may be re-registered and replaced. + +```javascript +var Clipboard = Quill.import('modules/clipboard'); +var Delta = Quill.import('delta'); + +class PlainClipboard extends Clipboard { + convert(html = null) { + if (typeof html === 'string') { + this.container.innerHTML = html; + } + let text = this.container.innerText; + this.container.innerHTML = ''; + return new Delta().insert(text); + } +} + +Quill.register('modules/clipboard', PlainClipboard, true); + +// Will be created with instance of PlainClipboard +var quill = new Quill('#editor'); +``` + +*Note: This particular example was selected to show what is possible. It is often easier to just use an API or configuration the existing module exposes. In this example, the existing Clipboard's [addMatcher](/docs/modules/clipboard/#addmatcher) API is suitable for most paste customization scenarios.* diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/modules/clipboard.md b/bl-plugins/quill/quill-1.3.6/docs/docs/modules/clipboard.md new file mode 100755 index 00000000..ae2c9dd8 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/modules/clipboard.md @@ -0,0 +1,94 @@ +--- +layout: docs +title: Clipboard Module +permalink: /docs/modules/clipboard/ +--- + +The Clipboard handles copy, cut and paste between Quill and external applications. A set of defaults exist to provide sane interpretation of pasted content, with the ability for further customization through matchers. + +The Clipboard interprets pasted HTML by traversing the corresponding DOM tree in [post-order](https://en.wikipedia.org/wiki/Tree_traversal#Post-order), building up a [Delta](/docs/delta/) representation of all subtrees. At each descendant node, matcher functions are called with the DOM Node and Delta interpretation so far, allowing the matcher to return a modified Delta interpretation. + +Familiarity and comfort with [Deltas](/docs/delta/) is necessary in order to effectively use matchers. + + +## API + +#### addMatcher + +Adds a custom matcher to the Clipboard. Matchers using `nodeType` are called first, in the order they were added, followed by matchers using a CSS `selector`, also in the order they were added. [`nodeType`](https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType) may be `Node.ELEMENT_NODE` or `Node.TEXT_NODE`. + +**Methods** + +```javascript +addMatcher(selector: String, (node: Node, delta: Delta) => Delta) +addMatcher(nodeType: Number, (node: Node, delta: Delta) => Delta) +``` + +**Examples** + +```javascript +quill.clipboard.addMatcher(Node.TEXT_NODE, function(node, delta) { + return new Delta().insert(node.data); +}); + +// Interpret a tag as bold +quill.clipboard.addMatcher('B', function(node, delta) { + return delta.compose(new Delta().retain(delta.length(), { bold: true })); +}); +``` + +### dangerouslyPasteHTML + +Inserts content represented by HTML snippet into editor at a given index. The snippet is interpreted by Clipboard [matchers](#addMatcher), which may not produce the exactly input HTML. If no insertion index is provided, the entire editor contents will be overwritten. The [source](/docs/api/#events) may be `"user"`, `"api"`, or `"silent"`. + +Improper handling of HTML can lead to [cross site scripting (XSS)](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)) and failure to sanitize properly is both notoriously error-prone and a leading cause of web vulnerabilities. This method follows React's example and is aptly named to ensure the developer has taken the necessary precautions. + +**Methods** + +```javascript +dangerouslyPasteHTML(html: String, source: String = 'api') +dangerouslyPasteHTML(index: Number, html: String, source: String = 'api') +``` + +**Examples** + +```javascript +quill.setText('Hello!'); + +quill.clipboard.dangerouslyPasteHTML(5, ' World'); +// Editor is now '

Hello World!

'; +``` + + +## Configuration + +### matchers + +An array of matchers can be passed into Clipboard's configuration options. These will be appended after Quill's own default matchers. + +```javascript +var quill = new Quill('#editor', { + modules: { + clipboard: { + matchers: [ + ['B', customMatcherA], + [Node.TEXT_NODE, customMatcherB] + ] + } + } +}); +``` + +### matchVisual + +Quill by default does not have padding or margin for each line, whereas some websites or sources where a paste will come from will. By default Quill will try to match this spacing visually by adding an extra line to compensate for the missing margin/padding. This option disables this behavior. + +```javascript +var quill = new Quill('#editor', { + modules: { + clipboard: { + matchVisual: false + } + } +}); +``` diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/modules/formula.md b/bl-plugins/quill/quill-1.3.6/docs/docs/modules/formula.md new file mode 100755 index 00000000..9714266b --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/modules/formula.md @@ -0,0 +1,30 @@ +--- +layout: docs +title: Formula Module +permalink: /docs/modules/formula/ +redirect_from: + - /docs/modules/formulas/ +--- + +The Formula Module adds beautifully rendered formulas into Quill documents, powered by [KaTeX](https://khan.github.io/KaTeX/). + + +### Example + +```html + + + + + + + +``` diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/modules/history.md b/bl-plugins/quill/quill-1.3.6/docs/docs/modules/history.md new file mode 100755 index 00000000..a81e844f --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/modules/history.md @@ -0,0 +1,116 @@ +--- +layout: docs +title: History Module +permalink: /docs/modules/history/ +--- + +The History module is responsible for handling undo and redo for Quill. It can be configured with the following options: + +## Configuration + +#### delay + +- Default: `1000` + +Changes occuring within the `delay` number of milliseconds is merged into a single change. + +For example, with delay set to `0`, nearly every character is recorded as one change and so undo would undo one character at a time. With delay set to `1000`, undo would undo all changes that occured within the last 1000 milliseconds. + + +#### maxStack + +- Default: `100` + +Maximum size of the history's undo/redo stack. Merged changes with the `delay` option counts as a singular change. + + +#### userOnly + +- Default: `false` + +By default all changes, whether originating from user input or programmatically through the API, are treated the same and change be undone or redone by the history module. If `userOnly` is set to `true`, only user changes will be undone or redone. + + +### Example + +```javascript +var quill = new Quill('#editor', { + modules: { + history: { + delay: 2000, + maxStack: 500, + userOnly: true + } + }, + theme: 'snow' +}); +``` + +## API + +#### clear + +Clears the history stack. + +**Methods** + +```js +clear() +``` + +**Examples** + +```js +quill.history.clear(); +``` + + +#### cutoff experimental {#cutoff-experimental} + +Normally changes made in short succession (configured by `delay`) are merged as a single change, so that triggering an undo will undo multiple changes. Using `cutoff()` will reset the merger window so that a changes before and after `cutoff()` is called will not be merged. + +**Methods** + +```js +cutoff() +``` + +**Examples** + +```js +quill.history.cutoff(); +``` + + +#### undo + +Undo last change. + +**Methods** + +```js +undo() +``` + +**Examples** + +```js +quill.history.undo(); +``` + + +#### redo + +If last change was an undo, redo this undo. Otherwise does nothing. + +**Methods** + +```js +redo() +``` + +**Examples** + +```js +quill.history.redo(); +``` diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/modules/keyboard.md b/bl-plugins/quill/quill-1.3.6/docs/docs/modules/keyboard.md new file mode 100755 index 00000000..df7eccde --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/modules/keyboard.md @@ -0,0 +1,214 @@ +--- +layout: docs +title: Keyboard Module +permalink: /docs/modules/keyboard/ +--- + +The Keyboard module enables custom behavior for keyboard events in particular contexts. Quill uses this to bind formatting hotkeys and prevent undesirable browser side effects. + + +### Key Bindings + +Keyboard handlers are bound to a particular key and key modifiers. The `key` is the JavaScript event key code, but string shorthands are allowed for alphanumeric keys and some common keys. + +Key modifiers include: `metaKey`, `ctrlKey`, `shiftKey` and `altKey`. In addition, `shortKey` is a platform specific modifier equivalent to `metaKey` on a Mac and `ctrlKey` on Linux and Windows. + +Handlers will be called with `this` bound to the keyboard instance and be passed the current selection range. + +```js +quill.keyboard.addBinding({ + key: 'B', + shortKey: true +}, function(range, context) { + this.quill.formatText(range, 'bold', true); +}); + +// addBinding may also be called with one parameter, +// in the same form as in initialization +quill.keyboard.addBinding({ + key: 'B', + shortKey: true, + handler: function(range, context) { + + } +}); +``` + +If a modifier key is `false`, it is assumed to mean that modifier is not active. You may also pass `null` to mean any value for the modifier. + +```js +// Only b with no modifier will trigger +quill.keyboard.addBinding({ key: 'B' }, handler); + +// Only shift+b will trigger +quill.keyboard.addBinding({ key: 'B', shiftKey: true }, handler); + +// Either b or shift+b will trigger +quill.keyboard.addBinding({ key: 'B', shiftKey: null }, handler); + +``` + +Multiple handlers may be bound to the same key and modifier combination. Handlers will be called synchronously, in the order they were bound. By default, a handler stops propagating to the next handler, unless it explicitly returns `true`. + + +```js +quill.keyboard.addBinding({ key: 'tab' }, function(range) { + // I will normally prevent handlers of the tab key + // Return true to let later handlers be called + return true; +}); +``` + +Note: Since Quill's default handlers are added at initialization, the only way to prevent them is to add yours in the [configuration](#configuration). + + +### Context + +Contexts enable further specification for handlers to be called only in particular scenarios. Regardless if context is specified, a context object is provided as a second parameter for all handlers. + +```js +// If the user hits backspace at the beginning of list or blockquote, +// remove the format instead delete any text +quill.keyboard.addBinding({ key: Keyboard.keys.BACKSPACE }, { + collapsed: true, + format: ['blockquote', 'list'], + offset: 0 +}, function(range, context) { + if (context.format.list) { + this.quill.format('list', false); + } else { + this.quill.format('blockquote', false); + } +}); +``` + +#### collapsed + +If `true`, handler is called only if the user's selection is collapsed, i.e. in cursor form. If `false`, the users's selection must be non-zero length, such as when the user has highlighted text. + + +#### empty + +If `true`, called only if user's selection is on an empty line, `false` for a non-empty line. Note setting empty to be true implies collapsed is also true and offset is 0—otherwise the user's selection would not be on an empty line. + +```js +// If the user hits enter on an empty list, remove the list instead +quill.keyboard.addBinding({ key: Keyboard.keys.ENTER }, { + empty: true, // implies collapsed: true and offset: 0 + format: ['list'] +}, function(range, context) { + this.quill.format('list', false); +}); +``` + + +#### format + +When an Array, handler will be called if *any* of the specified formats are active. When an Object, *all* specified formats conditions must be met. In either case, the context parameter will be an Object of all current active formats, the same returned by `quill.getFormat()`. + +```js +var context = { + format: { + list: true, // must be on a list, but can be any value + script: 'super', // must be exactly 'super', 'sub' will not suffice + link: false // cannot be in any link + } +}; +``` + + +#### offset + +Handler will be only called when the user's selection starts `offset` characters from the beginning of the line. Note this is before printable keys have been applied. This is useful in combination with other context specifications. + + +#### prefix + +Regex that must match the text immediately preceding the user's selection's start position. The text will not match cross format boundaries. The supplied `context.prefix` value will be the entire immediately preceding text, not just the regex match. + +```js +// When the user types space... +quill.keyboard.addBinding({ key: ' ' }, { + collapsed: true, + format: { list: false }, // ...on an line that's not already a list + prefix: /^-$/, // ...following a '-' character + offset: 1, // ...at the 1st position of the line, + // otherwise handler would trigger if the user + // typed hyphen+space mid sentence +}, function(range, context) { + // the space character is consumed by this handler + // so we only need to delete the hyphen + this.quill.deleteText(range.index - 1, 1); + // apply bullet formatting to the line + this.quill.formatLine(range.index, 1, 'list', 'bullet'); + // restore selection + this.quill.setSelection(range.index - 1); + + // console.log(context.prefix) would print '-' +}); +``` + +#### suffix + +The same as [`prefix`](#prefix) except matching text immediately following the user's selection's end position. + + +### Configuration + +By default, Quill comes with several useful key bindings, for example indenting lists with tabs. You can add your own upon initization. + +Some bindings are essential to preventing dangerous browser defaults, such as the enter and backspace keys. You cannot remove these bindings to revert to native browser behaviors. However since bindings specified in the configuration will run before Quill's defaults, you can handle special cases and propagate to Quill's otherwise. + +Adding a binding with `quill.keyboard.addBinding` will not run before Quill's because the defaults bindings will have been added by that point. + +```javascript +var bindings = { + // This will overwrite the default binding also named 'tab' + tab: { + key: 9, + handler: function() { + // Handle tab + } + }, + + // There is no default binding named 'custom' + // so this will be added without overwriting anything + custom: { + key: 'B', + shiftKey: true, + handler: function(range, context) { + // Handle shift+b + } + }, + + list: { + key: 'backspace', + context: { + format: ['list'] + }, + handler: function(range, context) { + if (context.offset === 0) { + // When backspace on the first character of a list, + // remove the list instead + this.quill.format('list', false, Quill.sources.USER); + } else { + // Otherwise propogate to Quill's default + return true; + } + } + } +}; + +var quill = new Quill('#editor', { + modules: { + keyboard: { + bindings: bindings + } + } +}); +``` + + +### Peformance + +Like DOM events, Quill key bindings are blocking calls on every match, so it is a bad idea to have a very expensive handler for a very common key binding. Apply the same performance best practices as you would when attaching to common blocking DOM events, like `scroll` or `mousemove`. diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/modules/syntax.md b/bl-plugins/quill/quill-1.3.6/docs/docs/modules/syntax.md new file mode 100755 index 00000000..f859bba4 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/modules/syntax.md @@ -0,0 +1,36 @@ +--- +layout: docs +title: Syntax Highlighter Module +permalink: /docs/modules/syntax/ +redirect_from: + - /docs/modules/code-highlighter/ +--- + +The Syntax Module enhances the Code Block format by automatically detecting and applying syntax highlighting. The excellent [highlight.js](https://highlightjs.org/) library is used as a dependency to parse and tokenize code blocks. + +In general, you may [configure](https://highlightjs.readthedocs.io/en/latest/api.html#configure-options) highlight.js as needed. However, Quill expects and requires the `useBR` option to be `false`. + + +### Example + +```html + + + + + + + +``` diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/modules/toolbar.md b/bl-plugins/quill/quill-1.3.6/docs/docs/modules/toolbar.md new file mode 100755 index 00000000..04be3436 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/modules/toolbar.md @@ -0,0 +1,217 @@ +--- +layout: docs +title: Toolbar Module +permalink: /docs/modules/toolbar/ +--- + + + + +The Toolbar module allow users to easily format Quill's contents. + +
+
+ {% include full-toolbar.html %} +
+
+
+ +It can be configured with a custom container and handlers. + +```javascript +var quill = new Quill('#editor', { + modules: { + toolbar: { + container: '#toolbar', // Selector for toolbar container + handlers: { + 'formula': customFormulaHandler + } + } + } +}); +``` + +Because the `container` option is so common, a top level shorthand is also allowed. + +```javascript +var quill = new Quill('#editor', { + modules: { + // Equivalent to { toolbar: { container: '#toolbar' }} + toolbar: '#toolbar' + } +}); +``` + + +## Container + +Toolbar controls can either be specified by a simple array of format names or a custom HTML container. + +To begin with the simpler array option: + +```javascript +var toolbarOptions = ['bold', 'italic', 'underline', 'strike']; + +var quill = new Quill('#editor', { + modules: { + toolbar: toolbarOptions + } +}); +``` + +Controls can also be grouped by one level of nesting an array. This will wrap controls in a `` with class name `ql-formats`, providing structure for themes to utilize. For example [Snow](/docs/themes/#snow/) adds extra spacing between control groups. + +```javascript +var toolbarOptions = [['bold', 'italic'], ['link', 'image']]; +``` + +Buttons with custom values can be specified with an Object with the name of the format as its only key. + +```javascript +var toolbarOptions = [{ 'header': '3' }]; +``` + +Dropdowns are similarly specified by an Object, but with an array of possible values. CSS is used to control the visual labels for dropdown options. + +```javascript +// Note false, not 'normal', is the correct value +// quill.format('size', false) removes the format, +// allowing default styling to work +var toolbarOptions = [ + { size: [ 'small', false, 'large', 'huge' ]} +]; +``` + +Note [Themes](/docs/themes/) may also specify default values for dropdowns. For example, [Snow](/docs/themes/#snow/) provides a default list of 35 colors for the `color` and `background` formats, if set to an empty array. + +```javascript +var toolbarOptions = [ + ['bold', 'italic', 'underline', 'strike'], // toggled buttons + ['blockquote', 'code-block'], + + [{ 'header': 1 }, { 'header': 2 }], // custom button values + [{ 'list': 'ordered'}, { 'list': 'bullet' }], + [{ 'script': 'sub'}, { 'script': 'super' }], // superscript/subscript + [{ 'indent': '-1'}, { 'indent': '+1' }], // outdent/indent + [{ 'direction': 'rtl' }], // text direction + + [{ 'size': ['small', false, 'large', 'huge'] }], // custom dropdown + [{ 'header': [1, 2, 3, 4, 5, 6, false] }], + + [{ 'color': [] }, { 'background': [] }], // dropdown with defaults from theme + [{ 'font': [] }], + [{ 'align': [] }], + + ['clean'] // remove formatting button +]; + +var quill = new Quill('#editor', { + modules: { + toolbar: toolbarOptions + }, + theme: 'snow' +}); +``` + +For use cases requiring even more customization, you can manually create a toolbar in HTML, and pass the DOM element or selector into Quill. The `ql-toolbar` class will be added to the toolbar container and Quill attach appropriate handlers to ` + + + + +
+ + + +``` + +Note by supplying your own HTML element, Quill searches for particular input elements, but your own inputs that have nothing to do with Quill can still be added and styled and coexist. + +```html +
+ + + + + + +
+
+ + +``` + + +## Handlers + +The toolbar controls by default applies and removes formatting, but you can also overwrite this with custom handlers, for example in order to show external UI. + +Handler functions will be bound to the toolbar (so using `this` will refer to the toolbar instance) and passed the `value` attribute of the input if the corresponding format is inactive, and `false` otherwise. Adding a custom handler will overwrite the default toolbar and theme behavior. + +```javascript +var toolbarOptions = { + handlers: { + // handlers object will be merged with default handlers object + 'link': function(value) { + if (value) { + var href = prompt('Enter the URL'); + this.quill.format('link', href); + } else { + this.quill.format('link', false); + } + } + } +} + +var quill = new Quill('#editor', { + modules: { + toolbar: toolbarOptions + } +}); + +// Handlers can also be added post initialization +var toolbar = quill.getModule('toolbar'); +toolbar.addHandler('image', showImageUI); +``` + + + + + diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/quickstart.md b/bl-plugins/quill/quill-1.3.6/docs/docs/quickstart.md new file mode 100755 index 00000000..686dee1a --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/quickstart.md @@ -0,0 +1,37 @@ +--- +layout: docs +title: Quickstart +permalink: /docs/quickstart/ +redirect_from: /docs/ +--- + +The best way to get started is try a simple example. Quill is initialized with a DOM element to contain the editor. The contents of that element will become the initial contents of Quill. + +```html + + + + +
+

Hello World!

+

Some initial bold text

+


+
+ + + + + + +``` + +And that's all there is to it! + + +### Next Steps ### + +The real magic of Quill comes in its flexibility and extensibility. You can get an idea of what is possible by playing around with the demos throughout this site or head straight to the [Interactive Playground](/playground/). For an in-depth walkthrough, take a look at [How to Customize Quill](/guides/how-to-customize-quill/). diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/autogrow.md b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/autogrow.md new file mode 100755 index 00000000..9df082e5 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/autogrow.md @@ -0,0 +1,82 @@ +--- +layout: standalone +title: Autogrow Example +permalink: /standalone/autogrow/ +--- + + + + +
+
+

Minas Tirith

+


+

Pippin looked out from the shelter of Gandalf"s cloak. He wondered if he was awake or still sleeping, still in the swift-moving dream in which he had been wrapped so long since the great ride began. The dark world was rushing by and the wind sang loudly in his ears. He could see nothing but the wheeling stars, and away to his right vast shadows against the sky where the mountains of the South marched past. Sleepily he tried to reckon the times and stages of their journey, but his memory was drowsy and uncertain.

+


+

There had been the first ride at terrible speed without a halt, and then in the dawn he had seen a pale gleam of gold, and they had come to the silent town and the great empty house on the hill. And hardly had they reached its shelter when the winged shadow had passed over once again, and men wilted with fear. But Gandalf had spoken soft words to him, and he had slept in a corner, tired but uneasy, dimly aware of comings and goings and of men talking and Gandalf giving orders. And then again riding, riding in the night. This was the second, no, the third night since he had looked in the Stone. And with that hideous memory he woke fully, and shivered, and the noise of the wind became filled with menacing voices.

+


+

A light kindled in the sky, a blaze of yellow fire behind dark barriers Pippin cowered back, afraid for a moment, wondering into what dreadful country Gandalf was bearing him. He rubbed his eyes, and then he saw that it was the moon rising above the eastern shadows, now almost at the full. So the night was not yet old and for hours the dark journey would go on. He stirred and spoke.

+


+

"Where are we, Gandalf?" he asked.

+


+

"In the realm of Gondor," the wizard answered. "The land of Anórien is still passing by."

+


+

There was a silence again for a while. Then, "What is that?" cried Pippin suddenly, clutching at Gandalf"s cloak. "Look! Fire, red fire! Are there dragons in this land? Look, there is another!"

+


+

For answer Gandalf cried aloud to his horse. "On, Shadowfax! We must hasten. Time is short. See! The beacons of Gondor are alight, calling for aid. War is kindled. See, there is the fire on Amon Dîn, and flame on Eilenach; and there they go speeding west: Nardol, Erelas, Min-Rimmon, Calenhad, and the Halifirien on the borders of Rohan."

+


+

But Shadowfax paused in his stride, slowing to a walk, and then he lifted up his head and neighed. And out of the darkness the answering neigh of other horses came; and presently the thudding of hoofs was heard, and three riders swept up and passed like flying ghosts in the moon and vanished into the West. Then Shadowfax gathered himself together and sprang away, and the night flowed over him like a roaring wind. +

+


+

Pippin became drowsy again and paid little attention to Gandalf telling him of the customs of Gondor, and how the Lord of the City had beacons built on the tops of outlying hills along both borders of the great range, and maintained posts at these points where fresh horses were always in readiness to bear his errand-riders to Rohan in the North, or to Belfalas in the South. "It is long since the beacons of the North were lit," he said; "and in the ancient days of Gondor they were not needed, for they had the Seven Stones." Pippin stirred uneasily.

+


+

"Sleep again, and do not be afraid!" said Gandalf. "For you are not going like Frodo to Mordor, but to Minas Tirith, and there you will be as safe as you can be anywhere in these days. If Gondor falls, or the Ring is taken, then the Shire will be no refuge."

+


+

"You do not comfort me," said Pippin, but nonetheless sleep crept over him. The last thing that he remembered before he fell into deep dream was a glimpse of high white peaks, glimmering like floating isles above the clouds as they caught the light of the westering moon. He wondered where Frodo was, and if he was already in Mordor, or if he was dead; and he did not know that Frodo from far away looked on that same moon as it set beyond Gondor ere the coming of the day.

+
+
+ + + + + diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/basic.md b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/basic.md new file mode 100755 index 00000000..f08533b3 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/basic.md @@ -0,0 +1,82 @@ +--- +layout: standalone +title: Basic Example +permalink: /standalone/basic/ +--- + + + + +
+ + + + + + + + + + + + + +
+
+ + + + diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/bubble.md b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/bubble.md new file mode 100755 index 00000000..acdd81ba --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/bubble.md @@ -0,0 +1,7 @@ +--- +layout: standalone +title: Bubble Theme +permalink: /standalone/bubble/ +--- + +{% include standalone/bubble.html %} diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/collaborative.md b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/collaborative.md new file mode 100755 index 00000000..0a291c14 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/collaborative.md @@ -0,0 +1,62 @@ +--- +layout: standalone +title: Collaborative Example +permalink: /standalone/collaborative/ +--- + + + + + +
+
+ + + + diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/full.md b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/full.md new file mode 100755 index 00000000..979441a3 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/full.md @@ -0,0 +1,7 @@ +--- +layout: standalone +title: Full Editor +permalink: /standalone/full/ +--- + +{% include standalone/full.html %} diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/list.md b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/list.md new file mode 100755 index 00000000..73231471 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/list.md @@ -0,0 +1,31 @@ +--- +layout: standalone +title: List Example +permalink: /standalone/list/ +--- + + + + +
+ + + + + diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/snow.md b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/snow.md new file mode 100755 index 00000000..35f4360b --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/standalone/snow.md @@ -0,0 +1,7 @@ +--- +layout: standalone +title: Snow Theme +permalink: /standalone/snow/ +--- + +{% include standalone/snow.html %} diff --git a/bl-plugins/quill/quill-1.3.6/docs/docs/themes.md b/bl-plugins/quill/quill-1.3.6/docs/docs/themes.md new file mode 100755 index 00000000..30015ee2 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/docs/themes.md @@ -0,0 +1,89 @@ +--- +layout: docs +title: Themes +permalink: /docs/themes/ +redirect_from: + - /docs/themes/bubble/ + - /docs/themes/snow/ +--- + + + + + + + + +Themes allow you to easily make your editor look good with minimal effort. Quill features two offically supported themes: [Snow](#snow) and [Bubble](#bubble). + +### Usage + +```html + + + + + +``` + +## Bubble + +Bubble is a simple tooltip based theme. + +
+
+
+Standalone + +## Snow + +Snow is a clean, flat toolbar theme. + +
+
+
+Standalone + + +### Customization + +Themes primarily control the visual look of Quill through its CSS stylesheet, and many changes can easily be made by overriding these rules. This is easiest to do, as with any other web application, by simply using your browser developer console to inspect the elements to view the rules affecting them. + +Many other customizations can be done through the respective modules. For example, the toolbar is perhaps the most visible user interface, but much of the customization is done through the [Toolbar module](/docs/modules/toolbar/). + + + + + + + + diff --git a/bl-plugins/quill/quill-1.3.6/docs/guides/adding-quill-to-your-build-pipeline.md b/bl-plugins/quill/quill-1.3.6/docs/guides/adding-quill-to-your-build-pipeline.md new file mode 100755 index 00000000..7ce61504 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/guides/adding-quill-to-your-build-pipeline.md @@ -0,0 +1,66 @@ +--- +layout: docs +title: Adding Quill to Your Build Pipeline +permalink: /guides/adding-quill-to-your-build-pipeline/ +--- + +Each version of Quill is built and ready to use from a variety of sources, including [NPM](https://www.npmjs.com/package/quill) or its [CDN](/docs/download/). However there may be use cases where you would like to build Quill from source, as part of your application's build pipeline. If this desire has not occurred to you, don't sweat it! Using pre-built versions is the easiest way to use Quill. + +Quill is built using [Webpack](https://webpack.js.org/concepts/) and this guide is mostly targeted towards Webpack users. However some principles may translate to other build environments. + +A minimal working example of everything covered in this guide can be found at [quill-webpack-example](https://github.com/quilljs/webpack-example/). + + +### Webpack + +You will need to add Webpack and appropriate loaders as development dependencies to your app. The Typescript compiler is necessary if you want to build Parchment from source as well. + +- Quill source code - [`babel-core`](https://www.npmjs.com/package/babel-core), [`babel-loader`](https://www.npmjs.com/package/babel-loader), [`babel-preset-es2015`](https://www.npmjs.com/package/babel-preset-es2015) +- Parchment source code - [`ts-loader`](https://www.npmjs.com/package/ts-loader), [`typescript`](https://www.npmjs.com/package/typescript) +- SVG icons - [`html-loader`](https://www.npmjs.com/package/html-loader) + +You Webpack configuration file will also need to alias Quill and Parchment to point to their respective entry source files. Without this, Webpack will use the pre-built files included in NPM, instead of building from source. + + +### Entry + +Quill is distributed with builds `quill.js` and `quill.core.js`. The purpose of the entry files for both builds, [quill.js](https://github.com/quilljs/quill/blob/master/quill.js) and [core.js](https://github.com/quilljs/quill/blob/master/core.js), is to import and register necessary dependencies. You will likely want a similar entry point in your application that includes only the formats, modules, or themes that you use. + +```js +import Quill from 'quill/core'; + +import Toolbar from 'quill/modules/toolbar'; +import Snow from 'quill/themes/snow'; + +import Bold from 'quill/formats/bold'; +import Italic from 'quill/formats/italic'; +import Header from 'quill/formats/header'; + + +Quill.register({ + 'modules/toolbar': Toolbar, + 'themes/snow': Snow, + 'formats/bold': Bold, + 'formats/italic': Italic, + 'formats/header': Header +}); + + +export default Quill; +``` + + +### Stylesheets + +There is not as much to benefit from building from source in the realm of stylesheets, since rules can be so easily overwritten. However, [`css-loader`](https://www.npmjs.com/package/css-loader)'s tilde prefix may be useful to include Quill styles in a your application css file. + +```css +@import "~quill/dist/quill.core.css" + +// Rest of your application CSS +``` + + +### Example + +Take a look at [quill-webpack-example](https://github.com/quilljs/webpack-example/) for a minimal working example. diff --git a/bl-plugins/quill/quill-1.3.6/docs/guides/building-a-custom-module.md b/bl-plugins/quill/quill-1.3.6/docs/guides/building-a-custom-module.md new file mode 100755 index 00000000..e5f7b46a --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/guides/building-a-custom-module.md @@ -0,0 +1,162 @@ +--- +layout: docs +title: Building a Custom Module +permalink: /guides/building-a-custom-module/ +--- + +Quill's core strength as an editor is its rich API and powerful customization capabilities. As you implement functionality on top of Quill's API, it may be convenient to organize this as a module. For the purpose of this guide, we will walk through one way to build a word counter module, a commonly found feature in many word processors. + +*Note: Internally modules are how much of Quill's functionality is organized. You can overwrite these default [modules](/docs/modules/) by implementing your own and registering it with the same name.* + +### Counting Words + +At its core a word counter simply counts the number of words in the editor and displays this value in some UI. Thus we need to: + +1. Listen for text changes in Quill. +1. Count the number of words. +1. Display this value. + +Let's jump straight in with a complete example! + + +

+// Implement and register module
+Quill.register('modules/counter', function(quill, options) {
+  var container = document.querySelector('#counter');
+  quill.on('text-change', function() {
+    var text = quill.getText();
+    // There are a couple issues with counting words
+    // this way but we'll fix these later
+    container.innerText = text.split(/\s+/).length;
+  });
+});
+
+// We can now initialize Quill with something like this:
+var quill = new Quill('#editor', {
+  modules: {
+    counter: true
+  }
+});
+
+ +That's all it takes to add a custom module to Quill! A function can be [registered](/docs/api/#quillregistermodule/) as a module and it will be passed the corresponding Quill editor object along with any options. + +### Using Options + +Modules are passed an options object that can be used to fine tune the desired behavior. We can use this to accept a selector for the counter container instead of a hard-coded string. Let's also customize the counter to either count words or characters: + +

+Quill.register('modules/counter', function(quill, options) {
+  var container = document.querySelector(options.container);
+  quill.on('text-change', function() {
+    var text = quill.getText();
+    if (options.unit === 'word') {
+      container.innerText = text.split(/\s+/).length + ' words';
+    } else {
+      container.innerText = text.length + ' characters';
+    }
+  });
+});
+
+var quill = new Quill('#editor', {
+  modules: {
+    counter: {
+      container: '#counter',
+      unit: 'word'
+    }
+  }
+});
+
+ +### Constructors + +Since any function can be registered as a Quill module, we could have implemented our counter as an ES5 constructor or ES6 class. This allows us to access and utilize the module directly. + +

+var Counter = function(quill, options) {
+  this.quill = quill;
+  this.options = options;
+  var container = document.querySelector(options.container);
+  var _this = this;
+  quill.on('text-change', function() {
+    var length = _this.calculate();
+    container.innerText = length + ' ' + options.unit + 's';
+  });
+};
+
+Counter.prototype.calculate = function() {
+  var text = this.quill.getText();
+  if (this.options.unit === 'word') {
+    return text.split(/\s+/).length;
+  } else {
+    return text.length;
+  }
+};
+
+Quill.register('modules/counter', Counter);
+
+var quill = new Quill('#editor', {
+  modules: {
+    counter: {
+      container: '#counter',
+      unit: 'word'
+    }
+  }
+});
+
+var counter = quill.getModule('counter');
+
+// We can now access calculate() directly
+console.log(counter.calculate(), 'words');
+
+ +### Wrapping It All Up + +Now let's polish off the module in ES6 and fix a few pesky bugs. That's all there is to it! + +

+class Counter {
+  constructor(quill, options) {
+    this.quill = quill;
+    this.options = options;
+    this.container = document.querySelector(options.container);
+    quill.on('text-change', this.update.bind(this));
+    this.update();  // Account for initial contents
+  }
+
+  calculate() {
+    let text = this.quill.getText();
+    if (this.options.unit === 'word') {
+      text = text.trim();
+      // Splitting empty text returns a non-empty array
+      return text.length > 0 ? text.split(/\s+/).length : 0;
+    } else {
+      return text.length;
+    }
+  }
+
+  update() {
+    var length = this.calculate();
+    var label = this.options.unit;
+    if (length !== 1) {
+      label += 's';
+    }
+    this.container.innerText = length + ' ' + label;
+  }
+}
+
+Quill.register('modules/counter', Counter);
+
+var quill = new Quill('#editor', {
+  modules: {
+    counter: {
+      container: '#counter',
+      unit: 'word'
+    }
+  }
+});
+
+ + + + diff --git a/bl-plugins/quill/quill-1.3.6/docs/guides/cloning-medium-with-parchment.md b/bl-plugins/quill/quill-1.3.6/docs/guides/cloning-medium-with-parchment.md new file mode 100755 index 00000000..9a084e92 --- /dev/null +++ b/bl-plugins/quill/quill-1.3.6/docs/guides/cloning-medium-with-parchment.md @@ -0,0 +1,316 @@ +--- +layout: docs +title: Cloning Medium with Parchment +permalink: /guides/cloning-medium-with-parchment/ +redirect_from: + - /docs/parchment/ + - /guides/building-on-parchment/ +--- + + + + +To provide a consistent editing experience, you need both consistent data and predictable behaviors. The DOM unfortunately lacks both of these. The solution for modern editors is to maintain their own document model to represent their contents. [Parchment](https://github.com/quilljs/parchment/) is that solution for Quill. It is organized in its own codebase with its own API layer. Through Parchment you can customize the content and formats Quill recognizes, or add entirely new ones. + +In this guide, we will use the building blocks provided by Parchment and Quill to replicate the editor on Medium. We will start with the bare bones of Quill, without any themes, extraneous modules, or formats. At this basic level, Quill only understands plain text. But by the end of this guide, links, videos, and even tweets will be understood. + + +### Groundwork + +Let's start without even using Quill, with just a textarea and button, hooked up to a dummy event listener. We'll use jQuery for convenience throughout this guide, but neither Quill nor Parchment depends on this. We'll also add some basic styling, with the help of [Google Fonts](https://fonts.google.com/) and [Font Awesome](https://fontawesome.io/). None of this has anything to do with Quill or Parchment, so we'll move through quickly. + +
+ + +### Adding Quill Core + +Next, we'll replace the textarea with Quill core, absent of themes, formats and extraneous modules. Open up your developer console to inspect the demo while you type into the editor. You can see the basic building blocks of a Parchment document at work. + +
+ +Like the DOM, a Parchment document is a tree. Its nodes, called Blots, are an abstraction over DOM Nodes. A few blots are already defined for us: Scroll, Block, Inline, Text and Break. As you type, a Text blot is synchronized with the corresponding DOM Text node; enters are handled by creating a new Block blot. In Parchment, Blots that can have children must have at least one child, so empty Blocks are filled with a Break blot. This makes handling leaves simple and predictable. All this is organized under a root Scroll blot. + +You cannot observe an Inline blot by just typing at this point since it does not contribute meaningful structure or formatting to the document. A valid Quill document must be canonical and compact. There is only one valid DOM tree that can represent a given document, and that DOM tree contains the minimal number of nodes. + +Since `

Text

` and `

Text

` represent the same content, the former is invalid and it is part of Quill's optimization process to unwrap the ``. Similarly, once we add formatting, `

Test

` and `

Test

` are also invalid, as they are not the most compact representation. + +Because of these contraints, **Quill cannot support arbitrary DOM trees and HTML changes**. But as we will see, the consistency and predicability this structure provides enables us to easily build rich editing experiences. + + +### Basic Formatting + +We mentioned earlier that an Inline does not contribute formatting. This is the exception, rather than the rule, made for the base Inline class. The base Block blot works the same way for block level elements. + +To implement bold and italics, we need only to inherit from Inline, set the `blotName` and `tagName`, and register it with Quill. For a compelete reference of the signatures of inherited and static methods and variables, take a look at [Parchment](https://github.com/quilljs/parchment/). + +```js +let Inline = Quill.import('blots/inline'); + +class BoldBlot extends Inline { } +BoldBlot.blotName = 'bold'; +BoldBlot.tagName = 'strong'; + +class ItalicBlot extends Inline { } +ItalicBlot.blotName = 'italic'; +ItalicBlot.tagName = 'em'; + +Quill.register(BoldBlot); +Quill.register(ItalicBlot); +``` + +We follow Medium's example here in using `strong` and `em` tags but you could just as well use `b` and `i` tags. The name of the blot will be used as the name of the format by Quill. By registering our blots, we can now use Quill's full API on our new formats: + +```js +Quill.register(BoldBlot); +Quill.register(ItalicBlot); + +var quill = new Quill('#editor'); + +quill.insertText(0, 'Test', { bold: true }); +quill.formatText(0, 4, 'italic', true); +// If we named our italic blot "myitalic", we would call +// quill.formatText(0, 4, 'myitalic', true); +``` + +Let's get rid of our dummy button handler and hook up the bold and italic buttons to Quill's [`format()`](/docs/api/#format). We will hardcode `true` to always add formatting for simplicity. In your application, you can use [`getFormat()`](/docs/api/#getformat) to retrieve the current formatting over a arbitrary range to decide whether to add or remove a format. The [Toolbar](/docs/modules/toolbar/) module implements this for Quill, and we will not reimplement it here. + +Open your developer console and try out Quill's [APIs](/docs/api/) on your new bold and italic formats! Make sure to set the context to the correct CodePen iframe to be able to access the `quill` variable in the demo. + +
+ +Note that if you apply both bold and italic to some text, regardless of what order you do so, Quill wraps the `` tag outside of the `` tag, in a consistent order. + + +### Links + +Links are slightly more complicated, since we need more than a boolean to store the link url. This affects our Link blot in two ways: creation and format retrieval. We will represent the url as a string value, but we could easily do so in other ways, such as an object with a url key, allowing for other key/value pairs to be set and define a link. We will demonstrate this later with [images](#images). + +```js +class LinkBlot extends Inline { + static create(value) { + let node = super.create(); + // Sanitize url value if desired + node.setAttribute('href', value); + // Okay to set other non-format related attributes + // These are invisible to Parchment so must be static + node.setAttribute('target', '_blank'); + return node; + } + + static formats(node) { + // We will only be called with a node already + // determined to be a Link blot, so we do + // not need to check ourselves + return node.getAttribute('href'); + } +} +LinkBlot.blotName = 'link'; +LinkBlot.tagName = 'a'; + +Quill.register(LinkBlot); +``` + +Now we can hook our link button up to a fancy `prompt`, again to keep things simple, before passing to Quill's `format()`. + +
+ + +### Blockquote and Headers + +Blockquotes are implemented the same way as Bold blots, except we will inherit from Block, the base block level Blot. While Inline blots can be nested, Block blots cannot. Instead of wrapping, Block blots replace one another when applied to the same text range. + +```js +let Block = Quill.import('blots/block'); + +class BlockquoteBlot extends Block { } +BlockquoteBlot.blotName = 'blockquote'; +BlockquoteBlot.tagName = 'blockquote'; +``` + +Headers are implemented exactly the same way, with only one difference: it can be represented by more than one DOM element. The value of the format by default becomes the tagName, instead of just `true`. We can customize this by extending `formats()`, similar to how we did so for [links](#links). + +```js +class HeaderBlot extends Block { + static formats(node) { + return HeaderBlot.tagName.indexOf(node.tagName) + 1; + } +} +HeaderBlot.blotName = 'header'; +// Medium only supports two header sizes, so we will only demonstrate two, +// but we could easily just add more tags into this array +HeaderBlot.tagName = ['H1', 'H2']; +``` + +Let's hook these new blots up to their respective buttons and add some CSS for the `
` tag. + +
+ +Try setting some text to H1, and in your console, run `quill.getContents()`. You will see our custom static `formats()` function at work. Make sure to set the context to the correct CodePen iframe to be able to access the `quill` variable in the demo. + + +### Dividers + +Now let's implement our first leaf Blot. While our previous Blot examples contribute formatting and implement `format()`, leaf Blots contribute content and implement `value()`. Leaf Blots can either be Text or Embed Blots, so our section divider will be an Embed. Once created, Embed Blots' value is immutable, requiring deletion and reinsertion to change the content at that location. + +Our methodology is similar to before, except we inherit from a BlockEmbed. Embed also exists under `blots/embed`, but is meant for inline level blots. We want the block level implementation instead for dividers. + +```js +let BlockEmbed = Quill.import('blots/block/embed'); + +class DividerBlot extends BlockEmbed { } +DividerBlot.blotName = 'divider'; +DividerBlot.tagName = 'hr'; +``` + +Our click handler calls [`insertEmbed()`](/docs/api/#insertembed), which does not as convienently determine, save, and restore the user selection for us like [`format()`](/docs/api/#format) does, so we have to do a little more work to preserve selection ourselves. In addition, when we try to insert a BlockEmbed in the middle of the Block, Quill splits the Block for us. To make this behavior more clear, we will explicitly split the block oursevles by inserting a newline before inserting the divider. Take a look at the Babel tab in the CodePen for specifics. + +
+ + +### Images + +Images can be added with what we learned building the [Link](#links) and [Divider](#divider) blots. We will use an object for the value to show how this is supported. Our button handler to insert images will use a static value, so we are not distracted by tooltip UI code irrelevant to [Parchment](https://github.com/quilljs/parchment/), the focus of this guide. + +```js +let BlockEmbed = Quill.import('blots/block/embed'); + +class ImageBlot extends BlockEmbed { + static create(value) { + let node = super.create(); + node.setAttribute('alt', value.alt); + node.setAttribute('src', value.url); + return node; + } + + static value(node) { + return { + alt: node.getAttribute('alt'), + url: node.getAttribute('src') + }; + } +} +ImageBlot.blotName = 'image'; +ImageBlot.tagName = 'img'; +``` + +
+ + +### Videos + +We will implement videos in a similar way as we did [images](#images). We could use the HTML5 `