diff --git a/README.md b/README.md
index d5b71a8d6..b1adb2dcd 100644
--- a/README.md
+++ b/README.md
@@ -186,6 +186,7 @@ Check out the Wiki page for a list of available themes: [https://github.com/davi
* __.execAction(action, opts)__: executes an built-in action via `document.execCommand`
* __.createLink(opts)__: creates a link via the native `document.execCommand('createLink')` command
* __.subscribe(event, listener)__: attaches a listener to a custom medium-editor event
+* __.unsubscribe(event, listener)__: detaches a listener from a custom medium-editor event
* __.saveSelection()__: internally store the set of selected text
* __.restoreSelection()__: restore the selection to what was selected when `saveSelection()` was called
* __.selectAllContents()__: expands the selection to contain all text within the focused contenteditable
diff --git a/dist/js/medium-editor.js b/dist/js/medium-editor.js
index 040ade67f..ee5feba7c 100644
--- a/dist/js/medium-editor.js
+++ b/dist/js/medium-editor.js
@@ -1356,21 +1356,42 @@ var Events;
},
// custom events
- attachCustomEvent: function (event, handler) {
+ attachCustomEvent: function (event, listener) {
this.setupListener(event);
// If we don't suppot this custom event, don't do anything
if (this.listeners[event]) {
if (!this.customEvents[event]) {
this.customEvents[event] = [];
}
- this.customEvents[event].push(handler);
+ this.customEvents[event].push(listener);
}
},
+ detachCustomEvent: function (event, listener) {
+ var index = this.indexOfCustomListener(event, listener);
+ if (index !== -1) {
+ this.customEvents[event].splice(index, 1);
+ // TODO: If array is empty, should detach internal listeners via destoryListener()
+ }
+ },
+
+ indexOfCustomListener: function (event, listener) {
+ if (!this.customEvents[event] || !this.customEvents[event].length) {
+ return -1;
+ }
+
+ return this.customEvents[event].indexOf(listener);
+ },
+
+ detachAllCustomEvents: function () {
+ this.customEvents = {};
+ // TODO: Should detach internal listeners here via destroyListener()
+ },
+
triggerCustomEvent: function (name, data, editable) {
if (this.customEvents[name]) {
- this.customEvents[name].forEach(function (handler) {
- handler(data, editable);
+ this.customEvents[name].forEach(function (listener) {
+ listener(data, editable);
});
}
},
@@ -3637,6 +3658,7 @@ function MediumEditor(elements, options) {
}, this);
this.events.detachAllDOMEvents();
+ this.events.detachAllCustomEvents();
},
on: function (target, event, listener, useCapture) {
@@ -3651,6 +3673,10 @@ function MediumEditor(elements, options) {
this.events.attachCustomEvent(event, listener);
},
+ unsubscribe: function (event, listener) {
+ this.events.detachCustomEvent(event, listener);
+ },
+
delay: function (fn) {
var self = this;
return setTimeout(function () {
diff --git a/dist/js/medium-editor.min.js b/dist/js/medium-editor.min.js
index bd0f32812..d119fc3aa 100644
--- a/dist/js/medium-editor.min.js
+++ b/dist/js/medium-editor.min.js
@@ -1,2 +1,2 @@
-"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(++cA",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:''},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"},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:''},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"},removeFormat:{name:"removeFormat",aria:"remove formatting",action:"removeFormat",contentDefault:"X",contentFA:''}}}();var d;!function(){d={allowMultiParagraphSelection:!0,anchorInputPlaceholder:"Paste or type a link",anchorInputCheckboxLabel:"Open in new window",anchorPreviewHideDelay:500,buttons:["bold","italic","underline","anchor","header1","header2","quote"],buttonLabels:!1,checkLinkFormat:!1,delay:0,diffLeft:0,diffTop:-10,disableReturn:!1,disableDoubleReturn:!1,disableToolbar:!1,disableAnchorPreview:!1,disableEditing:!1,disablePlaceholders:!1,toolbarAlign:"center",elementsContainer:!1,imageDragging:!0,standardizeSelectionStart:!1,contentWindow:window,ownerDocument:document,firstHeader:"h3",placeholder:"Type your text",secondHeader:"h4",targetBlank:!1,anchorTarget:!1,anchorButton:!1,anchorButtonClass:"btn",extensions:{},activeButtonClass:"medium-editor-button-active",firstButtonClass:"medium-editor-button-first",lastButtonClass:"medium-editor-button-last",paste:{forcePlainText:!0,cleanPastedHtml:!1,cleanAttrs:["class","style","dir"],cleanTags:["meta"]}}}();var e;!function(){e=function(a){b.extend(this,a)},e.extend=function(a){var c,d=this;c=a&&a.hasOwnProperty("constructor")?a.constructor:function(){return d.apply(this,arguments)},b.extend(c,d);var e=function(){this.constructor=c};return e.prototype=d.prototype,c.prototype=new e,a&&b.extend(c.prototype,a),c},e.prototype={init:function(){}}}();var f;!function(){f={findMatchingSelectionParent:function(a,c){var d,e,f=c.getSelection();return 0===f.rangeCount?!1:(d=f.getRangeAt(0),e=d.commonAncestorContainer,b.traverseUp(e,a))},getSelectionElement:function(a){return this.findMatchingSelectionParent(function(a){return a.getAttribute("data-medium-element")},a)},selectionInContentEditableFalse:function(a){return this.findMatchingSelectionParent(function(a){return a&&"#text"!==a.nodeName&&"false"===a.getAttribute("contenteditable")},a)},getSelectionHtml:function(){var a,b,c,d="",e=this.options.contentWindow.getSelection();if(e.rangeCount){for(c=this.options.ownerDocument.createElement("div"),a=0,b=e.rangeCount;b>a;a+=1)c.appendChild(e.getRangeAt(a).cloneContents());d=c.innerHTML}return d},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){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},selectNode:function(a,b){var c=b.createRange(),d=b.getSelection();c.selectNodeContents(a),d.removeAllRanges(),d.addRange(c)}}}();var g;!function(){g=function(a){this.base=a,this.options=this.base.options,this.events=[],this.customEvents={},this.listeners={}},g.prototype={attachDOMEvent:function(a,b,c,d){a.addEventListener(b,c,d),this.events.push([a,b,c,d])},detachDOMEvent:function(a,b,c,d){var e,f=this.indexOfListener(a,b,c,d);-1!==f&&(e=this.events.splice(f,1)[0],e[0].removeEventListener(e[1],e[2],e[3]))},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()},attachCustomEvent:function(a,b){this.setupListener(a),this.listeners[a]&&(this.customEvents[a]||(this.customEvents[a]=[]),this.customEvents[a].push(b))},triggerCustomEvent:function(a,b,c){this.customEvents[a]&&this.customEvents[a].forEach(function(a){a(b,c)})},setupListener:function(a){if(!this.listeners[a])switch(a){case"externalInteraction":this.attachDOMEvent(this.options.ownerDocument.body,"click",this.handleInteraction.bind(this),!0),this.attachDOMEvent(this.options.ownerDocument.body,"focus",this.handleInteraction.bind(this),!0),this.listeners[a]=!0;break;case"blur":this.setupListener("externalInteraction"),this.listeners[a]=!0;break;case"focus":this.setupListener("externalInteraction"),this.listeners[a]=!0;break;case"editableClick":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"click",this.handleClick.bind(this))}.bind(this)),this.listeners[a]=!0;break;case"editableBlur":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"blur",this.handleBlur.bind(this))}.bind(this)),this.listeners[a]=!0;break;case"editableKeypress":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"keypress",this.handleKeypress.bind(this))}.bind(this)),this.listeners[a]=!0;break;case"editableKeyup":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"keyup",this.handleKeyup.bind(this))}.bind(this)),this.listeners[a]=!0;break;case"editableKeydown":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"keydown",this.handleKeydown.bind(this))}.bind(this)),this.listeners[a]=!0;break;case"editableKeydownEnter":this.setupListener("editableKeydown"),this.listeners[a]=!0;break;case"editableKeydownTab":this.setupListener("editableKeydown"),this.listeners[a]=!0;break;case"editableKeydownDelete":this.setupListener("editableKeydown"),this.listeners[a]=!0;break;case"editableMouseover":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"mouseover",this.handleMouseover.bind(this))},this),this.listeners[a]=!0;break;case"editableDrag":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"dragover",this.handleDragging.bind(this)),this.attachDOMEvent(a,"dragleave",this.handleDragging.bind(this))},this),this.listeners[a]=!0;break;case"editableDrop":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"drop",this.handleDrop.bind(this))},this),this.listeners[a]=!0;break;case"editablePaste":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"paste",this.handlePaste.bind(this))},this),this.listeners[a]=!0}},focusElement:function(a){a.focus(),this.updateFocus(a,{target:a,type:"focus"})},handleInteraction:function(a){this.updateFocus(a.target,a)},updateFocus:function(a,c){var d,e,g=this.options.contentWindow.getSelection(),h=this.base.toolbar?this.base.toolbar.getToolbarElement():null,i=this.base.getExtensionByName("anchor-preview"),j=i&&i.getPreviewElement?i.getPreviewElement():null,k=g.isCollapsed?null:f.getSelectedParentElement(g.getRangeAt(0));this.base.elements.some(function(c){return!d&&c.getAttribute("data-medium-focused")&&(d=c),e||!b.isDescendant(c,a,!0)&&!b.isDescendant(c,k)||(e=c),!!d&&!!e},this);var l=!b.isDescendant(d,a,!0)&&!b.isDescendant(h,a,!0)&&!b.isDescendant(j,a,!0);e!==d&&(d&&l&&(d.removeAttribute("data-medium-focused"),this.triggerCustomEvent("blur",c,d)),e&&(e.setAttribute("data-medium-focused",!0),this.triggerCustomEvent("focus",c,e))),l&&this.triggerCustomEvent("externalInteraction",c)},handleClick:function(a){this.triggerCustomEvent("editableClick",a,a.currentTarget)},handleBlur:function(a){this.triggerCustomEvent("editableBlur",a,a.currentTarget)},handleKeypress:function(a){this.triggerCustomEvent("editableKeypress",a,a.currentTarget)},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(a){switch(this.triggerCustomEvent("editableKeydown",a,a.currentTarget),a.which){case b.keyCode.ENTER:this.triggerCustomEvent("editableKeydownEnter",a,a.currentTarget);break;case b.keyCode.TAB:this.triggerCustomEvent("editableKeydownTab",a,a.currentTarget);break;case b.keyCode.DELETE:case b.keyCode.BACKSPACE:this.triggerCustomEvent("editableKeydownDelete",a,a.currentTarget)}}}}();var h;!function(){h=function(a,b){this.options=a,this.name=a.name,this.init(b)},h.prototype={init:function(a){this.base=a,this.button=this.createButton(),this.base.on(this.button,"click",this.handleClick.bind(this)),this.options.key&&this.base.subscribe("editableKeydown",this.handleKeydown.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},handleKeydown:function(a){var b,c;(a.ctrlKey||a.metaKey)&&(b=String.fromCharCode(a.which||a.keyCode).toLowerCase(),this.options.key===b&&(a.preventDefault(),a.stopPropagation(),c=this.getAction(),c&&this.base.execAction(c)))},handleClick:function(a){a.preventDefault(),a.stopPropagation();var b=this.getAction();b&&this.base.execAction(b)},isActive:function(){return this.button.classList.contains(this.base.options.activeButtonClass)},setInactive:function(){this.button.classList.remove(this.base.options.activeButtonClass),delete this.knownState},setActive:function(){this.button.classList.add(this.base.options.activeButtonClass),delete this.knownState},queryCommandState:function(){var a=null;return this.options.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&&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||(d=-1!==c.indexOf(a),(d||"text-decoration"!==this.options.style.prop)&&(this.knownState=d))},this)),d)}}}();var i;!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),''],[new RegExp(/<\/p>\n+/gi),"
/gi),""]]}i=function(a,b){this.base=a,this.options=b,(this.options.forcePlainText||this.options.cleanPastedHTML)&&this.base.subscribe("editablePaste",this.handlePaste.bind(this))},i.prototype={handlePaste:function(a,c){var d,e,f="",g="text/html",h="text/plain";if(this.options.contentWindow.clipboardData&&void 0===a.clipboardData&&(a.clipboardData=this.options.contentWindow.clipboardData,g="Text",h="Text"),a.clipboardData&&a.clipboardData.getData&&!a.defaultPrevented){if(a.preventDefault(),this.options.cleanPastedHTML&&a.clipboardData.getData(g))return this.cleanPaste(a.clipboardData.getData(g));if(this.options.disableReturn||c.getAttribute("data-disable-return"))f=b.htmlEntities(a.clipboardData.getData(h));else if(d=a.clipboardData.getData(h).split(/[\r\n]+/g),d.length>1)for(e=0;e
"),this.pasteHTML("
"+e.join("
")+"
");try{this.options.ownerDocument.execCommand("insertText",!1,"\n")}catch(k){}for(e=h.querySelectorAll("a,p,div,br"),d=0;d/gi),""]]}i=function(a,b){this.base=a,this.options=b,(this.options.forcePlainText||this.options.cleanPastedHTML)&&this.base.subscribe("editablePaste",this.handlePaste.bind(this))},i.prototype={handlePaste:function(a,c){var d,e,f="",g="text/html",h="text/plain";if(this.options.contentWindow.clipboardData&&void 0===a.clipboardData&&(a.clipboardData=this.options.contentWindow.clipboardData,g="Text",h="Text"),a.clipboardData&&a.clipboardData.getData&&!a.defaultPrevented){if(a.preventDefault(),this.options.cleanPastedHTML&&a.clipboardData.getData(g))return this.cleanPaste(a.clipboardData.getData(g));if(this.options.disableReturn||c.getAttribute("data-disable-return"))f=b.htmlEntities(a.clipboardData.getData(h));else if(d=a.clipboardData.getData(h).split(/[\r\n]+/g),d.length>1)for(e=0;e
"),this.pasteHTML("
"+e.join("
")+"
");try{this.options.ownerDocument.execCommand("insertText",!1,"\n")}catch(k){}for(e=h.querySelectorAll("a,p,div,br"),d=0;d