Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

medium-editor

Package Overview
Dependencies
Maintainers
1
Versions
125
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

medium-editor - npm Package Compare versions

Comparing version 1.7.5 to 1.8.0

demo/cleanpaste.html

2

bower.json
{
"name": "medium-editor",
"version": "1.7.5",
"version": "1.8.0",
"homepage": "http://daviferreira.github.io/medium-editor/",

@@ -5,0 +5,0 @@ "authors": [

@@ -0,1 +1,11 @@

1.8.0 / 2014-04-12
==================
* Removes anchor preview listeners on deactivate
* Implements clean paste
* Adds an option to validate links
* Adds a basic extensions support
* Misc minor fixes
1.7.5 / 2014-03-30

@@ -2,0 +12,0 @@ ==================

@@ -88,2 +88,7 @@ function MediumEditor(elements, options) {

// https://github.com/jashkenas/underscore
function isElement(obj) {
return !!(obj && obj.nodeType === 1);
}
MediumEditor.prototype = {

@@ -93,4 +98,7 @@ defaults: {

anchorInputPlaceholder: 'Paste or type a link',
anchorPreviewHideDelay: 500,
buttons: ['bold', 'italic', 'underline', 'anchor', 'header1', 'header2', 'quote'],
buttonLabels: false,
checkLinkFormat: false,
cleanPastedHTML: false,
delay: 0,

@@ -107,3 +115,3 @@ diffLeft: 0,

targetBlank: false,
anchorPreviewHideDelay: 500
extensions: {}
},

@@ -147,3 +155,3 @@

this.elements[i].setAttribute('data-medium-element', true);
this.bindParagraphCreation(i).bindReturn(i).bindTab(i).bindAnchorPreview(i);
this.bindParagraphCreation(i).bindReturn(i).bindTab(i);
if (!this.options.disableToolbar && !this.elements[i].getAttribute('data-disable-toolbar')) {

@@ -157,3 +165,4 @@ addToolbar = true;

.bindButtons()
.bindAnchorForm();
.bindAnchorForm()
.bindAnchorPreview();
}

@@ -176,2 +185,28 @@ return this;

/**
* Helper function to call a method with a number of parameters on all registered extensions.
* The function assures that the function exists before calling.
*
* @param {string} funcName name of the function to call
* @param [args] arguments passed into funcName
*/
callExtensions: function (funcName) {
if (arguments.length < 1) {
return;
}
var args = Array.prototype.slice.call(arguments, 1),
ext,
name;
for (name in this.options.extensions) {
if (this.options.extensions.hasOwnProperty(name)) {
ext = this.options.extensions[name];
if (ext[funcName] !== undefined) {
ext[funcName].apply(ext, args);
}
}
}
},
bindParagraphCreation: function (index) {

@@ -253,18 +288,18 @@ var self = this;

buttonTemplates = {
'bold': '<li><button class="medium-editor-action medium-editor-action-bold" data-action="bold" data-element="b">' + buttonLabels.bold + '</button></li>',
'italic': '<li><button class="medium-editor-action medium-editor-action-italic" data-action="italic" data-element="i">' + buttonLabels.italic + '</button></li>',
'underline': '<li><button class="medium-editor-action medium-editor-action-underline" data-action="underline" data-element="u">' + buttonLabels.underline + '</button></li>',
'strikethrough': '<li><button class="medium-editor-action medium-editor-action-strikethrough" data-action="strikethrough" data-element="strike"><strike>A</strike></button></li>',
'superscript': '<li><button class="medium-editor-action medium-editor-action-superscript" data-action="superscript" data-element="sup">' + buttonLabels.superscript + '</button></li>',
'subscript': '<li><button class="medium-editor-action medium-editor-action-subscript" data-action="subscript" data-element="sub">' + buttonLabels.subscript + '</button></li>',
'anchor': '<li><button class="medium-editor-action medium-editor-action-anchor" data-action="anchor" data-element="a">' + buttonLabels.anchor + '</button></li>',
'image': '<li><button class="medium-editor-action medium-editor-action-image" data-action="image" data-element="img">' + buttonLabels.image + '</button></li>',
'header1': '<li><button class="medium-editor-action medium-editor-action-header1" data-action="append-' + this.options.firstHeader + '" data-element="' + this.options.firstHeader + '">' + buttonLabels.header1 + '</button></li>',
'header2': '<li><button class="medium-editor-action medium-editor-action-header2" data-action="append-' + this.options.secondHeader + '" data-element="' + this.options.secondHeader + '">' + buttonLabels.header2 + '</button></li>',
'quote': '<li><button class="medium-editor-action medium-editor-action-quote" data-action="append-blockquote" data-element="blockquote">' + buttonLabels.quote + '</button></li>',
'orderedlist': '<li><button class="medium-editor-action medium-editor-action-orderedlist" data-action="insertorderedlist" data-element="ol">' + buttonLabels.orderedlist + '</button></li>',
'unorderedlist': '<li><button class="medium-editor-action medium-editor-action-unorderedlist" data-action="insertunorderedlist" data-element="ul">' + buttonLabels.unorderedlist + '</button></li>',
'pre': '<li><button class="medium-editor-action medium-editor-action-pre" data-action="append-pre" data-element="pre">' + buttonLabels.pre + '</button></li>',
'indent': '<li><button class="medium-editor-action medium-editor-action-indent" data-action="indent" data-element="ul">' + buttonLabels.indent + '</button></li>',
'outdent': '<li><button class="medium-editor-action medium-editor-action-outdent" data-action="outdent" data-element="ul">' + buttonLabels.outdent + '</button></li>'
'bold': '<button class="medium-editor-action medium-editor-action-bold" data-action="bold" data-element="b">' + buttonLabels.bold + '</button>',
'italic': '<button class="medium-editor-action medium-editor-action-italic" data-action="italic" data-element="i">' + buttonLabels.italic + '</button>',
'underline': '<button class="medium-editor-action medium-editor-action-underline" data-action="underline" data-element="u">' + buttonLabels.underline + '</button>',
'strikethrough': '<button class="medium-editor-action medium-editor-action-strikethrough" data-action="strikethrough" data-element="strike"><strike>A</strike></button>',
'superscript': '<button class="medium-editor-action medium-editor-action-superscript" data-action="superscript" data-element="sup">' + buttonLabels.superscript + '</button>',
'subscript': '<button class="medium-editor-action medium-editor-action-subscript" data-action="subscript" data-element="sub">' + buttonLabels.subscript + '</button>',
'anchor': '<button class="medium-editor-action medium-editor-action-anchor" data-action="anchor" data-element="a">' + buttonLabels.anchor + '</button>',
'image': '<button class="medium-editor-action medium-editor-action-image" data-action="image" data-element="img">' + buttonLabels.image + '</button>',
'header1': '<button class="medium-editor-action medium-editor-action-header1" data-action="append-' + this.options.firstHeader + '" data-element="' + this.options.firstHeader + '">' + buttonLabels.header1 + '</button>',
'header2': '<button class="medium-editor-action medium-editor-action-header2" data-action="append-' + this.options.secondHeader + '" data-element="' + this.options.secondHeader + '">' + buttonLabels.header2 + '</button>',
'quote': '<button class="medium-editor-action medium-editor-action-quote" data-action="append-blockquote" data-element="blockquote">' + buttonLabels.quote + '</button>',
'orderedlist': '<button class="medium-editor-action medium-editor-action-orderedlist" data-action="insertorderedlist" data-element="ol">' + buttonLabels.orderedlist + '</button>',
'unorderedlist': '<button class="medium-editor-action medium-editor-action-unorderedlist" data-action="insertunorderedlist" data-element="ul">' + buttonLabels.unorderedlist + '</button>',
'pre': '<button class="medium-editor-action medium-editor-action-pre" data-action="append-pre" data-element="pre">' + buttonLabels.pre + '</button>',
'indent': '<button class="medium-editor-action medium-editor-action-indent" data-action="indent" data-element="ul">' + buttonLabels.indent + '</button>',
'outdent': '<button class="medium-editor-action medium-editor-action-outdent" data-action="outdent" data-element="ul">' + buttonLabels.outdent + '</button>'
};

@@ -324,23 +359,2 @@ return buttonTemplates[btnType] || false;

//TODO: actionTemplate
toolbarTemplate: function () {
var btns = this.options.buttons,
html = '<ul id="medium-editor-toolbar-actions" class="medium-editor-toolbar-actions clearfix">',
i,
tpl;
for (i = 0; i < btns.length; i += 1) {
tpl = this.buttonTemplate(btns[i]);
if (tpl) {
html += tpl;
}
}
html += '</ul>' +
'<div class="medium-editor-toolbar-form-anchor" id="medium-editor-toolbar-form-anchor">' +
' <input type="text" value="" placeholder="' + this.options.anchorInputPlaceholder + '">' +
' <a href="#">&times;</a>' +
'</div>';
return html;
},
initToolbar: function () {

@@ -364,3 +378,4 @@ if (this.toolbar) {

toolbar.className = 'medium-editor-toolbar';
toolbar.innerHTML = this.toolbarTemplate();
toolbar.appendChild(this.toolbarButtons());
toolbar.appendChild(this.toolbarFormAnchor());
document.body.appendChild(toolbar);

@@ -370,2 +385,55 @@ return toolbar;

//TODO: actionTemplate
toolbarButtons: function () {
var btns = this.options.buttons,
ul = document.createElement('ul'),
li,
i,
btn,
ext;
ul.id = 'medium-editor-toolbar-actions';
ul.className = 'medium-editor-toolbar-actions clearfix';
for (i = 0; i < btns.length; i += 1) {
if (this.options.extensions.hasOwnProperty(btns[i])) {
ext = this.options.extensions[btns[i]];
btn = ext.getButton !== undefined ? ext.getButton() : null;
} else {
btn = this.buttonTemplate(btns[i]);
}
if (btn) {
li = document.createElement('li');
if (isElement(btn)) {
li.appendChild(btn);
} else {
li.innerHTML = btn;
}
ul.appendChild(li);
}
}
return ul;
},
toolbarFormAnchor: function () {
var anchor = document.createElement('div'),
input = document.createElement('input'),
a = document.createElement('a');
a.setAttribute('href', '#');
a.innerHTML = '&times;';
input.setAttribute('type', 'text');
input.setAttribute('placeholder', this.options.anchorInputPlaceholder);
anchor.className = 'medium-editor-toolbar-form-anchor';
anchor.id = 'medium-editor-toolbar-form-anchor';
anchor.appendChild(input);
anchor.appendChild(a);
return anchor;
},
bindSelect: function () {

@@ -451,5 +519,3 @@ var self = this,

var selection = window.getSelection(),
range = selection.getRangeAt(0),
current = range.commonAncestorContainer,
parent = current.parentNode,
range, current, parent,
result,

@@ -469,2 +535,6 @@ getMediumElement = function (e) {

try {
range = selection.getRangeAt(0);
current = range.commonAncestorContainer;
parent = current.parentNode;
if (current.getAttribute('data-medium-element')) {

@@ -523,3 +593,4 @@ result = current;

checkActiveButtons: function () {
var parentNode = this.selection.anchorNode;
var elements = Array.prototype.slice.call(this.elements),
parentNode = this.selection.anchorNode;
if (!parentNode.tagName) {

@@ -530,2 +601,8 @@ parentNode = this.selection.anchorNode.parentNode;

this.activateButton(parentNode.tagName.toLowerCase());
this.callExtensions('checkState', parentNode);
// we can abort the search upwards if we leave the contentEditable element
if (elements.indexOf(parentNode) !== -1) {
break;
}
parentNode = parentNode.parentNode;

@@ -557,3 +634,5 @@ }

}
self.execAction(this.getAttribute('data-action'), e);
if (this.hasAttribute('data-action')) {
self.execAction(this.getAttribute('data-action'), e);
}
};

@@ -568,4 +647,6 @@ for (i = 0; i < buttons.length; i += 1) {

setFirstAndLastItems: function (buttons) {
buttons[0].className += ' medium-editor-button-first';
buttons[buttons.length - 1].className += ' medium-editor-button-last';
if (buttons.length > 0) {
buttons[0].className += ' medium-editor-button-first';
buttons[buttons.length - 1].className += ' medium-editor-button-last';
}
return this;

@@ -657,3 +738,5 @@ },

this.keepToolbarAlive = false;
this.toolbar.classList.remove('medium-editor-toolbar-active');
if (this.toolbar !== undefined) {
this.toolbar.classList.remove('medium-editor-toolbar-active');
}
},

@@ -669,3 +752,3 @@

timer = setTimeout(function () {
if (!self.toolbar.classList.contains('medium-editor-toolbar-active')) {
if (self.toolbar && !self.toolbar.classList.contains('medium-editor-toolbar-active')) {
self.toolbar.classList.add('medium-editor-toolbar-active');

@@ -739,3 +822,3 @@ }

timer = setTimeout(function () {
if (!self.anchorPreview.classList.contains('medium-editor-anchor-preview-active')) {
if (self.anchorPreview && !self.anchorPreview.classList.contains('medium-editor-anchor-preview-active')) {
self.anchorPreview.classList.add('medium-editor-anchor-preview-active');

@@ -833,3 +916,5 @@ }

setTimeout(function () {
self.showAnchorForm(self.activeAnchor.href);
if (self.activeAnchor) {
self.showAnchorForm(self.activeAnchor.href);
}
self.keepToolbarAlive = false;

@@ -855,3 +940,3 @@ }, 100 + self.options.delay);

// Detect empty href attributes
// The browser will make href="" or href="#top"
// The browser will make href="" or href="#top"
// into absolute urls when accessed as e.targed.href, so check the html

@@ -882,9 +967,20 @@ if (!/href=["']\S+["']/.test(e.target.outerHTML) || /href=["']#\S+["']/.test(e.target.outerHTML)) {

bindAnchorPreview: function (index) {
var self = this;
this.elements[index].addEventListener('mouseover', function (e) {
var i, self = this;
this.editorAnchorObserverWrapper = function (e) {
self.editorAnchorObserver(e);
});
};
for (i = 0; i < this.elements.length; i += 1) {
this.elements[i].addEventListener('mouseover', this.editorAnchorObserverWrapper);
}
return this;
},
checkLinkFormat: function (value) {
var re = /^https?:\/\//;
if (value.match(re)) {
return value;
}
return "http://" + value;
},
setTargetBlank: function () {

@@ -905,2 +1001,5 @@ var el = getSelectionStart(),

restoreSelection(this.savedSelection);
if (this.options.checkLinkFormat) {
input.value = this.checkLinkFormat(input.value);
}
document.execCommand('createLink', false, input.value);

@@ -956,2 +1055,3 @@ if (this.options.targetBlank) {

for (i = 0; i < this.elements.length; i += 1) {
this.elements[i].removeEventListener('mouseover', this.editorAnchorObserverWrapper);
this.elements[i].removeEventListener('keyup', this.checkSelectionWrapper);

@@ -966,2 +1066,8 @@ this.elements[i].removeEventListener('blur', this.checkSelectionWrapper);

htmlEntities: function (str) {
// converts special characters (like <) into their escaped/encoded values (like &lt;).
// This allows you to show to display the string without the browser reading it as HTML.
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
},
bindPaste: function () {

@@ -975,3 +1081,3 @@ var i, self = this;

this.classList.remove('medium-editor-placeholder');
if (!self.options.forcePlainText) {
if (!self.options.forcePlainText && !self.options.cleanPastedHTML) {
return this;

@@ -982,2 +1088,6 @@ }

e.preventDefault();
if (self.options.cleanPastedHTML && e.clipboardData.getData('text/html')) {
return self.cleanPaste(e.clipboardData.getData('text/html'));
}
if (!self.options.disableReturn) {

@@ -987,3 +1097,7 @@ paragraphs = e.clipboardData.getData('text/plain').split(/[\r\n]/g);

if (paragraphs[p] !== '') {
html += '<p>' + paragraphs[p] + '</p>';
if (navigator.userAgent.match(/firefox/i) && p === 0) {
html += self.htmlEntities(paragraphs[p]);
} else {
html += '<p>' + self.htmlEntities(paragraphs[p]) + '</p>';
}
}

@@ -1022,2 +1136,189 @@ }

return this;
},
cleanPaste: function (text) {
/*jslint regexp: true*/
/*
jslint does not allow character negation, because the negation
will not match any unicode characters. In the regexes in this
block, negation is used specifically to match the end of an html
tag, and in fact unicode characters *should* be allowed.
*/
var i, elList, workEl,
el = this.getSelectionElement(),
multiline = /<p|<br|<div/.test(text),
replacements = [
// replace two bogus tags that begin pastes from google docs
[new RegExp(/<[^>]*docs-internal-guid[^>]*>/gi), ""],
[new RegExp(/<\/b>(<br[^>]*>)?$/gi), ""],
// un-html spaces and newlines inserted by OS X
[new RegExp(/<span class="Apple-converted-space">\s+<\/span>/g), ' '],
[new RegExp(/<br class="Apple-interchange-newline">/g), '<br>'],
// replace google docs italics+bold with a span to be replaced once the html is inserted
[new RegExp(/<span[^>]*(font-style:italic;font-weight:bold|font-weight:bold;font-style:italic)[^>]*>/gi), '<span class="replace-with italic bold">'],
// replace google docs italics with a span to be replaced once the html is inserted
[new RegExp(/<span[^>]*font-style:italic[^>]*>/gi), '<span class="replace-with italic">'],
//[replace google docs bolds with a span to be replaced once the html is inserted
[new RegExp(/<span[^>]*font-weight:bold[^>]*>/gi), '<span class="replace-with bold">'],
// replace manually entered b/i/a tags with real ones
[new RegExp(/&lt;(\/?)(i|b|a)&gt;/gi), '<$1$2>'],
// replace manually a tags with real ones, converting smart-quotes from google docs
[new RegExp(/&lt;a\s+href=(&quot;|&rdquo;|&ldquo;|“|”)([^&]+)(&quot;|&rdquo;|&ldquo;|“|”)&gt;/gi), '<a href="$2">']
];
/*jslint regexp: false*/
for (i = 0; i < replacements.length; i += 1) {
text = text.replace(replacements[i][0], replacements[i][1]);
}
if (multiline) {
// double br's aren't converted to p tags, but we want paragraphs.
elList = text.split('<br><br>');
this.pasteHTML('<p>' + elList.join('</p><p>') + '</p>');
document.execCommand('insertText', false, "\n");
// block element cleanup
elList = el.querySelectorAll('p,div,br');
for (i = 0; i < elList.length; i += 1) {
workEl = elList[i];
switch (workEl.tagName.toLowerCase()) {
case 'p':
case 'div':
this.filterCommonBlocks(workEl);
break;
case 'br':
this.filterLineBreak(workEl);
break;
}
}
} else {
this.pasteHTML(text);
}
},
pasteHTML: function (html) {
var elList, workEl, i, fragmentBody, pasteBlock = document.createDocumentFragment();
pasteBlock.appendChild(document.createElement('body'));
fragmentBody = pasteBlock.querySelector('body');
fragmentBody.innerHTML = html;
this.cleanupSpans(fragmentBody);
elList = fragmentBody.querySelectorAll('*');
for (i = 0; i < elList.length; i += 1) {
workEl = elList[i];
// delete ugly attributes
workEl.removeAttribute('class');
workEl.removeAttribute('style');
workEl.removeAttribute('dir');
if (workEl.tagName.toLowerCase() === 'meta') {
workEl.parentNode.removeChild(workEl);
}
}
document.execCommand('insertHTML', false, fragmentBody.innerHTML.replace(/&nbsp;/g, ' '));
},
isCommonBlock: function (el) {
return (el && (el.tagName.toLowerCase() === 'p' || el.tagName.toLowerCase() === 'div'));
},
filterCommonBlocks: function (el) {
if (/^\s*$/.test(el.innerText)) {
el.parentNode.removeChild(el);
}
},
filterLineBreak: function (el) {
if (this.isCommonBlock(el.previousElementSibling)) {
// remove stray br's following common block elements
el.parentNode.removeChild(el);
} else if (this.isCommonBlock(el.parentNode) && (el.parentNode.firstChild === el || el.parentNode.lastChild === el)) {
// remove br's just inside open or close tags of a div/p
el.parentNode.removeChild(el);
} else if (el.parentNode.childElementCount === 1) {
// and br's that are the only child of a div/p
this.removeWithParent(el);
}
},
// remove an element, including its parent, if it is the only element within its parent
removeWithParent: function (el) {
if (el && el.parentNode) {
if (el.parentNode.parentNode && el.parentNode.childElementCount === 1) {
el.parentNode.parentNode.removeChild(el.parentNode);
} else {
el.parentNode.removeChild(el.parentNode);
}
}
},
cleanupSpans: function (container_el) {
var i,
el,
new_el,
spans = container_el.querySelectorAll('.replace-with');
for (i = 0; i < spans.length; i += 1) {
el = spans[i];
new_el = document.createElement(el.classList.contains('bold') ? 'b' : 'i');
if (el.classList.contains('bold') && el.classList.contains('italic')) {
// add an i tag as well if this has both italics and bold
new_el.innerHTML = '<i>' + el.innerHTML + '</i>';
} else {
new_el.innerHTML = el.innerHTML;
}
el.parentNode.replaceChild(new_el, el);
}
spans = container_el.querySelectorAll('span');
for (i = 0; i < spans.length; i += 1) {
el = spans[i];
// remove empty spans, replace others with their contents
if (/^\s*$/.test()) {
el.parentNode.removeChild(el);
} else {
el.parentNode.replaceChild(document.createTextNode(el.innerText), el);
}
}
}

@@ -1024,0 +1325,0 @@

@@ -1,1 +0,1 @@

function MediumEditor(a,b){"use strict";return this.init(a,b)}"object"==typeof module&&(module.exports=MediumEditor),function(a,b){"use strict";function c(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}function d(){var b,c,d,e=a.getSelection();if(e.getRangeAt&&e.rangeCount){for(d=[],b=0,c=e.rangeCount;c>b;b+=1)d.push(e.getRangeAt(b));return d}return null}function e(b){var c,d,e=a.getSelection();if(b)for(e.removeAllRanges(),c=0,d=b.length;d>c;c+=1)e.addRange(b[c])}function f(){var a=b.getSelection().anchorNode,c=a&&3===a.nodeType?a.parentNode:a;return c}function g(){var c,d,e,f,g="";if(void 0!==a.getSelection){if(d=a.getSelection(),d.rangeCount){for(f=b.createElement("div"),c=0,e=d.rangeCount;e>c;c+=1)f.appendChild(d.getRangeAt(c).cloneContents());g=f.innerHTML}}else void 0!==b.selection&&"Text"===b.selection.type&&(g=b.selection.createRange().htmlText);return g}MediumEditor.prototype={defaults:{allowMultiParagraphSelection:!0,anchorInputPlaceholder:"Paste or type a link",buttons:["bold","italic","underline","anchor","header1","header2","quote"],buttonLabels:!1,delay:0,diffLeft:0,diffTop:-10,disableReturn:!1,disableDoubleReturn:!1,disableToolbar:!1,firstHeader:"h3",forcePlainText:!0,placeholder:"Type your text",secondHeader:"h4",targetBlank:!1,anchorPreviewHideDelay:500},isIE:"Microsoft Internet Explorer"===navigator.appName||"Netscape"===navigator.appName&&null!==new RegExp("Trident/.*rv:([0-9]{1,}[.0-9]{0,})").exec(navigator.userAgent),init:function(a,d){return this.elements="string"==typeof a?b.querySelectorAll(a):a,1===this.elements.nodeType&&(this.elements=[this.elements]),0!==this.elements.length?(this.parentElements=["p","h1","h2","h3","h4","h5","h6","blockquote","pre"],this.id=b.querySelectorAll(".medium-editor-toolbar").length+1,this.options=c(d,this.defaults),this.setup()):void 0},setup:function(){this.isActive=!0,this.initElements().bindSelect().bindPaste().setPlaceholders().bindWindowActions()},initElements:function(){var a,b=!1;for(a=0;a<this.elements.length;a+=1)this.elements[a].setAttribute("contentEditable",!0),this.elements[a].getAttribute("data-placeholder")||this.elements[a].setAttribute("data-placeholder",this.options.placeholder),this.elements[a].setAttribute("data-medium-element",!0),this.bindParagraphCreation(a).bindReturn(a).bindTab(a).bindAnchorPreview(a),this.options.disableToolbar||this.elements[a].getAttribute("data-disable-toolbar")||(b=!0);return b&&this.initToolbar().bindButtons().bindAnchorForm(),this},serialize:function(){var a,b,c={};for(a=0;a<this.elements.length;a+=1)b=""!==this.elements[a].id?this.elements[a].id:"element-"+a,c[b]={value:this.elements[a].innerHTML.trim()};return c},bindParagraphCreation:function(a){var c=this;return this.elements[a].addEventListener("keyup",function(a){var d,e=f();e&&e.getAttribute("data-medium-element")&&0===e.children.length&&!c.options.disableReturn&&!e.getAttribute("data-disable-return")&&b.execCommand("formatBlock",!1,"p"),13===a.which&&(e=f(),d=e.tagName.toLowerCase(),c.options.disableReturn||this.getAttribute("data-disable-return")||"li"===d||c.isListItemChild(e)||(a.shiftKey||b.execCommand("formatBlock",!1,"p"),"a"===d&&b.execCommand("unlink",!1,null)))}),this},isListItemChild:function(a){for(var b=a.parentNode,c=b.tagName.toLowerCase();-1===this.parentElements.indexOf(c)&&"div"!==c;){if("li"===c)return!0;if(b=b.parentNode,!b||!b.tagName)return!1;c=b.tagName.toLowerCase()}return!1},bindReturn:function(a){var b=this;return this.elements[a].addEventListener("keypress",function(a){if(13===a.which)if(b.options.disableReturn||this.getAttribute("data-disable-return"))a.preventDefault();else if(b.options.disableDoubleReturn||this.getAttribute("data-disable-double-return")){var c=f();c&&"\n"===c.innerText&&a.preventDefault()}}),this},bindTab:function(a){return this.elements[a].addEventListener("keydown",function(a){if(9===a.which){var c=f().tagName.toLowerCase();"pre"===c&&(a.preventDefault(),b.execCommand("insertHtml",null," "))}}),this},buttonTemplate:function(a){var b=this.getButtonLabels(this.options.buttonLabels),c={bold:'<li><button class="medium-editor-action medium-editor-action-bold" data-action="bold" data-element="b">'+b.bold+"</button></li>",italic:'<li><button class="medium-editor-action medium-editor-action-italic" data-action="italic" data-element="i">'+b.italic+"</button></li>",underline:'<li><button class="medium-editor-action medium-editor-action-underline" data-action="underline" data-element="u">'+b.underline+"</button></li>",strikethrough:'<li><button class="medium-editor-action medium-editor-action-strikethrough" data-action="strikethrough" data-element="strike"><strike>A</strike></button></li>',superscript:'<li><button class="medium-editor-action medium-editor-action-superscript" data-action="superscript" data-element="sup">'+b.superscript+"</button></li>",subscript:'<li><button class="medium-editor-action medium-editor-action-subscript" data-action="subscript" data-element="sub">'+b.subscript+"</button></li>",anchor:'<li><button class="medium-editor-action medium-editor-action-anchor" data-action="anchor" data-element="a">'+b.anchor+"</button></li>",image:'<li><button class="medium-editor-action medium-editor-action-image" data-action="image" data-element="img">'+b.image+"</button></li>",header1:'<li><button class="medium-editor-action medium-editor-action-header1" data-action="append-'+this.options.firstHeader+'" data-element="'+this.options.firstHeader+'">'+b.header1+"</button></li>",header2:'<li><button class="medium-editor-action medium-editor-action-header2" data-action="append-'+this.options.secondHeader+'" data-element="'+this.options.secondHeader+'">'+b.header2+"</button></li>",quote:'<li><button class="medium-editor-action medium-editor-action-quote" data-action="append-blockquote" data-element="blockquote">'+b.quote+"</button></li>",orderedlist:'<li><button class="medium-editor-action medium-editor-action-orderedlist" data-action="insertorderedlist" data-element="ol">'+b.orderedlist+"</button></li>",unorderedlist:'<li><button class="medium-editor-action medium-editor-action-unorderedlist" data-action="insertunorderedlist" data-element="ul">'+b.unorderedlist+"</button></li>",pre:'<li><button class="medium-editor-action medium-editor-action-pre" data-action="append-pre" data-element="pre">'+b.pre+"</button></li>",indent:'<li><button class="medium-editor-action medium-editor-action-indent" data-action="indent" data-element="ul">'+b.indent+"</button></li>",outdent:'<li><button class="medium-editor-action medium-editor-action-outdent" data-action="outdent" data-element="ul">'+b.outdent+"</button></li>"};return c[a]||!1},getButtonLabels:function(a){var b,c,d={bold:"<b>B</b>",italic:"<b><i>I</i></b>",underline:"<b><u>U</u></b>",superscript:"<b>x<sup>1</sup></b>",subscript:"<b>x<sub>1</sub></b>",anchor:"<b>#</b>",image:"<b>image</b>",header1:"<b>H1</b>",header2:"<b>H2</b>",quote:"<b>&ldquo;</b>",orderedlist:"<b>1.</b>",unorderedlist:"<b>&bull;</b>",pre:"<b>0101</b>",indent:"<b>&rarr;</b>",outdent:"<b>&larr;</b>"};if("fontawesome"===a?b={bold:'<i class="fa fa-bold"></i>',italic:'<i class="fa fa-italic"></i>',underline:'<i class="fa fa-underline"></i>',superscript:'<i class="fa fa-superscript"></i>',subscript:'<i class="fa fa-subscript"></i>',anchor:'<i class="fa fa-link"></i>',image:'<i class="fa fa-picture-o"></i>',quote:'<i class="fa fa-quote-right"></i>',orderedlist:'<i class="fa fa-list-ol"></i>',unorderedlist:'<i class="fa fa-list-ul"></i>',pre:'<i class="fa fa-code fa-lg"></i>',indent:'<i class="fa fa-indent"></i>',outdent:'<i class="fa fa-outdent"></i>'}:"object"==typeof a&&(b=a),"object"==typeof b)for(c in b)b.hasOwnProperty(c)&&(d[c]=b[c]);return d},toolbarTemplate:function(){var a,b,c=this.options.buttons,d='<ul id="medium-editor-toolbar-actions" class="medium-editor-toolbar-actions clearfix">';for(a=0;a<c.length;a+=1)b=this.buttonTemplate(c[a]),b&&(d+=b);return d+='</ul><div class="medium-editor-toolbar-form-anchor" id="medium-editor-toolbar-form-anchor"> <input type="text" value="" placeholder="'+this.options.anchorInputPlaceholder+'"> <a href="#">&times;</a></div>'},initToolbar:function(){return this.toolbar?this:(this.toolbar=this.createToolbar(),this.keepToolbarAlive=!1,this.anchorForm=this.toolbar.querySelector(".medium-editor-toolbar-form-anchor"),this.anchorInput=this.anchorForm.querySelector("input"),this.toolbarActions=this.toolbar.querySelector(".medium-editor-toolbar-actions"),this.anchorPreview=this.createAnchorPreview(),this)},createToolbar:function(){var a=b.createElement("div");return a.id="medium-editor-toolbar-"+this.id,a.className="medium-editor-toolbar",a.innerHTML=this.toolbarTemplate(),b.body.appendChild(a),a},bindSelect:function(){var a,c=this,d="";for(this.checkSelectionWrapper=function(a){return a&&c.clickingIntoArchorForm(a)?!1:(clearTimeout(d),void(d=setTimeout(function(){c.checkSelection()},c.options.delay)))},b.documentElement.addEventListener("mouseup",this.checkSelectionWrapper),a=0;a<this.elements.length;a+=1)this.elements[a].addEventListener("keyup",this.checkSelectionWrapper),this.elements[a].addEventListener("blur",this.checkSelectionWrapper);return this},checkSelection:function(){var b,c;return this.keepToolbarAlive===!0||this.options.disableToolbar||(b=a.getSelection(),""===b.toString().trim()||this.options.allowMultiParagraphSelection===!1&&this.hasMultiParagraphs()?this.hideToolbarActions():(c=this.getSelectionElement(),!c||c.getAttribute("data-disable-toolbar")?this.hideToolbarActions():this.checkSelectionElement(b,c))),this},clickingIntoArchorForm:function(a){var b=this;return a.type&&"blur"===a.type.toLowerCase()&&a.relatedTarget&&a.relatedTarget===b.anchorInput?!0:!1},hasMultiParagraphs:function(){var a=g().replace(/<[\S]+><\/[\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,b){var c;for(this.selection=a,this.selectionRange=this.selection.getRangeAt(0),c=0;c<this.elements.length;c+=1)if(this.elements[c]===b)return void this.setToolbarButtonStates().setToolbarPosition().showToolbarActions();this.hideToolbarActions()},getSelectionElement:function(){var b,c=a.getSelection(),d=c.getRangeAt(0),e=d.commonAncestorContainer,f=e.parentNode,g=function(a){var b=a;try{for(;!b.getAttribute("data-medium-element");)b=b.parentNode}catch(c){return!1}return b};try{b=e.getAttribute("data-medium-element")?e:g(f)}catch(h){b=g(f)}return b},setToolbarPosition:function(){var b=50,c=a.getSelection(),d=c.getRangeAt(0),e=d.getBoundingClientRect(),f=this.options.diffLeft-this.toolbar.offsetWidth/2,g=(e.left+e.right)/2,h=this.toolbar.offsetWidth/2;return e.top<b?(this.toolbar.classList.add("medium-toolbar-arrow-over"),this.toolbar.classList.remove("medium-toolbar-arrow-under"),this.toolbar.style.top=b+e.bottom-this.options.diffTop+a.pageYOffset-this.toolbar.offsetHeight+"px"):(this.toolbar.classList.add("medium-toolbar-arrow-under"),this.toolbar.classList.remove("medium-toolbar-arrow-over"),this.toolbar.style.top=e.top+this.options.diffTop+a.pageYOffset-this.toolbar.offsetHeight+"px"),this.toolbar.style.left=h>g?f+h+"px":a.innerWidth-g<h?a.innerWidth+f-h+"px":f+g+"px",this.hideAnchorPreview(),this},setToolbarButtonStates:function(){var a,b=this.toolbarActions.querySelectorAll("button");for(a=0;a<b.length;a+=1)b[a].classList.remove("medium-editor-button-active");return this.checkActiveButtons(),this},checkActiveButtons:function(){var a=this.selection.anchorNode;for(a.tagName||(a=this.selection.anchorNode.parentNode);void 0!==a.tagName&&-1===this.parentElements.indexOf(a.tagName.toLowerCase);)this.activateButton(a.tagName.toLowerCase()),a=a.parentNode},activateButton:function(a){var b=this.toolbar.querySelector('[data-element="'+a+'"]');null!==b&&-1===b.className.indexOf("medium-editor-button-active")&&(b.className+=" medium-editor-button-active")},bindButtons:function(){var a,b=this.toolbar.querySelectorAll("button"),c=this,d=function(a){a.preventDefault(),a.stopPropagation(),void 0===c.selection&&c.checkSelection(),this.className.indexOf("medium-editor-button-active")>-1?this.classList.remove("medium-editor-button-active"):this.className+=" medium-editor-button-active",c.execAction(this.getAttribute("data-action"),a)};for(a=0;a<b.length;a+=1)b[a].addEventListener("click",d);return this.setFirstAndLastItems(b),this},setFirstAndLastItems:function(a){return a[0].className+=" medium-editor-button-first",a[a.length-1].className+=" medium-editor-button-last",this},execAction:function(c,d){c.indexOf("append-")>-1?(this.execFormatBlock(c.replace("append-","")),this.setToolbarPosition(),this.setToolbarButtonStates()):"anchor"===c?this.triggerAnchorAction(d):"image"===c?b.execCommand("insertImage",!1,a.getSelection()):(b.execCommand(c,!1,null),this.setToolbarPosition())},triggerAnchorAction:function(){return"a"===this.selection.anchorNode.parentNode.tagName.toLowerCase()?b.execCommand("unlink",!1,null):"block"===this.anchorForm.style.display?this.showToolbarActions():this.showAnchorForm(),this},execFormatBlock:function(a){var c=this.getSelectionData(this.selection.anchorNode);if("blockquote"===a&&c.el&&"blockquote"===c.el.parentNode.tagName.toLowerCase())return b.execCommand("outdent",!1,null);if(c.tagName===a&&(a="p"),this.isIE){if("blockquote"===a)return b.execCommand("indent",!1,a);a="<"+a+">"}return b.execCommand("formatBlock",!1,a)},getSelectionData:function(a){var b;for(a&&a.tagName&&(b=a.tagName.toLowerCase());a&&-1===this.parentElements.indexOf(b);)a=a.parentNode,a&&a.tagName&&(b=a.tagName.toLowerCase());return{el:a,tagName:b}},getFirstChild:function(a){for(var b=a.firstChild;null!==b&&1!==b.nodeType;)b=b.nextSibling;return b},hideToolbarActions:function(){this.keepToolbarAlive=!1,this.toolbar.classList.remove("medium-editor-toolbar-active")},showToolbarActions:function(){var a,b=this;this.anchorForm.style.display="none",this.toolbarActions.style.display="block",this.keepToolbarAlive=!1,clearTimeout(a),a=setTimeout(function(){b.toolbar.classList.contains("medium-editor-toolbar-active")||b.toolbar.classList.add("medium-editor-toolbar-active")},100)},showAnchorForm:function(a){this.toolbarActions.style.display="none",this.savedSelection=d(),this.anchorForm.style.display="block",this.keepToolbarAlive=!0,this.anchorInput.focus(),this.anchorInput.value=a||""},bindAnchorForm:function(){var a=this.anchorForm.querySelector("a"),b=this;return this.anchorForm.addEventListener("click",function(a){a.stopPropagation()}),this.anchorInput.addEventListener("keyup",function(a){13===a.keyCode&&(a.preventDefault(),b.createLink(this))}),this.anchorInput.addEventListener("click",function(a){a.stopPropagation(),b.keepToolbarAlive=!0}),this.anchorInput.addEventListener("blur",function(){b.keepToolbarAlive=!1,b.checkSelection()}),a.addEventListener("click",function(a){a.preventDefault(),b.showToolbarActions(),e(b.savedSelection)}),this},hideAnchorPreview:function(){this.anchorPreview.classList.remove("medium-editor-anchor-preview-active")},showAnchorPreview:function(b){if(this.anchorPreview.classList.contains("medium-editor-anchor-preview-active"))return!0;var c,d,e,f=this,g=40,h=b.getBoundingClientRect(),i=(h.left+h.right)/2;return f.anchorPreview.querySelector("i").innerHTML=b.href,c=f.anchorPreview.offsetWidth/2,d=f.options.diffLeft-c,clearTimeout(e),e=setTimeout(function(){f.anchorPreview.classList.contains("medium-editor-anchor-preview-active")||f.anchorPreview.classList.add("medium-editor-anchor-preview-active")},100),f.observeAnchorPreview(b),f.anchorPreview.classList.add("medium-toolbar-arrow-over"),f.anchorPreview.classList.remove("medium-toolbar-arrow-under"),f.anchorPreview.style.top=Math.round(g+h.bottom-f.options.diffTop+a.pageYOffset-f.anchorPreview.offsetHeight)+"px",f.anchorPreview.style.left=c>i?d+c+"px":a.innerWidth-i<c?a.innerWidth+d-c+"px":d+i+"px",this},observeAnchorPreview:function(a){var b=this,c=(new Date).getTime(),d=!0,e=function(){c=(new Date).getTime(),d=!0},f=function(a){a.relatedTarget&&/anchor-preview/.test(a.relatedTarget.className)||(d=!1)},g=setInterval(function(){if(d)return!0;var h=(new Date).getTime()-c;h>b.options.anchorPreviewHideDelay&&(b.hideAnchorPreview(),clearInterval(g),b.anchorPreview.removeEventListener("mouseover",e),b.anchorPreview.removeEventListener("mouseout",f),a.removeEventListener("mouseover",e),a.removeEventListener("mouseout",f))},200);b.anchorPreview.addEventListener("mouseover",e),b.anchorPreview.addEventListener("mouseout",f),a.addEventListener("mouseover",e),a.addEventListener("mouseout",f)},createAnchorPreview:function(){var a=this,c=b.createElement("div");return c.id="medium-editor-anchor-preview-"+this.id,c.className="medium-editor-anchor-preview",c.innerHTML=this.anchorPreviewTemplate(),b.body.appendChild(c),c.addEventListener("click",function(){a.anchorPreviewClickHandler()}),c},anchorPreviewTemplate:function(){return'<div class="medium-editor-toolbar-anchor-preview" id="medium-editor-toolbar-anchor-preview"> <i class="medium-editor-toolbar-anchor-preview-inner"></i></div>'},anchorPreviewClickHandler:function(){if(this.activeAnchor){var c=this,d=b.createRange(),e=a.getSelection();d.selectNodeContents(c.activeAnchor),e.removeAllRanges(),e.addRange(d),setTimeout(function(){c.showAnchorForm(c.activeAnchor.href),c.keepToolbarAlive=!1},100+c.options.delay)}this.hideAnchorPreview()},editorAnchorObserver:function(a){var b=this,c=!0,d=function(){c=!1,b.activeAnchor.removeEventListener("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.toolbar.classList.contains("medium-editor-toolbar-active"))return!0;this.activeAnchor=a.target,this.activeAnchor.addEventListener("mouseout",d),setTimeout(function(){c&&b.showAnchorPreview(a.target)},b.options.delay)}},bindAnchorPreview:function(a){var b=this;return this.elements[a].addEventListener("mouseover",function(a){b.editorAnchorObserver(a)}),this},setTargetBlank:function(){var a,b=f();if("a"===b.tagName.toLowerCase())b.target="_blank";else for(b=b.getElementsByTagName("a"),a=0;a<b.length;a+=1)b[a].target="_blank"},createLink:function(a){e(this.savedSelection),b.execCommand("createLink",!1,a.value),this.options.targetBlank&&this.setTargetBlank(),this.showToolbarActions(),a.value=""},bindWindowActions:function(){var b,c=this;return this.windowResizeHandler=function(){clearTimeout(b),b=setTimeout(function(){c.toolbar&&c.toolbar.classList.contains("medium-editor-toolbar-active")&&c.setToolbarPosition()},100)},a.addEventListener("resize",this.windowResizeHandler),this},activate:function(){this.isActive||this.setup()},deactivate:function(){var c;if(this.isActive)for(this.isActive=!1,void 0!==this.toolbar&&(b.body.removeChild(this.anchorPreview),b.body.removeChild(this.toolbar),delete this.toolbar,delete this.anchorPreview),b.documentElement.removeEventListener("mouseup",this.checkSelectionWrapper),a.removeEventListener("resize",this.windowResizeHandler),c=0;c<this.elements.length;c+=1)this.elements[c].removeEventListener("keyup",this.checkSelectionWrapper),this.elements[c].removeEventListener("blur",this.checkSelectionWrapper),this.elements[c].removeEventListener("paste",this.pasteWrapper),this.elements[c].removeAttribute("contentEditable"),this.elements[c].removeAttribute("data-medium-element")},bindPaste:function(){var a,c=this;for(this.pasteWrapper=function(a){var d,e,f="";if(this.classList.remove("medium-editor-placeholder"),!c.options.forcePlainText)return this;if(a.clipboardData&&a.clipboardData.getData&&!a.defaultPrevented)if(a.preventDefault(),c.options.disableReturn)b.execCommand("insertHTML",!1,a.clipboardData.getData("text/plain"));else{for(d=a.clipboardData.getData("text/plain").split(/[\r\n]/g),e=0;e<d.length;e+=1)""!==d[e]&&(f+="<p>"+d[e]+"</p>");b.execCommand("insertHTML",!1,f)}},a=0;a<this.elements.length;a+=1)this.elements[a].addEventListener("paste",this.pasteWrapper);return this},setPlaceholders:function(){var a,b=function(a){""===a.textContent.replace(/^\s+|\s+$/g,"")&&a.classList.add("medium-editor-placeholder")},c=function(a){this.classList.remove("medium-editor-placeholder"),"keypress"!==a.type&&b(this)};for(a=0;a<this.elements.length;a+=1)b(this.elements[a]),this.elements[a].addEventListener("blur",c),this.elements[a].addEventListener("keypress",c);return this}}}(window,document);
function MediumEditor(a,b){"use strict";return this.init(a,b)}"object"==typeof module&&(module.exports=MediumEditor),function(a,b){"use strict";function c(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}function d(){var b,c,d,e=a.getSelection();if(e.getRangeAt&&e.rangeCount){for(d=[],b=0,c=e.rangeCount;c>b;b+=1)d.push(e.getRangeAt(b));return d}return null}function e(b){var c,d,e=a.getSelection();if(b)for(e.removeAllRanges(),c=0,d=b.length;d>c;c+=1)e.addRange(b[c])}function f(){var a=b.getSelection().anchorNode,c=a&&3===a.nodeType?a.parentNode:a;return c}function g(){var c,d,e,f,g="";if(void 0!==a.getSelection){if(d=a.getSelection(),d.rangeCount){for(f=b.createElement("div"),c=0,e=d.rangeCount;e>c;c+=1)f.appendChild(d.getRangeAt(c).cloneContents());g=f.innerHTML}}else void 0!==b.selection&&"Text"===b.selection.type&&(g=b.selection.createRange().htmlText);return g}function h(a){return!(!a||1!==a.nodeType)}MediumEditor.prototype={defaults:{allowMultiParagraphSelection:!0,anchorInputPlaceholder:"Paste or type a link",anchorPreviewHideDelay:500,buttons:["bold","italic","underline","anchor","header1","header2","quote"],buttonLabels:!1,checkLinkFormat:!1,cleanPastedHTML:!1,delay:0,diffLeft:0,diffTop:-10,disableReturn:!1,disableDoubleReturn:!1,disableToolbar:!1,firstHeader:"h3",forcePlainText:!0,placeholder:"Type your text",secondHeader:"h4",targetBlank:!1,extensions:{}},isIE:"Microsoft Internet Explorer"===navigator.appName||"Netscape"===navigator.appName&&null!==new RegExp("Trident/.*rv:([0-9]{1,}[.0-9]{0,})").exec(navigator.userAgent),init:function(a,d){return this.elements="string"==typeof a?b.querySelectorAll(a):a,1===this.elements.nodeType&&(this.elements=[this.elements]),0!==this.elements.length?(this.parentElements=["p","h1","h2","h3","h4","h5","h6","blockquote","pre"],this.id=b.querySelectorAll(".medium-editor-toolbar").length+1,this.options=c(d,this.defaults),this.setup()):void 0},setup:function(){this.isActive=!0,this.initElements().bindSelect().bindPaste().setPlaceholders().bindWindowActions()},initElements:function(){var a,b=!1;for(a=0;a<this.elements.length;a+=1)this.elements[a].setAttribute("contentEditable",!0),this.elements[a].getAttribute("data-placeholder")||this.elements[a].setAttribute("data-placeholder",this.options.placeholder),this.elements[a].setAttribute("data-medium-element",!0),this.bindParagraphCreation(a).bindReturn(a).bindTab(a),this.options.disableToolbar||this.elements[a].getAttribute("data-disable-toolbar")||(b=!0);return b&&this.initToolbar().bindButtons().bindAnchorForm().bindAnchorPreview(),this},serialize:function(){var a,b,c={};for(a=0;a<this.elements.length;a+=1)b=""!==this.elements[a].id?this.elements[a].id:"element-"+a,c[b]={value:this.elements[a].innerHTML.trim()};return c},callExtensions:function(a){if(!(arguments.length<1)){var b,c,d=Array.prototype.slice.call(arguments,1);for(c in this.options.extensions)this.options.extensions.hasOwnProperty(c)&&(b=this.options.extensions[c],void 0!==b[a]&&b[a].apply(b,d))}},bindParagraphCreation:function(a){var c=this;return this.elements[a].addEventListener("keyup",function(a){var d,e=f();e&&e.getAttribute("data-medium-element")&&0===e.children.length&&!c.options.disableReturn&&!e.getAttribute("data-disable-return")&&b.execCommand("formatBlock",!1,"p"),13===a.which&&(e=f(),d=e.tagName.toLowerCase(),c.options.disableReturn||this.getAttribute("data-disable-return")||"li"===d||c.isListItemChild(e)||(a.shiftKey||b.execCommand("formatBlock",!1,"p"),"a"===d&&b.execCommand("unlink",!1,null)))}),this},isListItemChild:function(a){for(var b=a.parentNode,c=b.tagName.toLowerCase();-1===this.parentElements.indexOf(c)&&"div"!==c;){if("li"===c)return!0;if(b=b.parentNode,!b||!b.tagName)return!1;c=b.tagName.toLowerCase()}return!1},bindReturn:function(a){var b=this;return this.elements[a].addEventListener("keypress",function(a){if(13===a.which)if(b.options.disableReturn||this.getAttribute("data-disable-return"))a.preventDefault();else if(b.options.disableDoubleReturn||this.getAttribute("data-disable-double-return")){var c=f();c&&"\n"===c.innerText&&a.preventDefault()}}),this},bindTab:function(a){return this.elements[a].addEventListener("keydown",function(a){if(9===a.which){var c=f().tagName.toLowerCase();"pre"===c&&(a.preventDefault(),b.execCommand("insertHtml",null," "))}}),this},buttonTemplate:function(a){var b=this.getButtonLabels(this.options.buttonLabels),c={bold:'<button class="medium-editor-action medium-editor-action-bold" data-action="bold" data-element="b">'+b.bold+"</button>",italic:'<button class="medium-editor-action medium-editor-action-italic" data-action="italic" data-element="i">'+b.italic+"</button>",underline:'<button class="medium-editor-action medium-editor-action-underline" data-action="underline" data-element="u">'+b.underline+"</button>",strikethrough:'<button class="medium-editor-action medium-editor-action-strikethrough" data-action="strikethrough" data-element="strike"><strike>A</strike></button>',superscript:'<button class="medium-editor-action medium-editor-action-superscript" data-action="superscript" data-element="sup">'+b.superscript+"</button>",subscript:'<button class="medium-editor-action medium-editor-action-subscript" data-action="subscript" data-element="sub">'+b.subscript+"</button>",anchor:'<button class="medium-editor-action medium-editor-action-anchor" data-action="anchor" data-element="a">'+b.anchor+"</button>",image:'<button class="medium-editor-action medium-editor-action-image" data-action="image" data-element="img">'+b.image+"</button>",header1:'<button class="medium-editor-action medium-editor-action-header1" data-action="append-'+this.options.firstHeader+'" data-element="'+this.options.firstHeader+'">'+b.header1+"</button>",header2:'<button class="medium-editor-action medium-editor-action-header2" data-action="append-'+this.options.secondHeader+'" data-element="'+this.options.secondHeader+'">'+b.header2+"</button>",quote:'<button class="medium-editor-action medium-editor-action-quote" data-action="append-blockquote" data-element="blockquote">'+b.quote+"</button>",orderedlist:'<button class="medium-editor-action medium-editor-action-orderedlist" data-action="insertorderedlist" data-element="ol">'+b.orderedlist+"</button>",unorderedlist:'<button class="medium-editor-action medium-editor-action-unorderedlist" data-action="insertunorderedlist" data-element="ul">'+b.unorderedlist+"</button>",pre:'<button class="medium-editor-action medium-editor-action-pre" data-action="append-pre" data-element="pre">'+b.pre+"</button>",indent:'<button class="medium-editor-action medium-editor-action-indent" data-action="indent" data-element="ul">'+b.indent+"</button>",outdent:'<button class="medium-editor-action medium-editor-action-outdent" data-action="outdent" data-element="ul">'+b.outdent+"</button>"};return c[a]||!1},getButtonLabels:function(a){var b,c,d={bold:"<b>B</b>",italic:"<b><i>I</i></b>",underline:"<b><u>U</u></b>",superscript:"<b>x<sup>1</sup></b>",subscript:"<b>x<sub>1</sub></b>",anchor:"<b>#</b>",image:"<b>image</b>",header1:"<b>H1</b>",header2:"<b>H2</b>",quote:"<b>&ldquo;</b>",orderedlist:"<b>1.</b>",unorderedlist:"<b>&bull;</b>",pre:"<b>0101</b>",indent:"<b>&rarr;</b>",outdent:"<b>&larr;</b>"};if("fontawesome"===a?b={bold:'<i class="fa fa-bold"></i>',italic:'<i class="fa fa-italic"></i>',underline:'<i class="fa fa-underline"></i>',superscript:'<i class="fa fa-superscript"></i>',subscript:'<i class="fa fa-subscript"></i>',anchor:'<i class="fa fa-link"></i>',image:'<i class="fa fa-picture-o"></i>',quote:'<i class="fa fa-quote-right"></i>',orderedlist:'<i class="fa fa-list-ol"></i>',unorderedlist:'<i class="fa fa-list-ul"></i>',pre:'<i class="fa fa-code fa-lg"></i>',indent:'<i class="fa fa-indent"></i>',outdent:'<i class="fa fa-outdent"></i>'}:"object"==typeof a&&(b=a),"object"==typeof b)for(c in b)b.hasOwnProperty(c)&&(d[c]=b[c]);return d},initToolbar:function(){return this.toolbar?this:(this.toolbar=this.createToolbar(),this.keepToolbarAlive=!1,this.anchorForm=this.toolbar.querySelector(".medium-editor-toolbar-form-anchor"),this.anchorInput=this.anchorForm.querySelector("input"),this.toolbarActions=this.toolbar.querySelector(".medium-editor-toolbar-actions"),this.anchorPreview=this.createAnchorPreview(),this)},createToolbar:function(){var a=b.createElement("div");return a.id="medium-editor-toolbar-"+this.id,a.className="medium-editor-toolbar",a.appendChild(this.toolbarButtons()),a.appendChild(this.toolbarFormAnchor()),b.body.appendChild(a),a},toolbarButtons:function(){var a,c,d,e,f=this.options.buttons,g=b.createElement("ul");for(g.id="medium-editor-toolbar-actions",g.className="medium-editor-toolbar-actions clearfix",c=0;c<f.length;c+=1)this.options.extensions.hasOwnProperty(f[c])?(e=this.options.extensions[f[c]],d=void 0!==e.getButton?e.getButton():null):d=this.buttonTemplate(f[c]),d&&(a=b.createElement("li"),h(d)?a.appendChild(d):a.innerHTML=d,g.appendChild(a));return g},toolbarFormAnchor:function(){var a=b.createElement("div"),c=b.createElement("input"),d=b.createElement("a");return d.setAttribute("href","#"),d.innerHTML="&times;",c.setAttribute("type","text"),c.setAttribute("placeholder",this.options.anchorInputPlaceholder),a.className="medium-editor-toolbar-form-anchor",a.id="medium-editor-toolbar-form-anchor",a.appendChild(c),a.appendChild(d),a},bindSelect:function(){var a,c=this,d="";for(this.checkSelectionWrapper=function(a){return a&&c.clickingIntoArchorForm(a)?!1:(clearTimeout(d),void(d=setTimeout(function(){c.checkSelection()},c.options.delay)))},b.documentElement.addEventListener("mouseup",this.checkSelectionWrapper),a=0;a<this.elements.length;a+=1)this.elements[a].addEventListener("keyup",this.checkSelectionWrapper),this.elements[a].addEventListener("blur",this.checkSelectionWrapper);return this},checkSelection:function(){var b,c;return this.keepToolbarAlive===!0||this.options.disableToolbar||(b=a.getSelection(),""===b.toString().trim()||this.options.allowMultiParagraphSelection===!1&&this.hasMultiParagraphs()?this.hideToolbarActions():(c=this.getSelectionElement(),!c||c.getAttribute("data-disable-toolbar")?this.hideToolbarActions():this.checkSelectionElement(b,c))),this},clickingIntoArchorForm:function(a){var b=this;return a.type&&"blur"===a.type.toLowerCase()&&a.relatedTarget&&a.relatedTarget===b.anchorInput?!0:!1},hasMultiParagraphs:function(){var a=g().replace(/<[\S]+><\/[\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,b){var c;for(this.selection=a,this.selectionRange=this.selection.getRangeAt(0),c=0;c<this.elements.length;c+=1)if(this.elements[c]===b)return void this.setToolbarButtonStates().setToolbarPosition().showToolbarActions();this.hideToolbarActions()},getSelectionElement:function(){var b,c,d,e,f=a.getSelection(),g=function(a){var b=a;try{for(;!b.getAttribute("data-medium-element");)b=b.parentNode}catch(c){return!1}return b};try{b=f.getRangeAt(0),c=b.commonAncestorContainer,d=c.parentNode,e=c.getAttribute("data-medium-element")?c:g(d)}catch(h){e=g(d)}return e},setToolbarPosition:function(){var b=50,c=a.getSelection(),d=c.getRangeAt(0),e=d.getBoundingClientRect(),f=this.options.diffLeft-this.toolbar.offsetWidth/2,g=(e.left+e.right)/2,h=this.toolbar.offsetWidth/2;return e.top<b?(this.toolbar.classList.add("medium-toolbar-arrow-over"),this.toolbar.classList.remove("medium-toolbar-arrow-under"),this.toolbar.style.top=b+e.bottom-this.options.diffTop+a.pageYOffset-this.toolbar.offsetHeight+"px"):(this.toolbar.classList.add("medium-toolbar-arrow-under"),this.toolbar.classList.remove("medium-toolbar-arrow-over"),this.toolbar.style.top=e.top+this.options.diffTop+a.pageYOffset-this.toolbar.offsetHeight+"px"),this.toolbar.style.left=h>g?f+h+"px":a.innerWidth-g<h?a.innerWidth+f-h+"px":f+g+"px",this.hideAnchorPreview(),this},setToolbarButtonStates:function(){var a,b=this.toolbarActions.querySelectorAll("button");for(a=0;a<b.length;a+=1)b[a].classList.remove("medium-editor-button-active");return this.checkActiveButtons(),this},checkActiveButtons:function(){var a=Array.prototype.slice.call(this.elements),b=this.selection.anchorNode;for(b.tagName||(b=this.selection.anchorNode.parentNode);void 0!==b.tagName&&-1===this.parentElements.indexOf(b.tagName.toLowerCase)&&(this.activateButton(b.tagName.toLowerCase()),this.callExtensions("checkState",b),-1===a.indexOf(b));)b=b.parentNode},activateButton:function(a){var b=this.toolbar.querySelector('[data-element="'+a+'"]');null!==b&&-1===b.className.indexOf("medium-editor-button-active")&&(b.className+=" medium-editor-button-active")},bindButtons:function(){var a,b=this.toolbar.querySelectorAll("button"),c=this,d=function(a){a.preventDefault(),a.stopPropagation(),void 0===c.selection&&c.checkSelection(),this.className.indexOf("medium-editor-button-active")>-1?this.classList.remove("medium-editor-button-active"):this.className+=" medium-editor-button-active",this.hasAttribute("data-action")&&c.execAction(this.getAttribute("data-action"),a)};for(a=0;a<b.length;a+=1)b[a].addEventListener("click",d);return this.setFirstAndLastItems(b),this},setFirstAndLastItems:function(a){return a.length>0&&(a[0].className+=" medium-editor-button-first",a[a.length-1].className+=" medium-editor-button-last"),this},execAction:function(c,d){c.indexOf("append-")>-1?(this.execFormatBlock(c.replace("append-","")),this.setToolbarPosition(),this.setToolbarButtonStates()):"anchor"===c?this.triggerAnchorAction(d):"image"===c?b.execCommand("insertImage",!1,a.getSelection()):(b.execCommand(c,!1,null),this.setToolbarPosition())},triggerAnchorAction:function(){return"a"===this.selection.anchorNode.parentNode.tagName.toLowerCase()?b.execCommand("unlink",!1,null):"block"===this.anchorForm.style.display?this.showToolbarActions():this.showAnchorForm(),this},execFormatBlock:function(a){var c=this.getSelectionData(this.selection.anchorNode);if("blockquote"===a&&c.el&&"blockquote"===c.el.parentNode.tagName.toLowerCase())return b.execCommand("outdent",!1,null);if(c.tagName===a&&(a="p"),this.isIE){if("blockquote"===a)return b.execCommand("indent",!1,a);a="<"+a+">"}return b.execCommand("formatBlock",!1,a)},getSelectionData:function(a){var b;for(a&&a.tagName&&(b=a.tagName.toLowerCase());a&&-1===this.parentElements.indexOf(b);)a=a.parentNode,a&&a.tagName&&(b=a.tagName.toLowerCase());return{el:a,tagName:b}},getFirstChild:function(a){for(var b=a.firstChild;null!==b&&1!==b.nodeType;)b=b.nextSibling;return b},hideToolbarActions:function(){this.keepToolbarAlive=!1,void 0!==this.toolbar&&this.toolbar.classList.remove("medium-editor-toolbar-active")},showToolbarActions:function(){var a,b=this;this.anchorForm.style.display="none",this.toolbarActions.style.display="block",this.keepToolbarAlive=!1,clearTimeout(a),a=setTimeout(function(){b.toolbar&&!b.toolbar.classList.contains("medium-editor-toolbar-active")&&b.toolbar.classList.add("medium-editor-toolbar-active")},100)},showAnchorForm:function(a){this.toolbarActions.style.display="none",this.savedSelection=d(),this.anchorForm.style.display="block",this.keepToolbarAlive=!0,this.anchorInput.focus(),this.anchorInput.value=a||""},bindAnchorForm:function(){var a=this.anchorForm.querySelector("a"),b=this;return this.anchorForm.addEventListener("click",function(a){a.stopPropagation()}),this.anchorInput.addEventListener("keyup",function(a){13===a.keyCode&&(a.preventDefault(),b.createLink(this))}),this.anchorInput.addEventListener("click",function(a){a.stopPropagation(),b.keepToolbarAlive=!0}),this.anchorInput.addEventListener("blur",function(){b.keepToolbarAlive=!1,b.checkSelection()}),a.addEventListener("click",function(a){a.preventDefault(),b.showToolbarActions(),e(b.savedSelection)}),this},hideAnchorPreview:function(){this.anchorPreview.classList.remove("medium-editor-anchor-preview-active")},showAnchorPreview:function(b){if(this.anchorPreview.classList.contains("medium-editor-anchor-preview-active"))return!0;var c,d,e,f=this,g=40,h=b.getBoundingClientRect(),i=(h.left+h.right)/2;return f.anchorPreview.querySelector("i").innerHTML=b.href,c=f.anchorPreview.offsetWidth/2,d=f.options.diffLeft-c,clearTimeout(e),e=setTimeout(function(){f.anchorPreview&&!f.anchorPreview.classList.contains("medium-editor-anchor-preview-active")&&f.anchorPreview.classList.add("medium-editor-anchor-preview-active")},100),f.observeAnchorPreview(b),f.anchorPreview.classList.add("medium-toolbar-arrow-over"),f.anchorPreview.classList.remove("medium-toolbar-arrow-under"),f.anchorPreview.style.top=Math.round(g+h.bottom-f.options.diffTop+a.pageYOffset-f.anchorPreview.offsetHeight)+"px",f.anchorPreview.style.left=c>i?d+c+"px":a.innerWidth-i<c?a.innerWidth+d-c+"px":d+i+"px",this},observeAnchorPreview:function(a){var b=this,c=(new Date).getTime(),d=!0,e=function(){c=(new Date).getTime(),d=!0},f=function(a){a.relatedTarget&&/anchor-preview/.test(a.relatedTarget.className)||(d=!1)},g=setInterval(function(){if(d)return!0;var h=(new Date).getTime()-c;h>b.options.anchorPreviewHideDelay&&(b.hideAnchorPreview(),clearInterval(g),b.anchorPreview.removeEventListener("mouseover",e),b.anchorPreview.removeEventListener("mouseout",f),a.removeEventListener("mouseover",e),a.removeEventListener("mouseout",f))},200);b.anchorPreview.addEventListener("mouseover",e),b.anchorPreview.addEventListener("mouseout",f),a.addEventListener("mouseover",e),a.addEventListener("mouseout",f)},createAnchorPreview:function(){var a=this,c=b.createElement("div");return c.id="medium-editor-anchor-preview-"+this.id,c.className="medium-editor-anchor-preview",c.innerHTML=this.anchorPreviewTemplate(),b.body.appendChild(c),c.addEventListener("click",function(){a.anchorPreviewClickHandler()}),c},anchorPreviewTemplate:function(){return'<div class="medium-editor-toolbar-anchor-preview" id="medium-editor-toolbar-anchor-preview"> <i class="medium-editor-toolbar-anchor-preview-inner"></i></div>'},anchorPreviewClickHandler:function(){if(this.activeAnchor){var c=this,d=b.createRange(),e=a.getSelection();d.selectNodeContents(c.activeAnchor),e.removeAllRanges(),e.addRange(d),setTimeout(function(){c.activeAnchor&&c.showAnchorForm(c.activeAnchor.href),c.keepToolbarAlive=!1},100+c.options.delay)}this.hideAnchorPreview()},editorAnchorObserver:function(a){var b=this,c=!0,d=function(){c=!1,b.activeAnchor.removeEventListener("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.toolbar.classList.contains("medium-editor-toolbar-active"))return!0;this.activeAnchor=a.target,this.activeAnchor.addEventListener("mouseout",d),setTimeout(function(){c&&b.showAnchorPreview(a.target)},b.options.delay)}},bindAnchorPreview:function(){var a,b=this;for(this.editorAnchorObserverWrapper=function(a){b.editorAnchorObserver(a)},a=0;a<this.elements.length;a+=1)this.elements[a].addEventListener("mouseover",this.editorAnchorObserverWrapper);return this},checkLinkFormat:function(a){var b=/^https?:\/\//;return a.match(b)?a:"http://"+a},setTargetBlank:function(){var a,b=f();if("a"===b.tagName.toLowerCase())b.target="_blank";else for(b=b.getElementsByTagName("a"),a=0;a<b.length;a+=1)b[a].target="_blank"},createLink:function(a){e(this.savedSelection),this.options.checkLinkFormat&&(a.value=this.checkLinkFormat(a.value)),b.execCommand("createLink",!1,a.value),this.options.targetBlank&&this.setTargetBlank(),this.showToolbarActions(),a.value=""},bindWindowActions:function(){var b,c=this;return this.windowResizeHandler=function(){clearTimeout(b),b=setTimeout(function(){c.toolbar&&c.toolbar.classList.contains("medium-editor-toolbar-active")&&c.setToolbarPosition()},100)},a.addEventListener("resize",this.windowResizeHandler),this},activate:function(){this.isActive||this.setup()},deactivate:function(){var c;if(this.isActive)for(this.isActive=!1,void 0!==this.toolbar&&(b.body.removeChild(this.anchorPreview),b.body.removeChild(this.toolbar),delete this.toolbar,delete this.anchorPreview),b.documentElement.removeEventListener("mouseup",this.checkSelectionWrapper),a.removeEventListener("resize",this.windowResizeHandler),c=0;c<this.elements.length;c+=1)this.elements[c].removeEventListener("mouseover",this.editorAnchorObserverWrapper),this.elements[c].removeEventListener("keyup",this.checkSelectionWrapper),this.elements[c].removeEventListener("blur",this.checkSelectionWrapper),this.elements[c].removeEventListener("paste",this.pasteWrapper),this.elements[c].removeAttribute("contentEditable"),this.elements[c].removeAttribute("data-medium-element")},htmlEntities:function(a){return String(a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")},bindPaste:function(){var a,c=this;for(this.pasteWrapper=function(a){var d,e,f="";if(this.classList.remove("medium-editor-placeholder"),!c.options.forcePlainText&&!c.options.cleanPastedHTML)return this;if(a.clipboardData&&a.clipboardData.getData&&!a.defaultPrevented){if(a.preventDefault(),c.options.cleanPastedHTML&&a.clipboardData.getData("text/html"))return c.cleanPaste(a.clipboardData.getData("text/html"));if(c.options.disableReturn)b.execCommand("insertHTML",!1,a.clipboardData.getData("text/plain"));else{for(d=a.clipboardData.getData("text/plain").split(/[\r\n]/g),e=0;e<d.length;e+=1)""!==d[e]&&(f+=navigator.userAgent.match(/firefox/i)&&0===e?c.htmlEntities(d[e]):"<p>"+c.htmlEntities(d[e])+"</p>");b.execCommand("insertHTML",!1,f)}}},a=0;a<this.elements.length;a+=1)this.elements[a].addEventListener("paste",this.pasteWrapper);return this},setPlaceholders:function(){var a,b=function(a){""===a.textContent.replace(/^\s+|\s+$/g,"")&&a.classList.add("medium-editor-placeholder")},c=function(a){this.classList.remove("medium-editor-placeholder"),"keypress"!==a.type&&b(this)};for(a=0;a<this.elements.length;a+=1)b(this.elements[a]),this.elements[a].addEventListener("blur",c),this.elements[a].addEventListener("keypress",c);return this},cleanPaste:function(a){var c,d,e,f=this.getSelectionElement(),g=/<p|<br|<div/.test(a),h=[[new RegExp(/<[^>]*docs-internal-guid[^>]*>/gi),""],[new RegExp(/<\/b>(<br[^>]*>)?$/gi),""],[new RegExp(/<span class="Apple-converted-space">\s+<\/span>/g)," "],[new RegExp(/<br class="Apple-interchange-newline">/g),"<br>"],[new RegExp(/<span[^>]*(font-style:italic;font-weight:bold|font-weight:bold;font-style:italic)[^>]*>/gi),'<span class="replace-with italic bold">'],[new RegExp(/<span[^>]*font-style:italic[^>]*>/gi),'<span class="replace-with italic">'],[new RegExp(/<span[^>]*font-weight:bold[^>]*>/gi),'<span class="replace-with bold">'],[new RegExp(/&lt;(\/?)(i|b|a)&gt;/gi),"<$1$2>"],[new RegExp(/&lt;a\s+href=(&quot;|&rdquo;|&ldquo;|“|”)([^&]+)(&quot;|&rdquo;|&ldquo;|“|”)&gt;/gi),'<a href="$2">']];for(c=0;c<h.length;c+=1)a=a.replace(h[c][0],h[c][1]);if(g)for(d=a.split("<br><br>"),this.pasteHTML("<p>"+d.join("</p><p>")+"</p>"),b.execCommand("insertText",!1,"\n"),d=f.querySelectorAll("p,div,br"),c=0;c<d.length;c+=1)switch(e=d[c],e.tagName.toLowerCase()){case"p":case"div":this.filterCommonBlocks(e);break;case"br":this.filterLineBreak(e)}else this.pasteHTML(a)},pasteHTML:function(a){var c,d,e,f,g=b.createDocumentFragment();for(g.appendChild(b.createElement("body")),f=g.querySelector("body"),f.innerHTML=a,this.cleanupSpans(f),c=f.querySelectorAll("*"),e=0;e<c.length;e+=1)d=c[e],d.removeAttribute("class"),d.removeAttribute("style"),d.removeAttribute("dir"),"meta"===d.tagName.toLowerCase()&&d.parentNode.removeChild(d);b.execCommand("insertHTML",!1,f.innerHTML.replace(/&nbsp;/g," "))},isCommonBlock:function(a){return a&&("p"===a.tagName.toLowerCase()||"div"===a.tagName.toLowerCase())},filterCommonBlocks:function(a){/^\s*$/.test(a.innerText)&&a.parentNode.removeChild(a)},filterLineBreak:function(a){this.isCommonBlock(a.previousElementSibling)?a.parentNode.removeChild(a):!this.isCommonBlock(a.parentNode)||a.parentNode.firstChild!==a&&a.parentNode.lastChild!==a?1===a.parentNode.childElementCount&&this.removeWithParent(a):a.parentNode.removeChild(a)},removeWithParent:function(a){a&&a.parentNode&&(a.parentNode.parentNode&&1===a.parentNode.childElementCount?a.parentNode.parentNode.removeChild(a.parentNode):a.parentNode.removeChild(a.parentNode))},cleanupSpans:function(a){var c,d,e,f=a.querySelectorAll(".replace-with");for(c=0;c<f.length;c+=1)d=f[c],e=b.createElement(d.classList.contains("bold")?"b":"i"),e.innerHTML=d.classList.contains("bold")&&d.classList.contains("italic")?"<i>"+d.innerHTML+"</i>":d.innerHTML,d.parentNode.replaceChild(e,d);for(f=a.querySelectorAll("span"),c=0;c<f.length;c+=1)d=f[c],/^\s*$/.test()?d.parentNode.removeChild(d):d.parentNode.replaceChild(b.createTextNode(d.innerText),d)}}}(window,document);

@@ -6,6 +6,11 @@ /*global module, require*/

var gruntConfig = {
pkg: grunt.file.readJSON('package.json')
},
autoprefixerBrowsers = ['last 3 versions', 'ie >= 9'];
var autoprefixerBrowsers = ['last 3 versions', 'ie >= 9'],
globalConfig = {
src: 'src',
dest: 'dev'
},
gruntConfig = {
pkg: grunt.file.readJSON('package.json'),
globalConfig: globalConfig
};

@@ -69,2 +74,9 @@ gruntConfig.jsbeautifier = {

}
},
spec: {
src: 'src/js/**/*.js',
options: {
specs: ['spec/<%= globalConfig.file %>.spec.js'],
helpers: 'spec/helpers/*.js'
}
}

@@ -174,7 +186,12 @@ };

grunt.registerTask('test', ['jsbeautifier', 'jslint', 'jasmine', 'csslint']);
grunt.registerTask('js', ['jsbeautifier', 'jslint', 'jasmine', 'uglify', 'concat']);
grunt.registerTask('test', ['jsbeautifier', 'jslint', 'jasmine:suite', 'csslint']);
grunt.registerTask('js', ['jsbeautifier', 'jslint', 'jasmine:suite', 'uglify', 'concat']);
grunt.registerTask('css', ['sass', 'autoprefixer', 'csslint']);
grunt.registerTask('default', ['js', 'css']);
grunt.registerTask('spec', 'Runs a task on a specified file', function (taskName, fileName) {
globalConfig.file = fileName;
grunt.task.run(taskName + ':spec');
});
};
{
"name": "medium-editor",
"version": "1.7.5",
"version": "1.8.0",
"author": "Davi Ferreira <hi@daviferreira.com>",

@@ -31,3 +31,3 @@ "description": "Medium.com WYSIWYG editor clone.",

"grunt-contrib-watch": "~0.6.1",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-concat": "~0.4.0",
"grunt-template-jasmine-istanbul": "~0.3.1",

@@ -34,0 +34,0 @@ "grunt-plato": "~1.0.0",

@@ -57,2 +57,5 @@ # MediumEditor

* __buttonLabels__: type of labels on the buttons. Values: 'fontawesome', `{'bold': '<b>b</b>', 'italic': '<i>i</i>'}`. Default: false
* __checkLinkFormat__: enables/disables check for http on anchor links. Default:
false
* __cleanPastedHTML__: cleans pasted content from different sources, like google docs etc. Default: false
* __delay__: time in milliseconds to show the toolbar or anchor tag preview. Default: 0

@@ -68,4 +71,4 @@ * __diffLeft__: value in pixels to be added to the X axis positioning of the toolbar. Default: 0

* __secondHeader__: HTML tag to be used as second header. Default: h4
* __targetBlank__: enables/disables target="\_blank" for anchor tags. Default:
false
* __targetBlank__: enables/disables target="\_blank" for anchor tags. Default: false
* __extensions__: extension to use (see _Extensions_) for more. Default: {}

@@ -127,2 +130,54 @@ Example:

## Extensions
To add additional additional functions that are not supported by the native [browser API](https://developer.mozilla.org/de/docs/Rich-Text_Editing_in_Mozilla) you can
write extensions that are then integrated into the toolbar. The Extension API is currently unstable and very minimal.
An extension is an object that has essentially two functions `getButton` and `checkState`.
* `getButton` is called when the editor is initialized and should return a element that is integrated into the toolbar.
Usually this will be a `<button>` element like the onces Medium Editor uses. All event handling on this button is
_entirely up to you_ so you should either keep a reference or bind your eventhandlers before returning it. You can
also return a HTML-String that is then integrated into the toolbar also this is not really useful.
* `checkState` is called whenever a user selects some text in the area where the Medium Editor instance is running. It's
responsability is to toggle the current _state_ of the button. I.e. marking is a _on_ or _off_. Again the method on how
determine the state is entirely up to you. `checkState` will be called multiple times and will receive a [DOM `Element`](https://developer.mozilla.org/en-US/docs/Web/API/element)
as parameter.
### Example
A simple example the uses [rangy](https://code.google.com/p/rangy/) and the [CSS Class Applier Module](https://code.google.com/p/rangy/wiki/CSSClassApplierModule) to support highlighting of text:
rangy.init();
function Highlighter() {
this.button = document.createElement('button');
this.button.className = 'medium-editor-action';
this.button.innerText = 'H';
this.button.onclick = this.onClick.bind(this);
this.classApplier = rangy.createCssClassApplier("highlight", {
elementTagName: 'mark',
normalize: true
});
}
Highlighter.prototype.onClick = function() {
this.classApplier.toggleSelection();
}
Highlighter.prototype.getButton = function() {
return this.button;
}
Highlighter.prototype.checkState = function (node) {
if(node.tagName == 'MARK') {
this.button.classList.add('medium-editor-button-active');
}
}
var e = new MediumEditor('.editor', {
buttons: ['highlight', 'bold', 'italic', 'underline'],
extensions: {
'highlight': new Highlighter()
}
});
## Image Upload

@@ -132,3 +187,6 @@

## Rails Gem
[Ahmet Sezgin Duran](https://github.com/marjinal1st/) gemified Medium Editor for Rails asset pipeline, check it out at [https://github.com/marjinal1st/medium-editor-rails](https://github.com/marjinal1st/medium-editor-rails).
## Angular directive

@@ -172,25 +230,27 @@

```
project : medium-editor
repo age : 10 months
active : 116 days
commits : 455
files : 47
project : medium-editor
repo age : 11 months
active : 129 days
commits : 493
files : 50
authors :
337 Davi Ferreira 74.1%
20 Maxime de Visscher 4.4%
8 Andy Yaco-Mink 1.8%
8 Derek Odegard 1.8%
8 Jarl Gunnar T. Flaten 1.8%
8 Pedro Nasser 1.8%
8 Seif 1.8%
4 Sebastian Zuchmanski 0.9%
4 minikomi 0.9%
3 Andrew Hubbs 0.7%
3 Dmitri Cherniak 0.7%
3 Nikita Korotaev 0.7%
3 Troels Knak-Nielsen 0.7%
3 arol 0.7%
3 ʞuıɯ-oɔɐʎ ʎpuɐ 0.7%
363 Davi Ferreira 73.6%
20 Maxime de Visscher 4.1%
12 Andy Yaco-Mink 2.4%
8 Derek Odegard 1.6%
8 Jarl Gunnar T. Flaten 1.6%
8 Pedro Nasser 1.6%
8 Seif 1.6%
5 Martin Thurau 1.0%
4 Sebastian Zuchmanski 0.8%
4 minikomi 0.8%
3 Andrew Hubbs 0.6%
3 Dmitri Cherniak 0.6%
3 Nikita Korotaev 0.6%
3 Troels Knak-Nielsen 0.6%
3 arol 0.6%
3 ʞuıɯ-oɔɐʎ ʎpuɐ 0.6%
2 Ethan Turkeltaub 0.4%
2 Jacob Magnusson 0.4%
2 OmniaGM 0.4%
1 Adam Mulligan 0.2%

@@ -214,2 +274,3 @@ 1 Alberto Gasparin 0.2%

1 Robert Koritnik 0.2%
1 Scott Carleton 0.2%
1 Søren Torp Petersen 0.2%

@@ -224,4 +285,3 @@ 1 Tom MacWright 0.2%

1 waffleio 0.2%
1 zzjin 0.2%
```
1 zzjin 0.2%```

@@ -228,0 +288,0 @@ ## License

@@ -1,2 +0,2 @@

/*global MediumEditor, describe, it, expect, spyOn,
/*global MediumEditor, describe, it, expect, spyOn, jasmine, fireEvent,
afterEach, beforeEach, selectElementContents, runs, waitsFor,

@@ -11,2 +11,3 @@ tearDown */

this.el.className = 'editor';
this.el.textContent = 'lore ipsum';
document.body.appendChild(this.el);

@@ -40,2 +41,11 @@ });

describe('Deactivate', function () {
beforeEach(function () {
jasmine.clock().install();
});
afterEach(function () {
jasmine.clock().uninstall();
});
it('should remove mediumEditor elements from DOM', function () {

@@ -49,3 +59,17 @@ var editor = new MediumEditor('.editor');

});
// regression test for https://github.com/daviferreira/medium-editor/issues/197
it('should not crash when deactivated immediately after a mouse click', function () {
var editor = new MediumEditor('.editor');
// selected some content and let the toolbar appear
selectElementContents(editor.elements[0]);
jasmine.clock().tick(501);
// fire a mouse up somewhere else (i.e. a button which click handler could have called deactivate() )
fireEvent(document.documentElement, 'mouseup');
editor.deactivate();
jasmine.clock().tick(501);
});
});
});

@@ -83,2 +83,13 @@ /*global MediumEditor, describe, it, expect, spyOn,

it('should add http:// if need be and checkLinkFormat option is set to true', function () {
var editor = new MediumEditor('.editor', {
checkLinkFormat: true
}),
input = editor.anchorForm.querySelector('input');
selectElementContents(editor.elements[0]);
input.value = 'test.com';
editor.createLink(input);
expect(editor.elements[0].querySelector('a').href).toBe('http://test.com/');
});
it('should add target="_blank" when respective option is set to true', function () {

@@ -85,0 +96,0 @@ var editor = new MediumEditor('.editor', {

@@ -84,2 +84,3 @@ /*global MediumEditor, describe, it, expect, spyOn,

forcePlainText: true,
cleanPastedHTML: false,
allowMultiParagraphSelection: true,

@@ -91,3 +92,5 @@ placeholder: 'Type your text',

targetBlank: false,
anchorPreviewHideDelay: 500
anchorPreviewHideDelay: 500,
checkLinkFormat: false,
extensions: {}
},

@@ -94,0 +97,0 @@ editor = new MediumEditor('.editor');

@@ -31,3 +31,3 @@ /*global MediumEditor, describe, it, expect, spyOn,

it('should set a custom id when elements have no ids', function () {
this.el.id = null;
this.el.removeAttribute('id');
var editor = new MediumEditor('.editor'),

@@ -34,0 +34,0 @@ json = editor.serialize();

@@ -90,2 +90,7 @@ /*global module, console*/

// https://github.com/jashkenas/underscore
function isElement(obj) {
return !!(obj && obj.nodeType === 1);
}
MediumEditor.prototype = {

@@ -95,4 +100,7 @@ defaults: {

anchorInputPlaceholder: 'Paste or type a link',
anchorPreviewHideDelay: 500,
buttons: ['bold', 'italic', 'underline', 'anchor', 'header1', 'header2', 'quote'],
buttonLabels: false,
checkLinkFormat: false,
cleanPastedHTML: false,
delay: 0,

@@ -109,3 +117,3 @@ diffLeft: 0,

targetBlank: false,
anchorPreviewHideDelay: 500
extensions: {}
},

@@ -149,3 +157,3 @@

this.elements[i].setAttribute('data-medium-element', true);
this.bindParagraphCreation(i).bindReturn(i).bindTab(i).bindAnchorPreview(i);
this.bindParagraphCreation(i).bindReturn(i).bindTab(i);
if (!this.options.disableToolbar && !this.elements[i].getAttribute('data-disable-toolbar')) {

@@ -159,3 +167,4 @@ addToolbar = true;

.bindButtons()
.bindAnchorForm();
.bindAnchorForm()
.bindAnchorPreview();
}

@@ -178,2 +187,28 @@ return this;

/**
* Helper function to call a method with a number of parameters on all registered extensions.
* The function assures that the function exists before calling.
*
* @param {string} funcName name of the function to call
* @param [args] arguments passed into funcName
*/
callExtensions: function (funcName) {
if (arguments.length < 1) {
return;
}
var args = Array.prototype.slice.call(arguments, 1),
ext,
name;
for (name in this.options.extensions) {
if (this.options.extensions.hasOwnProperty(name)) {
ext = this.options.extensions[name];
if (ext[funcName] !== undefined) {
ext[funcName].apply(ext, args);
}
}
}
},
bindParagraphCreation: function (index) {

@@ -255,18 +290,18 @@ var self = this;

buttonTemplates = {
'bold': '<li><button class="medium-editor-action medium-editor-action-bold" data-action="bold" data-element="b">' + buttonLabels.bold + '</button></li>',
'italic': '<li><button class="medium-editor-action medium-editor-action-italic" data-action="italic" data-element="i">' + buttonLabels.italic + '</button></li>',
'underline': '<li><button class="medium-editor-action medium-editor-action-underline" data-action="underline" data-element="u">' + buttonLabels.underline + '</button></li>',
'strikethrough': '<li><button class="medium-editor-action medium-editor-action-strikethrough" data-action="strikethrough" data-element="strike"><strike>A</strike></button></li>',
'superscript': '<li><button class="medium-editor-action medium-editor-action-superscript" data-action="superscript" data-element="sup">' + buttonLabels.superscript + '</button></li>',
'subscript': '<li><button class="medium-editor-action medium-editor-action-subscript" data-action="subscript" data-element="sub">' + buttonLabels.subscript + '</button></li>',
'anchor': '<li><button class="medium-editor-action medium-editor-action-anchor" data-action="anchor" data-element="a">' + buttonLabels.anchor + '</button></li>',
'image': '<li><button class="medium-editor-action medium-editor-action-image" data-action="image" data-element="img">' + buttonLabels.image + '</button></li>',
'header1': '<li><button class="medium-editor-action medium-editor-action-header1" data-action="append-' + this.options.firstHeader + '" data-element="' + this.options.firstHeader + '">' + buttonLabels.header1 + '</button></li>',
'header2': '<li><button class="medium-editor-action medium-editor-action-header2" data-action="append-' + this.options.secondHeader + '" data-element="' + this.options.secondHeader + '">' + buttonLabels.header2 + '</button></li>',
'quote': '<li><button class="medium-editor-action medium-editor-action-quote" data-action="append-blockquote" data-element="blockquote">' + buttonLabels.quote + '</button></li>',
'orderedlist': '<li><button class="medium-editor-action medium-editor-action-orderedlist" data-action="insertorderedlist" data-element="ol">' + buttonLabels.orderedlist + '</button></li>',
'unorderedlist': '<li><button class="medium-editor-action medium-editor-action-unorderedlist" data-action="insertunorderedlist" data-element="ul">' + buttonLabels.unorderedlist + '</button></li>',
'pre': '<li><button class="medium-editor-action medium-editor-action-pre" data-action="append-pre" data-element="pre">' + buttonLabels.pre + '</button></li>',
'indent': '<li><button class="medium-editor-action medium-editor-action-indent" data-action="indent" data-element="ul">' + buttonLabels.indent + '</button></li>',
'outdent': '<li><button class="medium-editor-action medium-editor-action-outdent" data-action="outdent" data-element="ul">' + buttonLabels.outdent + '</button></li>'
'bold': '<button class="medium-editor-action medium-editor-action-bold" data-action="bold" data-element="b">' + buttonLabels.bold + '</button>',
'italic': '<button class="medium-editor-action medium-editor-action-italic" data-action="italic" data-element="i">' + buttonLabels.italic + '</button>',
'underline': '<button class="medium-editor-action medium-editor-action-underline" data-action="underline" data-element="u">' + buttonLabels.underline + '</button>',
'strikethrough': '<button class="medium-editor-action medium-editor-action-strikethrough" data-action="strikethrough" data-element="strike"><strike>A</strike></button>',
'superscript': '<button class="medium-editor-action medium-editor-action-superscript" data-action="superscript" data-element="sup">' + buttonLabels.superscript + '</button>',
'subscript': '<button class="medium-editor-action medium-editor-action-subscript" data-action="subscript" data-element="sub">' + buttonLabels.subscript + '</button>',
'anchor': '<button class="medium-editor-action medium-editor-action-anchor" data-action="anchor" data-element="a">' + buttonLabels.anchor + '</button>',
'image': '<button class="medium-editor-action medium-editor-action-image" data-action="image" data-element="img">' + buttonLabels.image + '</button>',
'header1': '<button class="medium-editor-action medium-editor-action-header1" data-action="append-' + this.options.firstHeader + '" data-element="' + this.options.firstHeader + '">' + buttonLabels.header1 + '</button>',
'header2': '<button class="medium-editor-action medium-editor-action-header2" data-action="append-' + this.options.secondHeader + '" data-element="' + this.options.secondHeader + '">' + buttonLabels.header2 + '</button>',
'quote': '<button class="medium-editor-action medium-editor-action-quote" data-action="append-blockquote" data-element="blockquote">' + buttonLabels.quote + '</button>',
'orderedlist': '<button class="medium-editor-action medium-editor-action-orderedlist" data-action="insertorderedlist" data-element="ol">' + buttonLabels.orderedlist + '</button>',
'unorderedlist': '<button class="medium-editor-action medium-editor-action-unorderedlist" data-action="insertunorderedlist" data-element="ul">' + buttonLabels.unorderedlist + '</button>',
'pre': '<button class="medium-editor-action medium-editor-action-pre" data-action="append-pre" data-element="pre">' + buttonLabels.pre + '</button>',
'indent': '<button class="medium-editor-action medium-editor-action-indent" data-action="indent" data-element="ul">' + buttonLabels.indent + '</button>',
'outdent': '<button class="medium-editor-action medium-editor-action-outdent" data-action="outdent" data-element="ul">' + buttonLabels.outdent + '</button>'
};

@@ -326,23 +361,2 @@ return buttonTemplates[btnType] || false;

//TODO: actionTemplate
toolbarTemplate: function () {
var btns = this.options.buttons,
html = '<ul id="medium-editor-toolbar-actions" class="medium-editor-toolbar-actions clearfix">',
i,
tpl;
for (i = 0; i < btns.length; i += 1) {
tpl = this.buttonTemplate(btns[i]);
if (tpl) {
html += tpl;
}
}
html += '</ul>' +
'<div class="medium-editor-toolbar-form-anchor" id="medium-editor-toolbar-form-anchor">' +
' <input type="text" value="" placeholder="' + this.options.anchorInputPlaceholder + '">' +
' <a href="#">&times;</a>' +
'</div>';
return html;
},
initToolbar: function () {

@@ -366,3 +380,4 @@ if (this.toolbar) {

toolbar.className = 'medium-editor-toolbar';
toolbar.innerHTML = this.toolbarTemplate();
toolbar.appendChild(this.toolbarButtons());
toolbar.appendChild(this.toolbarFormAnchor());
document.body.appendChild(toolbar);

@@ -372,2 +387,55 @@ return toolbar;

//TODO: actionTemplate
toolbarButtons: function () {
var btns = this.options.buttons,
ul = document.createElement('ul'),
li,
i,
btn,
ext;
ul.id = 'medium-editor-toolbar-actions';
ul.className = 'medium-editor-toolbar-actions clearfix';
for (i = 0; i < btns.length; i += 1) {
if (this.options.extensions.hasOwnProperty(btns[i])) {
ext = this.options.extensions[btns[i]];
btn = ext.getButton !== undefined ? ext.getButton() : null;
} else {
btn = this.buttonTemplate(btns[i]);
}
if (btn) {
li = document.createElement('li');
if (isElement(btn)) {
li.appendChild(btn);
} else {
li.innerHTML = btn;
}
ul.appendChild(li);
}
}
return ul;
},
toolbarFormAnchor: function () {
var anchor = document.createElement('div'),
input = document.createElement('input'),
a = document.createElement('a');
a.setAttribute('href', '#');
a.innerHTML = '&times;';
input.setAttribute('type', 'text');
input.setAttribute('placeholder', this.options.anchorInputPlaceholder);
anchor.className = 'medium-editor-toolbar-form-anchor';
anchor.id = 'medium-editor-toolbar-form-anchor';
anchor.appendChild(input);
anchor.appendChild(a);
return anchor;
},
bindSelect: function () {

@@ -453,5 +521,3 @@ var self = this,

var selection = window.getSelection(),
range = selection.getRangeAt(0),
current = range.commonAncestorContainer,
parent = current.parentNode,
range, current, parent,
result,

@@ -471,2 +537,6 @@ getMediumElement = function (e) {

try {
range = selection.getRangeAt(0);
current = range.commonAncestorContainer;
parent = current.parentNode;
if (current.getAttribute('data-medium-element')) {

@@ -525,3 +595,4 @@ result = current;

checkActiveButtons: function () {
var parentNode = this.selection.anchorNode;
var elements = Array.prototype.slice.call(this.elements),
parentNode = this.selection.anchorNode;
if (!parentNode.tagName) {

@@ -532,2 +603,8 @@ parentNode = this.selection.anchorNode.parentNode;

this.activateButton(parentNode.tagName.toLowerCase());
this.callExtensions('checkState', parentNode);
// we can abort the search upwards if we leave the contentEditable element
if (elements.indexOf(parentNode) !== -1) {
break;
}
parentNode = parentNode.parentNode;

@@ -559,3 +636,5 @@ }

}
self.execAction(this.getAttribute('data-action'), e);
if (this.hasAttribute('data-action')) {
self.execAction(this.getAttribute('data-action'), e);
}
};

@@ -570,4 +649,6 @@ for (i = 0; i < buttons.length; i += 1) {

setFirstAndLastItems: function (buttons) {
buttons[0].className += ' medium-editor-button-first';
buttons[buttons.length - 1].className += ' medium-editor-button-last';
if (buttons.length > 0) {
buttons[0].className += ' medium-editor-button-first';
buttons[buttons.length - 1].className += ' medium-editor-button-last';
}
return this;

@@ -659,3 +740,5 @@ },

this.keepToolbarAlive = false;
this.toolbar.classList.remove('medium-editor-toolbar-active');
if (this.toolbar !== undefined) {
this.toolbar.classList.remove('medium-editor-toolbar-active');
}
},

@@ -671,3 +754,3 @@

timer = setTimeout(function () {
if (!self.toolbar.classList.contains('medium-editor-toolbar-active')) {
if (self.toolbar && !self.toolbar.classList.contains('medium-editor-toolbar-active')) {
self.toolbar.classList.add('medium-editor-toolbar-active');

@@ -741,3 +824,3 @@ }

timer = setTimeout(function () {
if (!self.anchorPreview.classList.contains('medium-editor-anchor-preview-active')) {
if (self.anchorPreview && !self.anchorPreview.classList.contains('medium-editor-anchor-preview-active')) {
self.anchorPreview.classList.add('medium-editor-anchor-preview-active');

@@ -835,3 +918,5 @@ }

setTimeout(function () {
self.showAnchorForm(self.activeAnchor.href);
if (self.activeAnchor) {
self.showAnchorForm(self.activeAnchor.href);
}
self.keepToolbarAlive = false;

@@ -857,3 +942,3 @@ }, 100 + self.options.delay);

// Detect empty href attributes
// The browser will make href="" or href="#top"
// The browser will make href="" or href="#top"
// into absolute urls when accessed as e.targed.href, so check the html

@@ -884,9 +969,20 @@ if (!/href=["']\S+["']/.test(e.target.outerHTML) || /href=["']#\S+["']/.test(e.target.outerHTML)) {

bindAnchorPreview: function (index) {
var self = this;
this.elements[index].addEventListener('mouseover', function (e) {
var i, self = this;
this.editorAnchorObserverWrapper = function (e) {
self.editorAnchorObserver(e);
});
};
for (i = 0; i < this.elements.length; i += 1) {
this.elements[i].addEventListener('mouseover', this.editorAnchorObserverWrapper);
}
return this;
},
checkLinkFormat: function (value) {
var re = /^https?:\/\//;
if (value.match(re)) {
return value;
}
return "http://" + value;
},
setTargetBlank: function () {

@@ -907,2 +1003,5 @@ var el = getSelectionStart(),

restoreSelection(this.savedSelection);
if (this.options.checkLinkFormat) {
input.value = this.checkLinkFormat(input.value);
}
document.execCommand('createLink', false, input.value);

@@ -958,2 +1057,3 @@ if (this.options.targetBlank) {

for (i = 0; i < this.elements.length; i += 1) {
this.elements[i].removeEventListener('mouseover', this.editorAnchorObserverWrapper);
this.elements[i].removeEventListener('keyup', this.checkSelectionWrapper);

@@ -968,2 +1068,8 @@ this.elements[i].removeEventListener('blur', this.checkSelectionWrapper);

htmlEntities: function (str) {
// converts special characters (like <) into their escaped/encoded values (like &lt;).
// This allows you to show to display the string without the browser reading it as HTML.
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
},
bindPaste: function () {

@@ -977,3 +1083,3 @@ var i, self = this;

this.classList.remove('medium-editor-placeholder');
if (!self.options.forcePlainText) {
if (!self.options.forcePlainText && !self.options.cleanPastedHTML) {
return this;

@@ -984,2 +1090,6 @@ }

e.preventDefault();
if (self.options.cleanPastedHTML && e.clipboardData.getData('text/html')) {
return self.cleanPaste(e.clipboardData.getData('text/html'));
}
if (!self.options.disableReturn) {

@@ -989,3 +1099,7 @@ paragraphs = e.clipboardData.getData('text/plain').split(/[\r\n]/g);

if (paragraphs[p] !== '') {
html += '<p>' + paragraphs[p] + '</p>';
if (navigator.userAgent.match(/firefox/i) && p === 0) {
html += self.htmlEntities(paragraphs[p]);
} else {
html += '<p>' + self.htmlEntities(paragraphs[p]) + '</p>';
}
}

@@ -1024,2 +1138,189 @@ }

return this;
},
cleanPaste: function (text) {
/*jslint regexp: true*/
/*
jslint does not allow character negation, because the negation
will not match any unicode characters. In the regexes in this
block, negation is used specifically to match the end of an html
tag, and in fact unicode characters *should* be allowed.
*/
var i, elList, workEl,
el = this.getSelectionElement(),
multiline = /<p|<br|<div/.test(text),
replacements = [
// replace two bogus tags that begin pastes from google docs
[new RegExp(/<[^>]*docs-internal-guid[^>]*>/gi), ""],
[new RegExp(/<\/b>(<br[^>]*>)?$/gi), ""],
// un-html spaces and newlines inserted by OS X
[new RegExp(/<span class="Apple-converted-space">\s+<\/span>/g), ' '],
[new RegExp(/<br class="Apple-interchange-newline">/g), '<br>'],
// replace google docs italics+bold with a span to be replaced once the html is inserted
[new RegExp(/<span[^>]*(font-style:italic;font-weight:bold|font-weight:bold;font-style:italic)[^>]*>/gi), '<span class="replace-with italic bold">'],
// replace google docs italics with a span to be replaced once the html is inserted
[new RegExp(/<span[^>]*font-style:italic[^>]*>/gi), '<span class="replace-with italic">'],
//[replace google docs bolds with a span to be replaced once the html is inserted
[new RegExp(/<span[^>]*font-weight:bold[^>]*>/gi), '<span class="replace-with bold">'],
// replace manually entered b/i/a tags with real ones
[new RegExp(/&lt;(\/?)(i|b|a)&gt;/gi), '<$1$2>'],
// replace manually a tags with real ones, converting smart-quotes from google docs
[new RegExp(/&lt;a\s+href=(&quot;|&rdquo;|&ldquo;|“|”)([^&]+)(&quot;|&rdquo;|&ldquo;|“|”)&gt;/gi), '<a href="$2">']
];
/*jslint regexp: false*/
for (i = 0; i < replacements.length; i += 1) {
text = text.replace(replacements[i][0], replacements[i][1]);
}
if (multiline) {
// double br's aren't converted to p tags, but we want paragraphs.
elList = text.split('<br><br>');
this.pasteHTML('<p>' + elList.join('</p><p>') + '</p>');
document.execCommand('insertText', false, "\n");
// block element cleanup
elList = el.querySelectorAll('p,div,br');
for (i = 0; i < elList.length; i += 1) {
workEl = elList[i];
switch (workEl.tagName.toLowerCase()) {
case 'p':
case 'div':
this.filterCommonBlocks(workEl);
break;
case 'br':
this.filterLineBreak(workEl);
break;
}
}
} else {
this.pasteHTML(text);
}
},
pasteHTML: function (html) {
var elList, workEl, i, fragmentBody, pasteBlock = document.createDocumentFragment();
pasteBlock.appendChild(document.createElement('body'));
fragmentBody = pasteBlock.querySelector('body');
fragmentBody.innerHTML = html;
this.cleanupSpans(fragmentBody);
elList = fragmentBody.querySelectorAll('*');
for (i = 0; i < elList.length; i += 1) {
workEl = elList[i];
// delete ugly attributes
workEl.removeAttribute('class');
workEl.removeAttribute('style');
workEl.removeAttribute('dir');
if (workEl.tagName.toLowerCase() === 'meta') {
workEl.parentNode.removeChild(workEl);
}
}
document.execCommand('insertHTML', false, fragmentBody.innerHTML.replace(/&nbsp;/g, ' '));
},
isCommonBlock: function (el) {
return (el && (el.tagName.toLowerCase() === 'p' || el.tagName.toLowerCase() === 'div'));
},
filterCommonBlocks: function (el) {
if (/^\s*$/.test(el.innerText)) {
el.parentNode.removeChild(el);
}
},
filterLineBreak: function (el) {
if (this.isCommonBlock(el.previousElementSibling)) {
// remove stray br's following common block elements
el.parentNode.removeChild(el);
} else if (this.isCommonBlock(el.parentNode) && (el.parentNode.firstChild === el || el.parentNode.lastChild === el)) {
// remove br's just inside open or close tags of a div/p
el.parentNode.removeChild(el);
} else if (el.parentNode.childElementCount === 1) {
// and br's that are the only child of a div/p
this.removeWithParent(el);
}
},
// remove an element, including its parent, if it is the only element within its parent
removeWithParent: function (el) {
if (el && el.parentNode) {
if (el.parentNode.parentNode && el.parentNode.childElementCount === 1) {
el.parentNode.parentNode.removeChild(el.parentNode);
} else {
el.parentNode.removeChild(el.parentNode);
}
}
},
cleanupSpans: function (container_el) {
var i,
el,
new_el,
spans = container_el.querySelectorAll('.replace-with');
for (i = 0; i < spans.length; i += 1) {
el = spans[i];
new_el = document.createElement(el.classList.contains('bold') ? 'b' : 'i');
if (el.classList.contains('bold') && el.classList.contains('italic')) {
// add an i tag as well if this has both italics and bold
new_el.innerHTML = '<i>' + el.innerHTML + '</i>';
} else {
new_el.innerHTML = el.innerHTML;
}
el.parentNode.replaceChild(new_el, el);
}
spans = container_el.querySelectorAll('span');
for (i = 0; i < spans.length; i += 1) {
el = spans[i];
// remove empty spans, replace others with their contents
if (/^\s*$/.test()) {
el.parentNode.removeChild(el);
} else {
el.parentNode.replaceChild(document.createTextNode(el.innerText), el);
}
}
}

@@ -1026,0 +1327,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc