diff --git a/Gruntfile.js b/Gruntfile.js index 2b3d4941e..3cadb09b0 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -17,6 +17,7 @@ module.exports = function (grunt) { 'src/js/selection.js', 'src/js/button.js', 'src/js/paste.js', + 'src/js/extension-anchor.js', 'src/js/core.js' ]; diff --git a/dist/js/medium-editor.js b/dist/js/medium-editor.js index 92211b7da..c5e990b04 100644 --- a/dist/js/medium-editor.js +++ b/dist/js/medium-editor.js @@ -406,6 +406,10 @@ var DefaultButton, action: 'underline', aria: 'underline', tagNames: ['u'], + style: { + prop: 'text-decoration', + value: 'underline' + }, useQueryState: true, contentDefault: 'U', contentFA: '' @@ -415,6 +419,10 @@ var DefaultButton, action: 'strikethrough', aria: 'strike through', tagNames: ['strike'], + style: { + prop: 'text-decoration', + value: 'line-through' + }, useQueryState: true, contentDefault: 'A', contentFA: '' @@ -675,7 +683,8 @@ var DefaultButton, shouldActivate: function (node) { var isMatch = false, tagNames = this.getTagNames(), - styleVals; + styleVals, + computedStyle; if (this.knownState === false || this.knownState === true) { return this.knownState; } @@ -686,10 +695,10 @@ var DefaultButton, if (!isMatch && this.options.style) { styleVals = this.options.style.value.split('|'); + computedStyle = this.base.options.contentWindow.getComputedStyle(node, null).getPropertyValue(this.options.style.prop); styleVals.forEach(function (val) { - this.knownState = isMatch = (this.base.options.contentWindow.getComputedStyle(node, null).getPropertyValue(this.options.style.prop).indexOf(val) !== -1); - if (this.knownState) { - return false; + if (!this.knownState) { + this.knownState = isMatch = (computedStyle.indexOf(val) !== -1); } }.bind(this)); } @@ -926,6 +935,209 @@ var pasteHandler; }; }(window, document)); +var AnchorExtension; + +(function (window, document) { + 'use strict'; + + AnchorExtension = function (instance) { + this.base = instance; + }; + + AnchorExtension.prototype = { + + getForm: function () { + if (!this.anchorForm) { + this.anchorForm = this.createForm(); + } + return this.anchorForm; + }, + + getInput: function () { + return this.getForm().querySelector('input.medium-editor-toolbar-input'); + }, + + deactivate: function () { + if (!this.anchorForm) { + return false; + } + + if (this.anchorForm.parentNode) { + this.anchorForm.parentNode.removeChild(this.anchorForm); + } + + delete this.anchorForm; + }, + + doLinkCreation: function () { + var button = null, + target, + targetCheckbox = this.getForm().querySelector('.medium-editor-toolbar-anchor-target'), + buttonCheckbox = this.getForm().querySelector('.medium-editor-toolbar-anchor-button'); + + if (targetCheckbox && targetCheckbox.checked) { + target = "_blank"; + } else { + target = "_self"; + } + + if (buttonCheckbox && buttonCheckbox.checked) { + button = this.base.options.anchorButtonClass; + } + + this.base.createLink(this.getInput(), target, button); + }, + + doFormCancel: function () { + this.base.showToolbarActions(); + this.base.restoreSelection(); + }, + + handleOutsideInteraction: function (event) { + if (event.target !== this.getForm() && + !mediumEditorUtil.isDescendant(this.getForm(), event.target) && + !mediumEditorUtil.isDescendant(this.base.toolbarActions, event.target)) { + this.base.keepToolbarAlive = false; + this.base.checkSelection(); + } + }, + + createForm: function () { + var doc = this.base.options.ownerDocument, + form = doc.createElement('div'), + input = doc.createElement('input'), + close = doc.createElement('a'), + save = doc.createElement('a'), + target, + target_label, + button, + button_label; + + // Anchor Form (div) + form.className = 'medium-editor-toolbar-form'; + form.id = 'medium-editor-toolbar-form-anchor-' + this.base.id; + + // Handle clicks on the form itself + this.base.on(form, 'click', function (event) { + event.stopPropagation(); + this.base.keepToolbarAlive = true; + }.bind(this)); + + // Add url textbox + input.setAttribute('type', 'text'); + input.className = 'medium-editor-toolbar-input'; + input.setAttribute('placeholder', this.base.options.anchorInputPlaceholder); + form.appendChild(input); + + // Handle typing in the textbox + this.base.on(input, 'keyup', function (event) { + // For ENTER -> create the anchor + if (event.keyCode === mediumEditorUtil.keyCode.ENTER) { + event.preventDefault(); + this.doLinkCreation(); + return; + } + + // For ESCAPE -> close the form + if (event.keyCode === mediumEditorUtil.keyCode.ESCAPE) { + event.preventDefault(); + this.doFormCancel(); + } + }.bind(this)); + + // Handle clicks into the textbox + this.base.on(input, 'click', function (event) { + // make sure not to hide form when cliking into the input + event.stopPropagation(); + this.base.keepToolbarAlive = true; + }.bind(this)); + + // Add save buton + save.setAttribute('href', '#'); + save.className = 'medium-editor-toobar-save'; + save.innerHTML = '✓'; + form.appendChild(save); + + // Handle save button clicks (capture) + this.base.on(save, 'click', function (event) { + // Clicking Save -> create the anchor + event.preventDefault(); + this.doLinkCreation(); + }.bind(this), true); + + // Add close button + close.setAttribute('href', '#'); + close.className = 'medium-editor-toobar-close'; + close.innerHTML = '×'; + form.appendChild(close); + + // Handle close button clicks + this.base.on(close, 'click', function (event) { + // Click Close -> close the form + event.preventDefault(); + this.doFormCancel(); + }.bind(this)); + + // (Optional) Add 'open in new window' checkbox + if (this.base.options.anchorTarget) { + target = doc.createElement('input'); + target.setAttribute('type', 'checkbox'); + target.className = 'medium-editor-toolbar-anchor-target'; + + target_label = doc.createElement('label'); + target_label.innerHTML = this.base.options.anchorInputCheckboxLabel; + target_label.insertBefore(target, target_label.firstChild); + + form.appendChild(target_label); + } + + // (Optional) Add 'add button class to anchor' checkbox + if (this.base.options.anchorButton) { + button = doc.createElement('input'); + button.setAttribute('type', 'checkbox'); + button.className = 'medium-editor-toolbar-anchor-button'; + + button_label = doc.createElement('label'); + button_label.innerHTML = "Button"; + button_label.insertBefore(button, button_label.firstChild); + + form.appendChild(button_label); + } + + // Handle click (capture) & focus (capture) outside of the form + this.base.on(doc.body, 'click', this.handleOutsideInteraction.bind(this), true); + this.base.on(doc.body, 'focus', this.handleOutsideInteraction.bind(this), true); + + return form; + }, + + focus: function (value) { + var input = this.getInput(); + input.focus(); + input.value = value || ''; + }, + + hideForm: function () { + this.getForm().style.display = 'none'; + }, + + showForm: function () { + this.getForm().style.display = 'block'; + }, + + isDisplayed: function () { + return this.getForm().style.display === 'block'; + }, + + isClickIntoForm: function (event) { + return (event && + event.type && + event.type.toLowerCase() === 'blur' && + event.relatedTarget && + event.relatedTarget === this.getInput()); + } + }; +}(window, document)); function MediumEditor(elements, options) { 'use strict'; return this.init(elements, options); @@ -936,7 +1148,8 @@ function MediumEditor(elements, options) { MediumEditor.statics = { ButtonsData: ButtonsData, - DefaultButton: DefaultButton + DefaultButton: DefaultButton, + AnchorExtension: AnchorExtension }; MediumEditor.prototype = { @@ -1102,7 +1315,6 @@ function MediumEditor(elements, options) { if (addToolbar) { this.initToolbar() .bindButtons() - .bindAnchorForm() .bindAnchorPreview(); } return this; @@ -1457,13 +1669,6 @@ function MediumEditor(elements, options) { this.toolbarActions = this.toolbar.querySelector('.medium-editor-toolbar-actions'); this.anchorPreview = this.createAnchorPreview(); - if (!this.options.disableAnchorForm) { - this.anchorForm = this.toolbar.querySelector('.medium-editor-toolbar-form'); - this.anchorInput = this.anchorForm.querySelector('input.medium-editor-toolbar-input'); - this.anchorTarget = this.anchorForm.querySelector('input.medium-editor-toolbar-anchor-target'); - this.anchorButton = this.anchorForm.querySelector('input.medium-editor-toolbar-anchor-button'); - } - this.addExtensionForms(); return this; @@ -1482,7 +1687,8 @@ function MediumEditor(elements, options) { toolbar.appendChild(this.toolbarButtons()); if (!this.options.disableAnchorForm) { - toolbar.appendChild(this.toolbarFormAnchor()); + this.anchorExtension = new AnchorExtension(this); + toolbar.appendChild(this.anchorExtension.getForm()); } this.options.elementsContainer.appendChild(toolbar); return toolbar; @@ -1530,58 +1736,6 @@ function MediumEditor(elements, options) { }.bind(this)); }, - toolbarFormAnchor: function () { - var anchor = this.options.ownerDocument.createElement('div'), - input = this.options.ownerDocument.createElement('input'), - target_label = this.options.ownerDocument.createElement('label'), - target = this.options.ownerDocument.createElement('input'), - button_label = this.options.ownerDocument.createElement('label'), - button = this.options.ownerDocument.createElement('input'), - close = this.options.ownerDocument.createElement('a'), - save = this.options.ownerDocument.createElement('a'); - - close.setAttribute('href', '#'); - close.className = 'medium-editor-toobar-close'; - close.innerHTML = '×'; - - save.setAttribute('href', '#'); - save.className = 'medium-editor-toobar-save'; - save.innerHTML = '✓'; - - input.setAttribute('type', 'text'); - input.className = 'medium-editor-toolbar-input'; - input.setAttribute('placeholder', this.options.anchorInputPlaceholder); - - - target.setAttribute('type', 'checkbox'); - target.className = 'medium-editor-toolbar-anchor-target'; - target_label.innerHTML = this.options.anchorInputCheckboxLabel; - target_label.insertBefore(target, target_label.firstChild); - - button.setAttribute('type', 'checkbox'); - button.className = 'medium-editor-toolbar-anchor-button'; - button_label.innerHTML = "Button"; - button_label.insertBefore(button, button_label.firstChild); - - - anchor.className = 'medium-editor-toolbar-form'; - anchor.id = 'medium-editor-toolbar-form-anchor-' + this.id; - anchor.appendChild(input); - - anchor.appendChild(save); - anchor.appendChild(close); - - if (this.options.anchorTarget) { - anchor.appendChild(target_label); - } - - if (this.options.anchorButton) { - anchor.appendChild(button_label); - } - - return anchor; - }, - bindSelect: function () { var self = this, i, @@ -1589,7 +1743,7 @@ function MediumEditor(elements, options) { this.checkSelectionWrapper = function (e) { // Do not close the toolbar when bluring the editable area and clicking into the anchor form - if (!self.options.disableAnchorForm && e && self.clickingIntoArchorForm(e)) { + if (e && this.anchorExtension && this.anchorExtension.isClickIntoForm(e)) { return false; } @@ -1730,7 +1884,7 @@ function MediumEditor(elements, options) { if (!this.options.staticToolbar) { this.hideToolbarActions(); - } else if (this.anchorForm && this.anchorForm.style.display === 'block') { + } else if (this.anchorExtension && this.anchorExtension.isDisplayed()) { this.setToolbarButtonStates(); this.showToolbarActions(); } @@ -1749,16 +1903,6 @@ function MediumEditor(elements, options) { return this; }, - clickingIntoArchorForm: function (e) { - var self = this; - - if (e.type && e.type.toLowerCase() === 'blur' && e.relatedTarget && e.relatedTarget === self.anchorInput) { - return true; - } - - return false; - }, - hasMultiParagraphs: function () { var selectionHtml = meSelection.getSelectionHtml.call(this).replace(/<[\S]+><\/[\S]+>/gim, ''), hasMultiParagraphs = selectionHtml.match(/<(p|h[0-6]|blockquote)>([\s\S]*?)<\/(p|h[0-6]|blockquote)>/g); @@ -2050,8 +2194,8 @@ function MediumEditor(elements, options) { if (selectedParentElement.tagName && selectedParentElement.tagName.toLowerCase() === 'a') { this.options.ownerDocument.execCommand('unlink', false, null); - } else if (this.anchorForm) { - if (this.anchorForm.style.display === 'block') { + } else if (this.anchorExtension) { + if (this.anchorExtension.isDisplayed()) { this.showToolbarActions(); } else { this.showAnchorForm(); @@ -2120,8 +2264,8 @@ function MediumEditor(elements, options) { showToolbarActions: function () { var self = this; - if (this.anchorForm) { - this.anchorForm.style.display = 'none'; + if (this.anchorExtension) { + this.anchorExtension.hideForm(); } this.toolbarActions.style.display = 'block'; this.keepToolbarAlive = false; @@ -2223,100 +2367,16 @@ function MediumEditor(elements, options) { }, showAnchorForm: function (link_value) { - if (!this.anchorForm) { + if (!this.anchorExtension) { return; } this.toolbarActions.style.display = 'none'; this.saveSelection(); - this.anchorForm.style.display = 'block'; + this.anchorExtension.showForm(); this.setToolbarPosition(); this.keepToolbarAlive = true; - this.anchorInput.focus(); - this.anchorInput.value = link_value || ''; - }, - - bindAnchorForm: function () { - if (!this.anchorForm) { - return this; - } - - var linkCancel = this.anchorForm.querySelector('a.medium-editor-toobar-close'), - linkSave = this.anchorForm.querySelector('a.medium-editor-toobar-save'), - self = this; - - this.on(this.anchorForm, 'click', function (e) { - e.stopPropagation(); - self.keepToolbarAlive = true; - }); - - this.on(this.anchorInput, 'keyup', function (e) { - var button = null, - target; - - if (e.keyCode === mediumEditorUtil.keyCode.ENTER) { - e.preventDefault(); - if (self.options.anchorTarget && self.anchorTarget.checked) { - target = "_blank"; - } else { - target = "_self"; - } - - if (self.options.anchorButton && self.anchorButton.checked) { - button = self.options.anchorButtonClass; - } - - self.createLink(this, target, button); - } else if (e.keyCode === mediumEditorUtil.keyCode.ESCAPE) { - e.preventDefault(); - self.showToolbarActions(); - self.restoreSelection(); - } - }); - - this.on(linkSave, 'click', function (e) { - var button = null, - target; - e.preventDefault(); - if (self.options.anchorTarget && self.anchorTarget.checked) { - target = "_blank"; - } else { - target = "_self"; - } - - if (self.options.anchorButton && self.anchorButton.checked) { - button = self.options.anchorButtonClass; - } - - self.createLink(self.anchorInput, target, button); - }, true); - - this.on(this.anchorInput, 'click', function (e) { - // make sure not to hide form when cliking into the input - e.stopPropagation(); - self.keepToolbarAlive = true; - }); - - // Hide the anchor form when focusing outside of it. - this.on(this.options.ownerDocument.body, 'click', function (e) { - if (e.target !== self.anchorForm && !mediumEditorUtil.isDescendant(self.anchorForm, e.target) && !mediumEditorUtil.isDescendant(self.toolbarActions, e.target)) { - self.keepToolbarAlive = false; - self.checkSelection(); - } - }, true); - this.on(this.options.ownerDocument.body, 'focus', function (e) { - if (e.target !== self.anchorForm && !mediumEditorUtil.isDescendant(self.anchorForm, e.target) && !mediumEditorUtil.isDescendant(self.toolbarActions, e.target)) { - self.keepToolbarAlive = false; - self.checkSelection(); - } - }, true); - - this.on(linkCancel, 'click', function (e) { - e.preventDefault(); - self.showToolbarActions(); - self.restoreSelection(); - }); - return this; + this.anchorExtension.focus(link_value); }, hideAnchorPreview: function () { @@ -2433,7 +2493,7 @@ function MediumEditor(elements, options) { sel.removeAllRanges(); sel.addRange(range); // Using setTimeout + options.delay because: - // We may actually be displaying the anchor preview, which should be controlled by options.delay + // We may actually be displaying the anchor form, which should be controlled by options.delay this.delay(function () { if (self.activeAnchor) { self.showAnchorForm(self.activeAnchor.attributes.href.value); @@ -2619,6 +2679,10 @@ function MediumEditor(elements, options) { } }.bind(this)); + if (this.anchorExtension) { + this.anchorExtension.deactivate(); + } + this.removeAllEvents(); }, diff --git a/dist/js/medium-editor.min.js b/dist/js/medium-editor.min.js index 7d1630b78..dc10b789f 100644 --- a/dist/js/medium-editor.min.js +++ b/dist/js/medium-editor.min.js @@ -1,2 +1,2 @@ -!function(a,b){"use strict";"object"==typeof module?module.exports=b:"function"==typeof define&&define.amd?define(b):a.MediumEditor=b}(this,function(){"use strict";function a(a,b){return this.init(a,b)}var b;!function(a){b={isIE:"Microsoft Internet Explorer"===navigator.appName||"Netscape"===navigator.appName&&null!==new RegExp("Trident/.*rv:([0-9]{1,}[.0-9]{0,})").exec(navigator.userAgent),keyCode:{BACKSPACE:8,TAB:9,ENTER:13,ESCAPE:27,SPACE:32,DELETE:46},parentElements:["p","h1","h2","h3","h4","h5","h6","blockquote","pre"],extend:function(a,b){var c;if(void 0===a)return b;for(c in b)b.hasOwnProperty(c)&&a.hasOwnProperty(c)===!1&&(a[c]=b[c]);return a},findAdjacentTextNodeWithContent:function(a,b,c){var d,e=!1,f=c.createNodeIterator(a,NodeFilter.SHOW_TEXT,null,!1);for(d=f.nextNode();d;){if(d===b)e=!0;else if(e&&3===d.nodeType&&d.nodeValue&&d.nodeValue.trim().length>0)break;d=f.nextNode()}return d},isDescendant:function(a,b){for(var c=b.parentNode;null!==c;){if(c===a)return!0;c=c.parentNode}return!1},isElement:function(a){return!(!a||1!==a.nodeType)},now:function(){return Date.now||(new Date).getTime()},throttle:function(a,c){var d,e,f,g,h=50,i=null,j=0;return c||0===c||(c=h),g=function(){j=b.now(),i=null,f=a.apply(d,e),i||(d=e=null)},function(){var h=b.now(),k=c-(h-j);return d=this,e=arguments,0>=k||k>c?(clearTimeout(i),i=null,j=h,f=a.apply(d,e),i||(d=e=null)):i||(i=setTimeout(g,k)),f}},traverseUp:function(a,b){do{if(1===a.nodeType){if(b(a))return a;if(a.getAttribute("data-medium-element"))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,h,i;if(b.queryCommandSupported("insertHTML"))try{return b.execCommand("insertHTML",!1,c)}catch(j){}if(d=a.getSelection(),d.getRangeAt&&d.rangeCount){for(e=d.getRangeAt(0),e.deleteContents(),f=b.createElement("div"),f.innerHTML=c,g=b.createDocumentFragment();f.firstChild;)h=f.firstChild,i=g.appendChild(h);e.insertNode(g),i&&(e=e.cloneRange(),e.setStartAfter(i),e.collapse(!0),d.removeAllRanges(),d.addRange(e))}},setTargetBlank:function(a){var b;if("a"===a.tagName.toLowerCase())a.target="_blank";else for(a=a.getElementsByTagName("a"),b=0;ba;a+=1)d.appendChild(b.getRangeAt(a).cloneContents());e=d.innerHTML}}else void 0!==this.options.ownerDocument.selection&&"Text"===this.options.ownerDocument.selection.type&&(e=this.options.ownerDocument.selection.createRange().htmlText);return e},getCaretOffsets:function(b,c){var d,e;return c||(c=a.getSelection().getRangeAt(0)),d=c.cloneRange(),e=c.cloneRange(),d.selectNodeContents(b),d.setEnd(c.endContainer,c.endOffset),e.selectNodeContents(b),e.setStart(c.endContainer,c.endOffset),{left:d.toString().length,right:e.toString().length}},rangeSelectsSingleNode:function(a){var b=a.startContainer;return b===a.endContainer&&b.hasChildNodes()&&a.endOffset===a.startOffset+1},getSelectedParentElement:function(a){var b=null;return b=this.rangeSelectsSingleNode(a)&&3!==a.startContainer.childNodes[a.startOffset].nodeType?a.startContainer.childNodes[a.startOffset]:3===a.startContainer.nodeType?a.startContainer.parentNode:a.startContainer},getSelectionData:function(a){var c;for(a&&a.tagName&&(c=a.tagName.toLowerCase());a&&-1===b.parentElements.indexOf(c);)a=a.parentNode,a&&a.tagName&&(c=a.tagName.toLowerCase());return{el:a,tagName:c}}}}(document,window);var d,e;!function(){e={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"],useQueryState:!0,contentDefault:"U",contentFA:''},strikethrough:{name:"strikethrough",action:"strikethrough",aria:"strike through",tagNames:["strike"],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:''},anchor:{name:"anchor",action:"anchor",aria:"link",tagNames:["a"],contentDefault:"#",contentFA:''},image:{name:"image",action:"image",aria:"image",tagNames:["img"],contentDefault:"image",contentFA:''},quote:{name:"quote",action:"append-blockquote",aria:"blockquote",tagNames:["blockquote"],contentDefault:"",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:''},pre:{name:"pre",action:"append-pre",aria:"preformatted text",tagNames:["pre"],contentDefault:"0101",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"},useQueryState:!0,contentDefault:"C",contentFA:''},justifyFull:{name:"justifyFull",action:"justifyFull",aria:"full justify",tagNames:[],style:{prop:"text-align",value:"justify"},useQueryState:!0,contentDefault:"J",contentFA:''},justifyLeft:{name:"justifyLeft",action:"justifyLeft",aria:"left justify",tagNames:[],style:{prop:"text-align",value:"left"},useQueryState:!0,contentDefault:"L",contentFA:''},justifyRight:{name:"justifyRight",action:"justifyRight",aria:"right justify",tagNames:[],style:{prop:"text-align",value:"right"},useQueryState:!0,contentDefault:"R",contentFA:''},header1:{name:"header1",action:function(a){return"append-"+a.firstHeader},aria:function(a){return a.firstHeader},tagNames:function(a){return[a.firstHeader]},contentDefault:"H1"},header2:{name:"header2",action:function(a){return"append-"+a.secondHeader},aria:function(a){return a.secondHeader},tagNames:function(a){return[a.secondHeader]},contentDefault:"H2"}},d=function(a,b){this.options=a,this.name=a.name,this.init(b)},d.prototype={init:function(a){this.base=a,this.button=this.createButton(),this.base.on(this.button,"click",this.handleClick.bind(this))},getButton:function(){return this.button},getAction:function(){return"function"==typeof this.options.action?this.options.action(this.base.options):this.options.action},getAria:function(){return"function"==typeof this.options.aria?this.options.aria(this.base.options):this.options.aria},getTagNames:function(){return"function"==typeof this.options.tagNames?this.options.tagNames(this.base.options):this.options.tagNames},createButton:function(){var a=this.base.options.ownerDocument.createElement("button"),b=this.options.contentDefault;return a.classList.add("medium-editor-action"),a.classList.add("medium-editor-action-"+this.name),a.setAttribute("data-action",this.getAction()),a.setAttribute("aria-label",this.getAria()),this.base.options.buttonLabels&&("fontawesome"===this.base.options.buttonLabels&&this.options.contentFA?b=this.options.contentFA:"object"==typeof this.base.options.buttonLabels&&this.base.options.buttonLabels[this.name]&&(b=this.base.options.buttonLabels[this.options.name])),a.innerHTML=b,a},handleClick:function(a){a.preventDefault(),a.stopPropagation();var b=this.getAction();this.base.selection||this.base.checkSelection(),this.isActive()?this.deactivate():this.activate(),b&&this.base.execAction(b,a)},isActive:function(){return this.button.classList.contains(this.base.options.activeButtonClass)},deactivate:function(){this.button.classList.remove(this.base.options.activeButtonClass),delete this.knownState},activate:function(){this.button.classList.add(this.base.options.activeButtonClass),delete this.knownState},queryCommandState:function(){var a=null;if(this.options.useQueryState)try{a=this.base.options.ownerDocument.queryCommandState(this.getAction())}catch(b){a=null}return a},shouldActivate:function(a){var b,c=!1,d=this.getTagNames();return this.knownState===!1||this.knownState===!0?this.knownState:(d&&d.length>0&&a.tagName&&(c=-1!==d.indexOf(a.tagName.toLowerCase())),!c&&this.options.style&&(b=this.options.style.value.split("|"),b.forEach(function(b){return this.knownState=c=-1!==this.base.options.contentWindow.getComputedStyle(a,null).getPropertyValue(this.options.style.prop).indexOf(b),this.knownState?!1:void 0}.bind(this))),c)}}}(window,document);var f;return function(){function a(){return[[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|font-weight:bold;font-style:italic)[^>]*>/gi),''],[new RegExp(/]*font-style:italic[^>]*>/gi),''],[new RegExp(/]*font-weight:bold[^>]*>/gi),''],[new RegExp(/<(\/?)(i|b|a)>/gi),"<$1$2>"],[new RegExp(/<a\s+href=("|”|“|“|”)([^&]+)("|”|“|“|”)>/gi),'']]}f={handlePaste:function(a,c,d){var e,f,g="",h="text/html",i="text/plain";if(a.classList.remove("medium-editor-placeholder"),!d.forcePlainText&&!d.cleanPastedHTML)return a;if(d.contentWindow.clipboardData&&void 0===c.clipboardData&&(c.clipboardData=d.contentWindow.clipboardData,h="Text",i="Text"),c.clipboardData&&c.clipboardData.getData&&!c.defaultPrevented){if(c.preventDefault(),d.cleanPastedHTML&&c.clipboardData.getData(h))return this.cleanPaste(c.clipboardData.getData(h),d);if(d.disableReturn||a.getAttribute("data-disable-return"))g=b.htmlEntities(c.clipboardData.getData(i)),b.insertHTMLCommand(d.ownerDocument,g);else{for(e=c.clipboardData.getData(i).split(/[\r\n]/g),f=0;f"+b.htmlEntities(e[f])+"

");b.insertHTMLCommand(d.ownerDocument,g)}}},cleanPaste:function(d,e){var f,g,h,i=c.getSelectionElement(e.contentWindow),j=/
"),this.pasteHTML("

"+g.join("

")+"

",e.ownerDocument),e.ownerDocument.execCommand("insertText",!1,"\n"),g=i.querySelectorAll("a,p,div,br"),f=0;f"+e.innerHTML+"":e.innerHTML,e.parentNode.replaceChild(f,e);for(g=a.querySelectorAll("span"),d=0;de;e+=1)if(g=this.events[e],g[0]===a&&g[1]===b&&g[2]===c&&g[3]===d)return e;return-1},delay:function(a){var b=this;setTimeout(function(){b.isActive&&a()},this.options.delay)},removeAllEvents:function(){for(var a=this.events.pop();a;)a[0].removeEventListener(a[1],a[2],a[3]),a=this.events.pop()},initThrottledMethods:function(){var a=this;return this.handleResize=b.throttle(function(){a.isActive&&a.positionToolbarIfShown()}),this.handleBlur=b.throttle(function(){a.isActive&&!a.keepToolbarAlive&&a.hideToolbarActions()}),this},initElements:function(){var a,b=!1;for(a=0;a)?$/i,j=/h\d/i;(a.which===b.keyCode.BACKSPACE||a.which===b.keyCode.ENTER)&&g.previousElementSibling&&j.test(h)&&0===c.getCaretOffsets(g).left?a.which===b.keyCode.BACKSPACE&&i.test(g.previousElementSibling.innerHTML)?(g.previousElementSibling.parentNode.removeChild(g.previousElementSibling),a.preventDefault()):a.which===b.keyCode.ENTER&&(f=this.options.ownerDocument.createElement("p"),f.innerHTML="
",g.previousElementSibling.parentNode.insertBefore(f,g),a.preventDefault()):a.which===b.keyCode.DELETE&&g.nextElementSibling&&g.previousElementSibling&&!j.test(h)&&i.test(g.innerHTML)&&j.test(g.nextElementSibling.tagName)&&(d=document.createRange(),e=window.getSelection(),d.setStart(g.nextElementSibling,0),d.collapse(!0),e.removeAllRanges(),e.addRange(d),g.previousElementSibling.parentNode.removeChild(g),a.preventDefault())},initToolbar:function(){return this.toolbar?this:(this.toolbar=this.createToolbar(),this.keepToolbarAlive=!1,this.toolbarActions=this.toolbar.querySelector(".medium-editor-toolbar-actions"),this.anchorPreview=this.createAnchorPreview(),this.options.disableAnchorForm||(this.anchorForm=this.toolbar.querySelector(".medium-editor-toolbar-form"),this.anchorInput=this.anchorForm.querySelector("input.medium-editor-toolbar-input"),this.anchorTarget=this.anchorForm.querySelector("input.medium-editor-toolbar-anchor-target"),this.anchorButton=this.anchorForm.querySelector("input.medium-editor-toolbar-anchor-button")),this.addExtensionForms(),this)},createToolbar:function(){var a=this.options.ownerDocument.createElement("div");return a.id="medium-editor-toolbar-"+this.id,a.className="medium-editor-toolbar",a.className+=this.options.staticToolbar?" static-toolbar":" stalker-toolbar",a.appendChild(this.toolbarButtons()),this.options.disableAnchorForm||a.appendChild(this.toolbarFormAnchor()),this.options.elementsContainer.appendChild(a),a},toolbarButtons:function(){var a,c,d=this.options.ownerDocument.createElement("ul");return d.id="medium-editor-toolbar-actions"+this.id,d.className="medium-editor-toolbar-actions clearfix",this.commands.forEach(function(e){"function"==typeof e.getButton&&(c=e.getButton(this),a=this.options.ownerDocument.createElement("li"),b.isElement(c)?a.appendChild(c):a.innerHTML=c,d.appendChild(a))}.bind(this)),d},addExtensionForms:function(){var a,b;this.commands.forEach(function(c){c.hasForm&&(a="function"==typeof c.getForm?c.getForm():null),a&&(b="medium-editor-toolbar-form-"+c.name+"-"+this.id,a.className+=" medium-editor-toolbar-form",a.id=b,this.toolbar.appendChild(a))}.bind(this))},toolbarFormAnchor:function(){var a=this.options.ownerDocument.createElement("div"),b=this.options.ownerDocument.createElement("input"),c=this.options.ownerDocument.createElement("label"),d=this.options.ownerDocument.createElement("input"),e=this.options.ownerDocument.createElement("label"),f=this.options.ownerDocument.createElement("input"),g=this.options.ownerDocument.createElement("a"),h=this.options.ownerDocument.createElement("a");return g.setAttribute("href","#"),g.className="medium-editor-toobar-close",g.innerHTML="×",h.setAttribute("href","#"),h.className="medium-editor-toobar-save",h.innerHTML="✓",b.setAttribute("type","text"),b.className="medium-editor-toolbar-input",b.setAttribute("placeholder",this.options.anchorInputPlaceholder),d.setAttribute("type","checkbox"),d.className="medium-editor-toolbar-anchor-target",c.innerHTML=this.options.anchorInputCheckboxLabel,c.insertBefore(d,c.firstChild),f.setAttribute("type","checkbox"),f.className="medium-editor-toolbar-anchor-button",e.innerHTML="Button",e.insertBefore(f,e.firstChild),a.className="medium-editor-toolbar-form",a.id="medium-editor-toolbar-form-anchor-"+this.id,a.appendChild(b),a.appendChild(h),a.appendChild(g),this.options.anchorTarget&&a.appendChild(c),this.options.anchorButton&&a.appendChild(e),a},bindSelect:function(){var a,b,c=this;for(this.checkSelectionWrapper=function(a){return!c.options.disableAnchorForm&&a&&c.clickingIntoArchorForm(a)?!1:void c.checkSelection()},b=function(a){setTimeout(function(){this.checkSelectionWrapper(a)}.bind(this),0)}.bind(this),this.on(this.options.ownerDocument.documentElement,"mouseup",this.checkSelectionWrapper),a=0;a'),c.onload=function(){var a=document.getElementById(d);a&&(a.removeAttribute("id"),a.removeAttribute("class"),a.src=c.result)}}}),this.classList.remove(c)},a=0;a<\/[\S]+>/gim,""),b=a.match(/<(p|h[0-6]|blockquote)>([\s\S]*?)<\/(p|h[0-6]|blockquote)>/g);return b?b.length:0},checkSelectionElement:function(a,d){var e,f,g,h=0;if(this.selection=a,this.selectionRange=this.selection.getRangeAt(0),this.options.standardizeSelectionStart&&this.selectionRange.startContainer.nodeValue&&this.selectionRange.startOffset===this.selectionRange.startContainer.nodeValue.length&&(f=b.findAdjacentTextNodeWithContent(c.getSelectionElement(this.options.contentWindow),this.selectionRange.startContainer,this.options.ownerDocument))){for(h=0;0===f.nodeValue.substr(h,1).trim().length;)h+=1;g=this.options.ownerDocument.createRange(),g.setStart(f,h),g.setEnd(this.selectionRange.endContainer,this.selectionRange.endOffset),this.selection.removeAllRanges(),this.selection.addRange(g),this.selectionRange=g}for(e=0;eg+this.elements[0].offsetHeight-this.toolbar.offsetHeight?this.toolbar.style.top=g+this.elements[0].offsetHeight+"px":d>g-this.toolbar.offsetHeight?(this.toolbar.classList.add("sticky-toolbar"),this.toolbar.style.top="0px"):(this.toolbar.classList.remove("sticky-toolbar"),this.toolbar.style.top=g-this.toolbar.offsetHeight+"px"):this.toolbar.style.top=g-this.toolbar.offsetHeight+"px",this.toolbar.style.left=this.options.toolbarAlign?"left"===this.options.toolbarAlign?f.left+"px":"center"===this.options.toolbarAlign?l-k+"px":f.right-this.toolbar.offsetWidth+"px":l-k+"px"):i.isCollapsed||(a=i.getRangeAt(0),b=a.getBoundingClientRect(),c=(b.left+b.right)/2,b.topc?j+k+"px":this.options.contentWindow.innerWidth-c0&&(a[0].className+=" "+this.options.firstButtonClass,a[a.length-1].className+=" "+this.options.lastButtonClass),this},execAction:function(a,b){a.indexOf("append-")>-1?(this.execFormatBlock(a.replace("append-","")),this.setToolbarPosition(),this.setToolbarButtonStates()):"anchor"===a?this.options.disableAnchorForm||this.triggerAnchorAction(b):"image"===a?this.options.ownerDocument.execCommand("insertImage",!1,this.options.contentWindow.getSelection()):(this.options.ownerDocument.execCommand(a,!1,null),this.setToolbarPosition(),0===a.indexOf("justify")&&this.setToolbarButtonStates())},showForm:function(a){this.toolbarActions.style.display="none",this.saveSelection();var b=document.getElementById(a);b.style.display="block",this.setToolbarPosition(),this.keepToolbarAlive=!0},hideForm:function(a){var b=document.getElementById(a.id);b.style.display="none",this.showToolbarActions(),this.setToolbarPosition(),this.restoreSelection()},rangeSelectsSingleNode:function(a){var b=a.startContainer;return b===a.endContainer&&b.hasChildNodes()&&a.endOffset===a.startOffset+1},getSelectedParentElement:function(){var a=null,b=this.selectionRange;return a=this.rangeSelectsSingleNode(b)&&3!==b.startContainer.childNodes[b.startOffset].nodeType?b.startContainer.childNodes[b.startOffset]:3===b.startContainer.nodeType?b.startContainer.parentNode:b.startContainer},triggerAnchorAction:function(){var a=c.getSelectedParentElement(this.selectionRange);return a.tagName&&"a"===a.tagName.toLowerCase()?this.options.ownerDocument.execCommand("unlink",!1,null):this.anchorForm&&("block"===this.anchorForm.style.display?this.showToolbarActions():this.showAnchorForm()),this},execFormatBlock:function(a){var d=c.getSelectionData(this.selection.anchorNode);if("blockquote"===a&&d.el&&"blockquote"===d.el.parentNode.tagName.toLowerCase())return this.options.ownerDocument.execCommand("outdent",!1,null);if(d.tagName===a&&(a="p"),b.isIE){if("blockquote"===a)return this.options.ownerDocument.execCommand("indent",!1,a);a="<"+a+">"}return this.options.ownerDocument.execCommand("formatBlock",!1,a)},isToolbarShown:function(){return this.toolbar&&this.toolbar.classList.contains("medium-editor-toolbar-active")},showToolbar:function(){this.toolbar&&!this.isToolbarShown()&&(this.toolbar.classList.add("medium-editor-toolbar-active"),this.onShowToolbar&&this.onShowToolbar())},hideToolbar:function(){this.isToolbarShown()&&(this.toolbar.classList.remove("medium-editor-toolbar-active"),this.onHideToolbar&&this.onHideToolbar())},hideToolbarActions:function(){this.commands.forEach(function(a){a.onHide&&"function"==typeof a.onHide&&a.onHide()}),this.keepToolbarAlive=!1,this.hideToolbar()},showToolbarActions:function(){var a=this;this.anchorForm&&(this.anchorForm.style.display="none"),this.toolbarActions.style.display="block",this.keepToolbarAlive=!1,this.delay(function(){a.showToolbar()})},saveSelection:function(){this.selectionState=null;var a,c,d,e=this.options.contentWindow.getSelection(),f=-1;e.rangeCount>0&&(a=e.getRangeAt(0),c=a.cloneRange(),this.elements.forEach(function(c,d){return c===a.startContainer||b.isDescendant(c,a.startContainer)?(f=d,!1):void 0}),f>-1&&(c.selectNodeContents(this.elements[f]),c.setEnd(a.startContainer,a.startOffset),d=c.toString().length,this.selectionState={start:d,end:d+a.toString().length,editableElementIndex:f}))},restoreSelection:function(){if(this.selectionState){var a,b,c,d,e=this.elements[this.selectionState.editableElementIndex],f=0,g=this.options.ownerDocument.createRange(),h=[e],i=!1,j=!1;for(g.setStart(e,0),g.collapse(!0),a=h.pop();!j&&a;){if(3===a.nodeType)d=f+a.length,!i&&this.selectionState.start>=f&&this.selectionState.start<=d&&(g.setStart(a,this.selectionState.start-f),i=!0),i&&this.selectionState.end>=f&&this.selectionState.end<=d&&(g.setEnd(a,this.selectionState.end-f),j=!0),f=d;else for(b=a.childNodes.length-1;b>=0;)h.push(a.childNodes[b]),b-=1;j||(a=h.pop())}c=this.options.contentWindow.getSelection(),c.removeAllRanges(),c.addRange(g)}},showAnchorForm:function(a){this.anchorForm&&(this.toolbarActions.style.display="none",this.saveSelection(),this.anchorForm.style.display="block",this.setToolbarPosition(),this.keepToolbarAlive=!0,this.anchorInput.focus(),this.anchorInput.value=a||"")},bindAnchorForm:function(){if(!this.anchorForm)return this;var a=this.anchorForm.querySelector("a.medium-editor-toobar-close"),c=this.anchorForm.querySelector("a.medium-editor-toobar-save"),d=this;return this.on(this.anchorForm,"click",function(a){a.stopPropagation(),d.keepToolbarAlive=!0}),this.on(this.anchorInput,"keyup",function(a){var c,e=null;a.keyCode===b.keyCode.ENTER?(a.preventDefault(),c=d.options.anchorTarget&&d.anchorTarget.checked?"_blank":"_self",d.options.anchorButton&&d.anchorButton.checked&&(e=d.options.anchorButtonClass),d.createLink(this,c,e)):a.keyCode===b.keyCode.ESCAPE&&(a.preventDefault(),d.showToolbarActions(),d.restoreSelection())}),this.on(c,"click",function(a){var b,c=null;a.preventDefault(),b=d.options.anchorTarget&&d.anchorTarget.checked?"_blank":"_self",d.options.anchorButton&&d.anchorButton.checked&&(c=d.options.anchorButtonClass),d.createLink(d.anchorInput,b,c)},!0),this.on(this.anchorInput,"click",function(a){a.stopPropagation(),d.keepToolbarAlive=!0}),this.on(this.options.ownerDocument.body,"click",function(a){a.target===d.anchorForm||b.isDescendant(d.anchorForm,a.target)||b.isDescendant(d.toolbarActions,a.target)||(d.keepToolbarAlive=!1,d.checkSelection())},!0),this.on(this.options.ownerDocument.body,"focus",function(a){a.target===d.anchorForm||b.isDescendant(d.anchorForm,a.target)||b.isDescendant(d.toolbarActions,a.target)||(d.keepToolbarAlive=!1,d.checkSelection())},!0),this.on(a,"click",function(a){a.preventDefault(),d.showToolbarActions(),d.restoreSelection()}),this},hideAnchorPreview:function(){this.anchorPreview.classList.remove("medium-editor-anchor-preview-active")},showAnchorPreview:function(a){if(this.anchorPreview.classList.contains("medium-editor-anchor-preview-active")||a.getAttribute("data-disable-preview"))return!0;var b,c,d=this,e=40,f=a.getBoundingClientRect(),g=(f.left+f.right)/2;return d.anchorPreview.querySelector("i").textContent=a.attributes.href.value,b=d.anchorPreview.offsetWidth/2,c=d.options.diffLeft-b,d.observeAnchorPreview(a),d.anchorPreview.classList.add("medium-toolbar-arrow-over"),d.anchorPreview.classList.remove("medium-toolbar-arrow-under"),d.anchorPreview.style.top=Math.round(e+f.bottom-d.options.diffTop+this.options.contentWindow.pageYOffset-d.anchorPreview.offsetHeight)+"px",d.anchorPreview.style.left=b>g?c+b+"px":this.options.contentWindow.innerWidth-gb.options.anchorPreviewHideDelay&&(b.hideAnchorPreview(),clearInterval(g),b.off(b.anchorPreview,"mouseover",e),b.off(b.anchorPreview,"mouseout",f),b.off(a,"mouseover",e),b.off(a,"mouseout",f))},200);this.on(b.anchorPreview,"mouseover",e),this.on(b.anchorPreview,"mouseout",f),this.on(a,"mouseover",e),this.on(a,"mouseout",f)},createAnchorPreview:function(){var a=this,b=this.options.ownerDocument.createElement("div");return b.id="medium-editor-anchor-preview-"+this.id,b.className="medium-editor-anchor-preview",b.innerHTML=this.anchorPreviewTemplate(),this.options.elementsContainer.appendChild(b),this.on(b,"click",function(){a.anchorPreviewClickHandler()}),b},anchorPreviewTemplate:function(){return'
'},anchorPreviewClickHandler:function(){if(!this.options.disableAnchorForm&&this.activeAnchor){var a=this,b=this.options.ownerDocument.createRange(),c=this.options.contentWindow.getSelection();b.selectNodeContents(a.activeAnchor),c.removeAllRanges(),c.addRange(b),this.delay(function(){a.activeAnchor&&a.showAnchorForm(a.activeAnchor.attributes.href.value),a.keepToolbarAlive=!1})}this.hideAnchorPreview()},editorAnchorObserver:function(a){var b=this,c=!0,d=function(){c=!1,b.off(b.activeAnchor,"mouseout",d)};if(a.target&&"a"===a.target.tagName.toLowerCase()){if(!/href=["']\S+["']/.test(a.target.outerHTML)||/href=["']#\S+["']/.test(a.target.outerHTML))return!0;if(this.isToolbarShown())return!0;this.activeAnchor=a.target,this.on(this.activeAnchor,"mouseout",d),this.delay(function(){c&&b.showAnchorPreview(a.target)})}},bindAnchorPreview:function(){var a,b=this;for(this.editorAnchorObserverWrapper=function(a){b.editorAnchorObserver(a)},a=0;a0)break;d=f.nextNode()}return d},isDescendant:function(a,b){for(var c=b.parentNode;null!==c;){if(c===a)return!0;c=c.parentNode}return!1},isElement:function(a){return!(!a||1!==a.nodeType)},now:function(){return Date.now||(new Date).getTime()},throttle:function(a,c){var d,e,f,g,h=50,i=null,j=0;return c||0===c||(c=h),g=function(){j=b.now(),i=null,f=a.apply(d,e),i||(d=e=null)},function(){var h=b.now(),k=c-(h-j);return d=this,e=arguments,0>=k||k>c?(clearTimeout(i),i=null,j=h,f=a.apply(d,e),i||(d=e=null)):i||(i=setTimeout(g,k)),f}},traverseUp:function(a,b){do{if(1===a.nodeType){if(b(a))return a;if(a.getAttribute("data-medium-element"))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,h,i;if(b.queryCommandSupported("insertHTML"))try{return b.execCommand("insertHTML",!1,c)}catch(j){}if(d=a.getSelection(),d.getRangeAt&&d.rangeCount){for(e=d.getRangeAt(0),e.deleteContents(),f=b.createElement("div"),f.innerHTML=c,g=b.createDocumentFragment();f.firstChild;)h=f.firstChild,i=g.appendChild(h);e.insertNode(g),i&&(e=e.cloneRange(),e.setStartAfter(i),e.collapse(!0),d.removeAllRanges(),d.addRange(e))}},setTargetBlank:function(a){var b;if("a"===a.tagName.toLowerCase())a.target="_blank";else for(a=a.getElementsByTagName("a"),b=0;ba;a+=1)d.appendChild(b.getRangeAt(a).cloneContents());e=d.innerHTML}}else void 0!==this.options.ownerDocument.selection&&"Text"===this.options.ownerDocument.selection.type&&(e=this.options.ownerDocument.selection.createRange().htmlText);return e},getCaretOffsets:function(b,c){var d,e;return c||(c=a.getSelection().getRangeAt(0)),d=c.cloneRange(),e=c.cloneRange(),d.selectNodeContents(b),d.setEnd(c.endContainer,c.endOffset),e.selectNodeContents(b),e.setStart(c.endContainer,c.endOffset),{left:d.toString().length,right:e.toString().length}},rangeSelectsSingleNode:function(a){var b=a.startContainer;return b===a.endContainer&&b.hasChildNodes()&&a.endOffset===a.startOffset+1},getSelectedParentElement:function(a){var b=null;return b=this.rangeSelectsSingleNode(a)&&3!==a.startContainer.childNodes[a.startOffset].nodeType?a.startContainer.childNodes[a.startOffset]:3===a.startContainer.nodeType?a.startContainer.parentNode:a.startContainer},getSelectionData:function(a){var c;for(a&&a.tagName&&(c=a.tagName.toLowerCase());a&&-1===b.parentElements.indexOf(c);)a=a.parentNode,a&&a.tagName&&(c=a.tagName.toLowerCase());return{el:a,tagName:c}}}}(document,window);var d,e;!function(){e={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:''},anchor:{name:"anchor",action:"anchor",aria:"link",tagNames:["a"],contentDefault:"#",contentFA:''},image:{name:"image",action:"image",aria:"image",tagNames:["img"],contentDefault:"image",contentFA:''},quote:{name:"quote",action:"append-blockquote",aria:"blockquote",tagNames:["blockquote"],contentDefault:"",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:''},pre:{name:"pre",action:"append-pre",aria:"preformatted text",tagNames:["pre"],contentDefault:"0101",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"},useQueryState:!0,contentDefault:"C",contentFA:''},justifyFull:{name:"justifyFull",action:"justifyFull",aria:"full justify",tagNames:[],style:{prop:"text-align",value:"justify"},useQueryState:!0,contentDefault:"J",contentFA:''},justifyLeft:{name:"justifyLeft",action:"justifyLeft",aria:"left justify",tagNames:[],style:{prop:"text-align",value:"left"},useQueryState:!0,contentDefault:"L",contentFA:''},justifyRight:{name:"justifyRight",action:"justifyRight",aria:"right justify",tagNames:[],style:{prop:"text-align",value:"right"},useQueryState:!0,contentDefault:"R",contentFA:''},header1:{name:"header1",action:function(a){return"append-"+a.firstHeader},aria:function(a){return a.firstHeader},tagNames:function(a){return[a.firstHeader]},contentDefault:"H1"},header2:{name:"header2",action:function(a){return"append-"+a.secondHeader},aria:function(a){return a.secondHeader},tagNames:function(a){return[a.secondHeader]},contentDefault:"H2"}},d=function(a,b){this.options=a,this.name=a.name,this.init(b)},d.prototype={init:function(a){this.base=a,this.button=this.createButton(),this.base.on(this.button,"click",this.handleClick.bind(this))},getButton:function(){return this.button},getAction:function(){return"function"==typeof this.options.action?this.options.action(this.base.options):this.options.action},getAria:function(){return"function"==typeof this.options.aria?this.options.aria(this.base.options):this.options.aria},getTagNames:function(){return"function"==typeof this.options.tagNames?this.options.tagNames(this.base.options):this.options.tagNames},createButton:function(){var a=this.base.options.ownerDocument.createElement("button"),b=this.options.contentDefault;return a.classList.add("medium-editor-action"),a.classList.add("medium-editor-action-"+this.name),a.setAttribute("data-action",this.getAction()),a.setAttribute("aria-label",this.getAria()),this.base.options.buttonLabels&&("fontawesome"===this.base.options.buttonLabels&&this.options.contentFA?b=this.options.contentFA:"object"==typeof this.base.options.buttonLabels&&this.base.options.buttonLabels[this.name]&&(b=this.base.options.buttonLabels[this.options.name])),a.innerHTML=b,a},handleClick:function(a){a.preventDefault(),a.stopPropagation();var b=this.getAction();this.base.selection||this.base.checkSelection(),this.isActive()?this.deactivate():this.activate(),b&&this.base.execAction(b,a)},isActive:function(){return this.button.classList.contains(this.base.options.activeButtonClass)},deactivate:function(){this.button.classList.remove(this.base.options.activeButtonClass),delete this.knownState},activate:function(){this.button.classList.add(this.base.options.activeButtonClass),delete this.knownState},queryCommandState:function(){var a=null;if(this.options.useQueryState)try{a=this.base.options.ownerDocument.queryCommandState(this.getAction())}catch(b){a=null}return a},shouldActivate:function(a){var b,c,d=!1,e=this.getTagNames();return this.knownState===!1||this.knownState===!0?this.knownState:(e&&e.length>0&&a.tagName&&(d=-1!==e.indexOf(a.tagName.toLowerCase())),!d&&this.options.style&&(b=this.options.style.value.split("|"),c=this.base.options.contentWindow.getComputedStyle(a,null).getPropertyValue(this.options.style.prop),b.forEach(function(a){this.knownState||(this.knownState=d=-1!==c.indexOf(a))}.bind(this))),d)}}}(window,document);var f;!function(){function a(){return[[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|font-weight:bold;font-style:italic)[^>]*>/gi),''],[new RegExp(/]*font-style:italic[^>]*>/gi),''],[new RegExp(/]*font-weight:bold[^>]*>/gi),''],[new RegExp(/<(\/?)(i|b|a)>/gi),"<$1$2>"],[new RegExp(/<a\s+href=("|”|“|“|”)([^&]+)("|”|“|“|”)>/gi),'
']]}f={handlePaste:function(a,c,d){var e,f,g="",h="text/html",i="text/plain";if(a.classList.remove("medium-editor-placeholder"),!d.forcePlainText&&!d.cleanPastedHTML)return a;if(d.contentWindow.clipboardData&&void 0===c.clipboardData&&(c.clipboardData=d.contentWindow.clipboardData,h="Text",i="Text"),c.clipboardData&&c.clipboardData.getData&&!c.defaultPrevented){if(c.preventDefault(),d.cleanPastedHTML&&c.clipboardData.getData(h))return this.cleanPaste(c.clipboardData.getData(h),d);if(d.disableReturn||a.getAttribute("data-disable-return"))g=b.htmlEntities(c.clipboardData.getData(i)),b.insertHTMLCommand(d.ownerDocument,g);else{for(e=c.clipboardData.getData(i).split(/[\r\n]/g),f=0;f"+b.htmlEntities(e[f])+"

");b.insertHTMLCommand(d.ownerDocument,g)}}},cleanPaste:function(d,e){var f,g,h,i=c.getSelectionElement(e.contentWindow),j=/
"),this.pasteHTML("

"+g.join("

")+"

",e.ownerDocument),e.ownerDocument.execCommand("insertText",!1,"\n"),g=i.querySelectorAll("a,p,div,br"),f=0;f"+e.innerHTML+"":e.innerHTML,e.parentNode.replaceChild(f,e);for(g=a.querySelectorAll("span"),d=0;de;e+=1)if(g=this.events[e],g[0]===a&&g[1]===b&&g[2]===c&&g[3]===d)return e;return-1},delay:function(a){var b=this;setTimeout(function(){b.isActive&&a()},this.options.delay)},removeAllEvents:function(){for(var a=this.events.pop();a;)a[0].removeEventListener(a[1],a[2],a[3]),a=this.events.pop()},initThrottledMethods:function(){var a=this;return this.handleResize=b.throttle(function(){a.isActive&&a.positionToolbarIfShown()}),this.handleBlur=b.throttle(function(){a.isActive&&!a.keepToolbarAlive&&a.hideToolbarActions()}),this},initElements:function(){var a,b=!1;for(a=0;a)?$/i,j=/h\d/i;(a.which===b.keyCode.BACKSPACE||a.which===b.keyCode.ENTER)&&g.previousElementSibling&&j.test(h)&&0===c.getCaretOffsets(g).left?a.which===b.keyCode.BACKSPACE&&i.test(g.previousElementSibling.innerHTML)?(g.previousElementSibling.parentNode.removeChild(g.previousElementSibling),a.preventDefault()):a.which===b.keyCode.ENTER&&(f=this.options.ownerDocument.createElement("p"),f.innerHTML="
",g.previousElementSibling.parentNode.insertBefore(f,g),a.preventDefault()):a.which===b.keyCode.DELETE&&g.nextElementSibling&&g.previousElementSibling&&!j.test(h)&&i.test(g.innerHTML)&&j.test(g.nextElementSibling.tagName)&&(d=document.createRange(),e=window.getSelection(),d.setStart(g.nextElementSibling,0),d.collapse(!0),e.removeAllRanges(),e.addRange(d),g.previousElementSibling.parentNode.removeChild(g),a.preventDefault())},initToolbar:function(){return this.toolbar?this:(this.toolbar=this.createToolbar(),this.keepToolbarAlive=!1,this.toolbarActions=this.toolbar.querySelector(".medium-editor-toolbar-actions"),this.anchorPreview=this.createAnchorPreview(),this.addExtensionForms(),this)},createToolbar:function(){var a=this.options.ownerDocument.createElement("div");return a.id="medium-editor-toolbar-"+this.id,a.className="medium-editor-toolbar",a.className+=this.options.staticToolbar?" static-toolbar":" stalker-toolbar",a.appendChild(this.toolbarButtons()),this.options.disableAnchorForm||(this.anchorExtension=new g(this),a.appendChild(this.anchorExtension.getForm())),this.options.elementsContainer.appendChild(a),a},toolbarButtons:function(){var a,c,d=this.options.ownerDocument.createElement("ul");return d.id="medium-editor-toolbar-actions"+this.id,d.className="medium-editor-toolbar-actions clearfix",this.commands.forEach(function(e){"function"==typeof e.getButton&&(c=e.getButton(this),a=this.options.ownerDocument.createElement("li"),b.isElement(c)?a.appendChild(c):a.innerHTML=c,d.appendChild(a))}.bind(this)),d},addExtensionForms:function(){var a,b;this.commands.forEach(function(c){c.hasForm&&(a="function"==typeof c.getForm?c.getForm():null),a&&(b="medium-editor-toolbar-form-"+c.name+"-"+this.id,a.className+=" medium-editor-toolbar-form",a.id=b,this.toolbar.appendChild(a))}.bind(this))},bindSelect:function(){var a,b,c=this;for(this.checkSelectionWrapper=function(a){return a&&this.anchorExtension&&this.anchorExtension.isClickIntoForm(a)?!1:void c.checkSelection()},b=function(a){setTimeout(function(){this.checkSelectionWrapper(a)}.bind(this),0)}.bind(this),this.on(this.options.ownerDocument.documentElement,"mouseup",this.checkSelectionWrapper),a=0;a'),c.onload=function(){var a=document.getElementById(d);a&&(a.removeAttribute("id"),a.removeAttribute("class"),a.src=c.result)}}}),this.classList.remove(c)},a=0;a<\/[\S]+>/gim,""),b=a.match(/<(p|h[0-6]|blockquote)>([\s\S]*?)<\/(p|h[0-6]|blockquote)>/g);return b?b.length:0},checkSelectionElement:function(a,d){var e,f,g,h=0;if(this.selection=a,this.selectionRange=this.selection.getRangeAt(0),this.options.standardizeSelectionStart&&this.selectionRange.startContainer.nodeValue&&this.selectionRange.startOffset===this.selectionRange.startContainer.nodeValue.length&&(f=b.findAdjacentTextNodeWithContent(c.getSelectionElement(this.options.contentWindow),this.selectionRange.startContainer,this.options.ownerDocument))){for(h=0;0===f.nodeValue.substr(h,1).trim().length;)h+=1;g=this.options.ownerDocument.createRange(),g.setStart(f,h),g.setEnd(this.selectionRange.endContainer,this.selectionRange.endOffset),this.selection.removeAllRanges(),this.selection.addRange(g),this.selectionRange=g}for(e=0;eg+this.elements[0].offsetHeight-this.toolbar.offsetHeight?this.toolbar.style.top=g+this.elements[0].offsetHeight+"px":d>g-this.toolbar.offsetHeight?(this.toolbar.classList.add("sticky-toolbar"),this.toolbar.style.top="0px"):(this.toolbar.classList.remove("sticky-toolbar"),this.toolbar.style.top=g-this.toolbar.offsetHeight+"px"):this.toolbar.style.top=g-this.toolbar.offsetHeight+"px",this.toolbar.style.left=this.options.toolbarAlign?"left"===this.options.toolbarAlign?f.left+"px":"center"===this.options.toolbarAlign?l-k+"px":f.right-this.toolbar.offsetWidth+"px":l-k+"px"):i.isCollapsed||(a=i.getRangeAt(0),b=a.getBoundingClientRect(),c=(b.left+b.right)/2,b.topc?j+k+"px":this.options.contentWindow.innerWidth-c0&&(a[0].className+=" "+this.options.firstButtonClass,a[a.length-1].className+=" "+this.options.lastButtonClass),this},execAction:function(a,b){a.indexOf("append-")>-1?(this.execFormatBlock(a.replace("append-","")),this.setToolbarPosition(),this.setToolbarButtonStates()):"anchor"===a?this.options.disableAnchorForm||this.triggerAnchorAction(b):"image"===a?this.options.ownerDocument.execCommand("insertImage",!1,this.options.contentWindow.getSelection()):(this.options.ownerDocument.execCommand(a,!1,null),this.setToolbarPosition(),0===a.indexOf("justify")&&this.setToolbarButtonStates())},showForm:function(a){this.toolbarActions.style.display="none",this.saveSelection();var b=document.getElementById(a);b.style.display="block",this.setToolbarPosition(),this.keepToolbarAlive=!0},hideForm:function(a){var b=document.getElementById(a.id);b.style.display="none",this.showToolbarActions(),this.setToolbarPosition(),this.restoreSelection()},rangeSelectsSingleNode:function(a){var b=a.startContainer;return b===a.endContainer&&b.hasChildNodes()&&a.endOffset===a.startOffset+1},getSelectedParentElement:function(){var a=null,b=this.selectionRange;return a=this.rangeSelectsSingleNode(b)&&3!==b.startContainer.childNodes[b.startOffset].nodeType?b.startContainer.childNodes[b.startOffset]:3===b.startContainer.nodeType?b.startContainer.parentNode:b.startContainer},triggerAnchorAction:function(){var a=c.getSelectedParentElement(this.selectionRange);return a.tagName&&"a"===a.tagName.toLowerCase()?this.options.ownerDocument.execCommand("unlink",!1,null):this.anchorExtension&&(this.anchorExtension.isDisplayed()?this.showToolbarActions():this.showAnchorForm()),this},execFormatBlock:function(a){var d=c.getSelectionData(this.selection.anchorNode);if("blockquote"===a&&d.el&&"blockquote"===d.el.parentNode.tagName.toLowerCase())return this.options.ownerDocument.execCommand("outdent",!1,null);if(d.tagName===a&&(a="p"),b.isIE){if("blockquote"===a)return this.options.ownerDocument.execCommand("indent",!1,a);a="<"+a+">"}return this.options.ownerDocument.execCommand("formatBlock",!1,a)},isToolbarShown:function(){return this.toolbar&&this.toolbar.classList.contains("medium-editor-toolbar-active")},showToolbar:function(){this.toolbar&&!this.isToolbarShown()&&(this.toolbar.classList.add("medium-editor-toolbar-active"),this.onShowToolbar&&this.onShowToolbar())},hideToolbar:function(){this.isToolbarShown()&&(this.toolbar.classList.remove("medium-editor-toolbar-active"),this.onHideToolbar&&this.onHideToolbar())},hideToolbarActions:function(){this.commands.forEach(function(a){a.onHide&&"function"==typeof a.onHide&&a.onHide()}),this.keepToolbarAlive=!1,this.hideToolbar()},showToolbarActions:function(){var a=this;this.anchorExtension&&this.anchorExtension.hideForm(),this.toolbarActions.style.display="block",this.keepToolbarAlive=!1,this.delay(function(){a.showToolbar()})},saveSelection:function(){this.selectionState=null;var a,c,d,e=this.options.contentWindow.getSelection(),f=-1;e.rangeCount>0&&(a=e.getRangeAt(0),c=a.cloneRange(),this.elements.forEach(function(c,d){return c===a.startContainer||b.isDescendant(c,a.startContainer)?(f=d,!1):void 0}),f>-1&&(c.selectNodeContents(this.elements[f]),c.setEnd(a.startContainer,a.startOffset),d=c.toString().length,this.selectionState={start:d,end:d+a.toString().length,editableElementIndex:f}))},restoreSelection:function(){if(this.selectionState){var a,b,c,d,e=this.elements[this.selectionState.editableElementIndex],f=0,g=this.options.ownerDocument.createRange(),h=[e],i=!1,j=!1;for(g.setStart(e,0),g.collapse(!0),a=h.pop();!j&&a;){if(3===a.nodeType)d=f+a.length,!i&&this.selectionState.start>=f&&this.selectionState.start<=d&&(g.setStart(a,this.selectionState.start-f),i=!0),i&&this.selectionState.end>=f&&this.selectionState.end<=d&&(g.setEnd(a,this.selectionState.end-f),j=!0),f=d;else for(b=a.childNodes.length-1;b>=0;)h.push(a.childNodes[b]),b-=1;j||(a=h.pop())}c=this.options.contentWindow.getSelection(),c.removeAllRanges(),c.addRange(g)}},showAnchorForm:function(a){this.anchorExtension&&(this.toolbarActions.style.display="none",this.saveSelection(),this.anchorExtension.showForm(),this.setToolbarPosition(),this.keepToolbarAlive=!0,this.anchorExtension.focus(a))},hideAnchorPreview:function(){this.anchorPreview.classList.remove("medium-editor-anchor-preview-active")},showAnchorPreview:function(a){if(this.anchorPreview.classList.contains("medium-editor-anchor-preview-active")||a.getAttribute("data-disable-preview"))return!0;var b,c,d=this,e=40,f=a.getBoundingClientRect(),g=(f.left+f.right)/2;return d.anchorPreview.querySelector("i").textContent=a.attributes.href.value,b=d.anchorPreview.offsetWidth/2,c=d.options.diffLeft-b,d.observeAnchorPreview(a),d.anchorPreview.classList.add("medium-toolbar-arrow-over"),d.anchorPreview.classList.remove("medium-toolbar-arrow-under"),d.anchorPreview.style.top=Math.round(e+f.bottom-d.options.diffTop+this.options.contentWindow.pageYOffset-d.anchorPreview.offsetHeight)+"px",d.anchorPreview.style.left=b>g?c+b+"px":this.options.contentWindow.innerWidth-gb.options.anchorPreviewHideDelay&&(b.hideAnchorPreview(),clearInterval(g),b.off(b.anchorPreview,"mouseover",e),b.off(b.anchorPreview,"mouseout",f),b.off(a,"mouseover",e),b.off(a,"mouseout",f))},200);this.on(b.anchorPreview,"mouseover",e),this.on(b.anchorPreview,"mouseout",f),this.on(a,"mouseover",e),this.on(a,"mouseout",f)},createAnchorPreview:function(){var a=this,b=this.options.ownerDocument.createElement("div");return b.id="medium-editor-anchor-preview-"+this.id,b.className="medium-editor-anchor-preview",b.innerHTML=this.anchorPreviewTemplate(),this.options.elementsContainer.appendChild(b),this.on(b,"click",function(){a.anchorPreviewClickHandler()}),b},anchorPreviewTemplate:function(){return'
'},anchorPreviewClickHandler:function(){if(!this.options.disableAnchorForm&&this.activeAnchor){var a=this,b=this.options.ownerDocument.createRange(),c=this.options.contentWindow.getSelection();b.selectNodeContents(a.activeAnchor),c.removeAllRanges(),c.addRange(b),this.delay(function(){a.activeAnchor&&a.showAnchorForm(a.activeAnchor.attributes.href.value),a.keepToolbarAlive=!1})}this.hideAnchorPreview()},editorAnchorObserver:function(a){var b=this,c=!0,d=function(){c=!1,b.off(b.activeAnchor,"mouseout",d)};if(a.target&&"a"===a.target.tagName.toLowerCase()){if(!/href=["']\S+["']/.test(a.target.outerHTML)||/href=["']#\S+["']/.test(a.target.outerHTML))return!0;if(this.isToolbarShown())return!0;this.activeAnchor=a.target,this.on(this.activeAnchor,"mouseout",d),this.delay(function(){c&&b.showAnchorPreview(a.target)})}},bindAnchorPreview:function(){var a,b=this;for(this.editorAnchorObserverWrapper=function(a){b.editorAnchorObserver(a)},a=0;aU', contentFA: '' @@ -47,6 +51,10 @@ var DefaultButton, action: 'strikethrough', aria: 'strike through', tagNames: ['strike'], + style: { + prop: 'text-decoration', + value: 'line-through' + }, useQueryState: true, contentDefault: 'A', contentFA: '' @@ -307,7 +315,8 @@ var DefaultButton, shouldActivate: function (node) { var isMatch = false, tagNames = this.getTagNames(), - styleVals; + styleVals, + computedStyle; if (this.knownState === false || this.knownState === true) { return this.knownState; } @@ -318,10 +327,10 @@ var DefaultButton, if (!isMatch && this.options.style) { styleVals = this.options.style.value.split('|'); + computedStyle = this.base.options.contentWindow.getComputedStyle(node, null).getPropertyValue(this.options.style.prop); styleVals.forEach(function (val) { - this.knownState = isMatch = (this.base.options.contentWindow.getComputedStyle(node, null).getPropertyValue(this.options.style.prop).indexOf(val) !== -1); - if (this.knownState) { - return false; + if (!this.knownState) { + this.knownState = isMatch = (computedStyle.indexOf(val) !== -1); } }.bind(this)); } diff --git a/src/js/core.js b/src/js/core.js index 1070cc304..0a3a048bf 100644 --- a/src/js/core.js +++ b/src/js/core.js @@ -1,6 +1,6 @@ /*global module, console, define, FileReader, mediumEditorUtil, ButtonsData, DefaultButton, - pasteHandler, meSelection*/ + pasteHandler, meSelection, AnchorExtension */ function MediumEditor(elements, options) { 'use strict'; @@ -12,7 +12,8 @@ function MediumEditor(elements, options) { MediumEditor.statics = { ButtonsData: ButtonsData, - DefaultButton: DefaultButton + DefaultButton: DefaultButton, + AnchorExtension: AnchorExtension }; MediumEditor.prototype = { @@ -178,7 +179,6 @@ function MediumEditor(elements, options) { if (addToolbar) { this.initToolbar() .bindButtons() - .bindAnchorForm() .bindAnchorPreview(); } return this; @@ -533,13 +533,6 @@ function MediumEditor(elements, options) { this.toolbarActions = this.toolbar.querySelector('.medium-editor-toolbar-actions'); this.anchorPreview = this.createAnchorPreview(); - if (!this.options.disableAnchorForm) { - this.anchorForm = this.toolbar.querySelector('.medium-editor-toolbar-form'); - this.anchorInput = this.anchorForm.querySelector('input.medium-editor-toolbar-input'); - this.anchorTarget = this.anchorForm.querySelector('input.medium-editor-toolbar-anchor-target'); - this.anchorButton = this.anchorForm.querySelector('input.medium-editor-toolbar-anchor-button'); - } - this.addExtensionForms(); return this; @@ -558,7 +551,8 @@ function MediumEditor(elements, options) { toolbar.appendChild(this.toolbarButtons()); if (!this.options.disableAnchorForm) { - toolbar.appendChild(this.toolbarFormAnchor()); + this.anchorExtension = new AnchorExtension(this); + toolbar.appendChild(this.anchorExtension.getForm()); } this.options.elementsContainer.appendChild(toolbar); return toolbar; @@ -606,58 +600,6 @@ function MediumEditor(elements, options) { }.bind(this)); }, - toolbarFormAnchor: function () { - var anchor = this.options.ownerDocument.createElement('div'), - input = this.options.ownerDocument.createElement('input'), - target_label = this.options.ownerDocument.createElement('label'), - target = this.options.ownerDocument.createElement('input'), - button_label = this.options.ownerDocument.createElement('label'), - button = this.options.ownerDocument.createElement('input'), - close = this.options.ownerDocument.createElement('a'), - save = this.options.ownerDocument.createElement('a'); - - close.setAttribute('href', '#'); - close.className = 'medium-editor-toobar-close'; - close.innerHTML = '×'; - - save.setAttribute('href', '#'); - save.className = 'medium-editor-toobar-save'; - save.innerHTML = '✓'; - - input.setAttribute('type', 'text'); - input.className = 'medium-editor-toolbar-input'; - input.setAttribute('placeholder', this.options.anchorInputPlaceholder); - - - target.setAttribute('type', 'checkbox'); - target.className = 'medium-editor-toolbar-anchor-target'; - target_label.innerHTML = this.options.anchorInputCheckboxLabel; - target_label.insertBefore(target, target_label.firstChild); - - button.setAttribute('type', 'checkbox'); - button.className = 'medium-editor-toolbar-anchor-button'; - button_label.innerHTML = "Button"; - button_label.insertBefore(button, button_label.firstChild); - - - anchor.className = 'medium-editor-toolbar-form'; - anchor.id = 'medium-editor-toolbar-form-anchor-' + this.id; - anchor.appendChild(input); - - anchor.appendChild(save); - anchor.appendChild(close); - - if (this.options.anchorTarget) { - anchor.appendChild(target_label); - } - - if (this.options.anchorButton) { - anchor.appendChild(button_label); - } - - return anchor; - }, - bindSelect: function () { var self = this, i, @@ -665,7 +607,7 @@ function MediumEditor(elements, options) { this.checkSelectionWrapper = function (e) { // Do not close the toolbar when bluring the editable area and clicking into the anchor form - if (!self.options.disableAnchorForm && e && self.clickingIntoArchorForm(e)) { + if (e && this.anchorExtension && this.anchorExtension.isClickIntoForm(e)) { return false; } @@ -806,7 +748,7 @@ function MediumEditor(elements, options) { if (!this.options.staticToolbar) { this.hideToolbarActions(); - } else if (this.anchorForm && this.anchorForm.style.display === 'block') { + } else if (this.anchorExtension && this.anchorExtension.isDisplayed()) { this.setToolbarButtonStates(); this.showToolbarActions(); } @@ -825,16 +767,6 @@ function MediumEditor(elements, options) { return this; }, - clickingIntoArchorForm: function (e) { - var self = this; - - if (e.type && e.type.toLowerCase() === 'blur' && e.relatedTarget && e.relatedTarget === self.anchorInput) { - return true; - } - - return false; - }, - hasMultiParagraphs: function () { var selectionHtml = meSelection.getSelectionHtml.call(this).replace(/<[\S]+><\/[\S]+>/gim, ''), hasMultiParagraphs = selectionHtml.match(/<(p|h[0-6]|blockquote)>([\s\S]*?)<\/(p|h[0-6]|blockquote)>/g); @@ -1126,8 +1058,8 @@ function MediumEditor(elements, options) { if (selectedParentElement.tagName && selectedParentElement.tagName.toLowerCase() === 'a') { this.options.ownerDocument.execCommand('unlink', false, null); - } else if (this.anchorForm) { - if (this.anchorForm.style.display === 'block') { + } else if (this.anchorExtension) { + if (this.anchorExtension.isDisplayed()) { this.showToolbarActions(); } else { this.showAnchorForm(); @@ -1196,8 +1128,8 @@ function MediumEditor(elements, options) { showToolbarActions: function () { var self = this; - if (this.anchorForm) { - this.anchorForm.style.display = 'none'; + if (this.anchorExtension) { + this.anchorExtension.hideForm(); } this.toolbarActions.style.display = 'block'; this.keepToolbarAlive = false; @@ -1299,100 +1231,16 @@ function MediumEditor(elements, options) { }, showAnchorForm: function (link_value) { - if (!this.anchorForm) { + if (!this.anchorExtension) { return; } this.toolbarActions.style.display = 'none'; this.saveSelection(); - this.anchorForm.style.display = 'block'; + this.anchorExtension.showForm(); this.setToolbarPosition(); this.keepToolbarAlive = true; - this.anchorInput.focus(); - this.anchorInput.value = link_value || ''; - }, - - bindAnchorForm: function () { - if (!this.anchorForm) { - return this; - } - - var linkCancel = this.anchorForm.querySelector('a.medium-editor-toobar-close'), - linkSave = this.anchorForm.querySelector('a.medium-editor-toobar-save'), - self = this; - - this.on(this.anchorForm, 'click', function (e) { - e.stopPropagation(); - self.keepToolbarAlive = true; - }); - - this.on(this.anchorInput, 'keyup', function (e) { - var button = null, - target; - - if (e.keyCode === mediumEditorUtil.keyCode.ENTER) { - e.preventDefault(); - if (self.options.anchorTarget && self.anchorTarget.checked) { - target = "_blank"; - } else { - target = "_self"; - } - - if (self.options.anchorButton && self.anchorButton.checked) { - button = self.options.anchorButtonClass; - } - - self.createLink(this, target, button); - } else if (e.keyCode === mediumEditorUtil.keyCode.ESCAPE) { - e.preventDefault(); - self.showToolbarActions(); - self.restoreSelection(); - } - }); - - this.on(linkSave, 'click', function (e) { - var button = null, - target; - e.preventDefault(); - if (self.options.anchorTarget && self.anchorTarget.checked) { - target = "_blank"; - } else { - target = "_self"; - } - - if (self.options.anchorButton && self.anchorButton.checked) { - button = self.options.anchorButtonClass; - } - - self.createLink(self.anchorInput, target, button); - }, true); - - this.on(this.anchorInput, 'click', function (e) { - // make sure not to hide form when cliking into the input - e.stopPropagation(); - self.keepToolbarAlive = true; - }); - - // Hide the anchor form when focusing outside of it. - this.on(this.options.ownerDocument.body, 'click', function (e) { - if (e.target !== self.anchorForm && !mediumEditorUtil.isDescendant(self.anchorForm, e.target) && !mediumEditorUtil.isDescendant(self.toolbarActions, e.target)) { - self.keepToolbarAlive = false; - self.checkSelection(); - } - }, true); - this.on(this.options.ownerDocument.body, 'focus', function (e) { - if (e.target !== self.anchorForm && !mediumEditorUtil.isDescendant(self.anchorForm, e.target) && !mediumEditorUtil.isDescendant(self.toolbarActions, e.target)) { - self.keepToolbarAlive = false; - self.checkSelection(); - } - }, true); - - this.on(linkCancel, 'click', function (e) { - e.preventDefault(); - self.showToolbarActions(); - self.restoreSelection(); - }); - return this; + this.anchorExtension.focus(link_value); }, hideAnchorPreview: function () { @@ -1509,7 +1357,7 @@ function MediumEditor(elements, options) { sel.removeAllRanges(); sel.addRange(range); // Using setTimeout + options.delay because: - // We may actually be displaying the anchor preview, which should be controlled by options.delay + // We may actually be displaying the anchor form, which should be controlled by options.delay this.delay(function () { if (self.activeAnchor) { self.showAnchorForm(self.activeAnchor.attributes.href.value); @@ -1695,6 +1543,10 @@ function MediumEditor(elements, options) { } }.bind(this)); + if (this.anchorExtension) { + this.anchorExtension.deactivate(); + } + this.removeAllEvents(); }, diff --git a/src/js/extension-anchor.js b/src/js/extension-anchor.js new file mode 100644 index 000000000..6772ab256 --- /dev/null +++ b/src/js/extension-anchor.js @@ -0,0 +1,205 @@ +/*global mediumEditorUtil, console */ + +var AnchorExtension; + +(function (window, document) { + 'use strict'; + + AnchorExtension = function (instance) { + this.base = instance; + }; + + AnchorExtension.prototype = { + + getForm: function () { + if (!this.anchorForm) { + this.anchorForm = this.createForm(); + } + return this.anchorForm; + }, + + getInput: function () { + return this.getForm().querySelector('input.medium-editor-toolbar-input'); + }, + + deactivate: function () { + if (!this.anchorForm) { + return false; + } + + if (this.anchorForm.parentNode) { + this.anchorForm.parentNode.removeChild(this.anchorForm); + } + + delete this.anchorForm; + }, + + doLinkCreation: function () { + var button = null, + target, + targetCheckbox = this.getForm().querySelector('.medium-editor-toolbar-anchor-target'), + buttonCheckbox = this.getForm().querySelector('.medium-editor-toolbar-anchor-button'); + + if (targetCheckbox && targetCheckbox.checked) { + target = "_blank"; + } else { + target = "_self"; + } + + if (buttonCheckbox && buttonCheckbox.checked) { + button = this.base.options.anchorButtonClass; + } + + this.base.createLink(this.getInput(), target, button); + }, + + doFormCancel: function () { + this.base.showToolbarActions(); + this.base.restoreSelection(); + }, + + handleOutsideInteraction: function (event) { + if (event.target !== this.getForm() && + !mediumEditorUtil.isDescendant(this.getForm(), event.target) && + !mediumEditorUtil.isDescendant(this.base.toolbarActions, event.target)) { + this.base.keepToolbarAlive = false; + this.base.checkSelection(); + } + }, + + createForm: function () { + var doc = this.base.options.ownerDocument, + form = doc.createElement('div'), + input = doc.createElement('input'), + close = doc.createElement('a'), + save = doc.createElement('a'), + target, + target_label, + button, + button_label; + + // Anchor Form (div) + form.className = 'medium-editor-toolbar-form'; + form.id = 'medium-editor-toolbar-form-anchor-' + this.base.id; + + // Handle clicks on the form itself + this.base.on(form, 'click', function (event) { + event.stopPropagation(); + this.base.keepToolbarAlive = true; + }.bind(this)); + + // Add url textbox + input.setAttribute('type', 'text'); + input.className = 'medium-editor-toolbar-input'; + input.setAttribute('placeholder', this.base.options.anchorInputPlaceholder); + form.appendChild(input); + + // Handle typing in the textbox + this.base.on(input, 'keyup', function (event) { + // For ENTER -> create the anchor + if (event.keyCode === mediumEditorUtil.keyCode.ENTER) { + event.preventDefault(); + this.doLinkCreation(); + return; + } + + // For ESCAPE -> close the form + if (event.keyCode === mediumEditorUtil.keyCode.ESCAPE) { + event.preventDefault(); + this.doFormCancel(); + } + }.bind(this)); + + // Handle clicks into the textbox + this.base.on(input, 'click', function (event) { + // make sure not to hide form when cliking into the input + event.stopPropagation(); + this.base.keepToolbarAlive = true; + }.bind(this)); + + // Add save buton + save.setAttribute('href', '#'); + save.className = 'medium-editor-toobar-save'; + save.innerHTML = '✓'; + form.appendChild(save); + + // Handle save button clicks (capture) + this.base.on(save, 'click', function (event) { + // Clicking Save -> create the anchor + event.preventDefault(); + this.doLinkCreation(); + }.bind(this), true); + + // Add close button + close.setAttribute('href', '#'); + close.className = 'medium-editor-toobar-close'; + close.innerHTML = '×'; + form.appendChild(close); + + // Handle close button clicks + this.base.on(close, 'click', function (event) { + // Click Close -> close the form + event.preventDefault(); + this.doFormCancel(); + }.bind(this)); + + // (Optional) Add 'open in new window' checkbox + if (this.base.options.anchorTarget) { + target = doc.createElement('input'); + target.setAttribute('type', 'checkbox'); + target.className = 'medium-editor-toolbar-anchor-target'; + + target_label = doc.createElement('label'); + target_label.innerHTML = this.base.options.anchorInputCheckboxLabel; + target_label.insertBefore(target, target_label.firstChild); + + form.appendChild(target_label); + } + + // (Optional) Add 'add button class to anchor' checkbox + if (this.base.options.anchorButton) { + button = doc.createElement('input'); + button.setAttribute('type', 'checkbox'); + button.className = 'medium-editor-toolbar-anchor-button'; + + button_label = doc.createElement('label'); + button_label.innerHTML = "Button"; + button_label.insertBefore(button, button_label.firstChild); + + form.appendChild(button_label); + } + + // Handle click (capture) & focus (capture) outside of the form + this.base.on(doc.body, 'click', this.handleOutsideInteraction.bind(this), true); + this.base.on(doc.body, 'focus', this.handleOutsideInteraction.bind(this), true); + + return form; + }, + + focus: function (value) { + var input = this.getInput(); + input.focus(); + input.value = value || ''; + }, + + hideForm: function () { + this.getForm().style.display = 'none'; + }, + + showForm: function () { + this.getForm().style.display = 'block'; + }, + + isDisplayed: function () { + return this.getForm().style.display === 'block'; + }, + + isClickIntoForm: function (event) { + return (event && + event.type && + event.type.toLowerCase() === 'blur' && + event.relatedTarget && + event.relatedTarget === this.getInput()); + } + }; +}(window, document)); \ No newline at end of file