While using it in my meteor application i am getting the below error
W20150603-16:45:52.065(5.5)? (STDERR) TypeError: Object n(attributeValue) {\n if (!attributeValue || !attributeValue.match(REG_EXP)) {\n return null;\n }\n return attributeValue.replace(REG_EXP, function(match) {\n return match.toLowerCase();\n });\n };\n })(),\n \n alt: (function() {\n var REGEXP = /[^ a-z0-9-]/gi;\n return function(attributeValue) {\n if (!attributeValue) {\n return \"\";\n }\n return attributeValue.replace(REG_EXP, \"\");\n };\n })(),\n \n numbers: (function() {\n var REG_EXP = /\D/g;\n return function(attributeValue) {\n attributeValue = (attributeValue || \"\").replace(REG_EXP, \"\");\n return attributeValue || null;\n };\n })()\n };\n \n // ------------ class converter (converts an html attribute to a class name) ------------ \\n var addClassMethods = {\n align_img: (function() {\n var mapping = {\n left: \"wysiwyg-float-left\",\n right: \"wysiwyg-float-right\"\n };\n return function(attributeValue) {\n return mapping[String(attributeValue).toLowerCase()];\n };\n })(),\n \n align_text: (function() {\n var mapping = {\n left: \"wysiwyg-text-align-left\",\n right: \"wysiwyg-text-align-right\",\n center: \"wysiwyg-text-align-center\",\n justify: \"wysiwyg-text-align-justify\"\n };\n return function(attributeValue) {\n return mapping[String(attributeValue).toLowerCase()];\n };\n })(),\n \n clear_br: (function() {\n var mapping = {\n left: \"wysiwyg-clear-left\",\n right: \"wysiwyg-clear-right\",\n both: \"wysiwyg-clear-both\",\n all: \"wysiwyg-clear-both\"\n };\n return function(attributeValue) {\n return mapping[String(attributeValue).toLowerCase()];\n };\n })(),\n \n size_font: (function() {\n var mapping = {\n \"1\": \"wysiwyg-font-size-xx-small\",\n \"2\": \"wysiwyg-font-size-small\",\n \"3\": \"wysiwyg-font-size-medium\",\n \"4\": \"wysiwyg-font-size-large\",\n \"5\": \"wysiwyg-font-size-x-large\",\n \"6\": \"wysiwyg-font-size-xx-large\",\n \"7\": \"wysiwyg-font-size-xx-large\",\n \"-\": \"wysiwyg-font-size-smaller\",\n \"+\": \"wysiwyg-font-size-larger\"\n };\n return function(attributeValue) {\n return mapping[String(attributeValue).charAt(0)];\n };\n })()\n };\n \n return parse;\n})();/*\n * Checks for empty text node childs and removes them\n \n * @param {Element} node The element in which to cleanup\n * @example\n * wysihtml5.dom.removeEmptyTextNodes(element);\n */\nwysihtml5.dom.removeEmptyTextNodes = function(node) {\n var childNode,\n childNodes = wysihtml5.lang.array(node.childNodes).get(),\n childNodesLength = childNodes.length,\n i = 0;\n for (; i<childNodesLength; i++) {\n childNode = childNodes[i];\n if (childNode.nodeType === wysihtml5.TEXTNODE && childNode.data === \"\") {\n childNode.parentNode.removeChild(childNode);\n }\n }\n};\n/*\n \ Renames an element (eg. a
to a
) and keeps its childs\n \n * @param {Element} element The list element which should be renamed\n * @param {Element} newNodeName The desired tag name\n \n * @example\n * \n * <ul id=\"list\">\n *
eminem
\n *
dr. dre
\n *
50 Cent
\n * \n \n * \n \n * \n * \n *
eminem
\n *
dr. dre
\n *
50 Cent
\n * \n /\nwysihtml5.dom.renameElement = function(element, newNodeName) {\n var newElement = element.ownerDocument.createElement(newNodeName),\n firstChild;\n while (firstChild = element.firstChild) {\n newElement.appendChild(firstChild);\n }\n wysihtml5.dom.copyAttributes([\"align\", \"className\"]).from(element).to(newElement);\n element.parentNode.replaceChild(newElement, element);\n return newElement;\n};/\n * Takes an element, removes it and replaces it with it's childs\n * \n * @param {Object} node The node which to replace with it's child nodes\n * @example\n * <div id=\"foo\">\n * hello\n *
\n * \n */\nwysihtml5.dom.replaceWithChildNodes = function(node) {\n if (!node.parentNode) {\n return;\n }\n \n if (!node.firstChild) {\n node.parentNode.removeChild(node);\n return;\n }\n \n var fragment = node.ownerDocument.createDocumentFragment();\n while (node.firstChild) {\n fragment.appendChild(node.firstChild);\n }\n node.parentNode.replaceChild(fragment, node);\n node = fragment = null;\n};\n/\n * Unwraps an unordered/ordered list\n \n * @param {Element} element The list element which should be unwrapped\n \n * @example\n * \n * <ul id=\"list\">\n *
eminem
\n *
dr. dre
\n *
50 Cent
\n * \n \n * \n \n * \n * eminem \n * dr. dre \n * 50 Cent \n /\n(function(dom) {\n function _isBlockElement(node) {\n return dom.getStyle(\"display\").from(node) === \"block\";\n }\n \n function _isLineBreak(node) {\n return node.nodeName === \"BR\";\n }\n \n function _appendLineBreak(element) {\n var lineBreak = element.ownerDocument.createElement(\"br\");\n element.appendChild(lineBreak);\n }\n \n function resolveList(list) {\n if (list.nodeName !== \"MENU\" && list.nodeName !== \"UL\" && list.nodeName !== \"OL\") {\n return;\n }\n \n var doc = list.ownerDocument,\n fragment = doc.createDocumentFragment(),\n previousSibling = list.previousElementSibling || list.previousSibling,\n firstChild,\n lastChild,\n isLastChild,\n shouldAppendLineBreak,\n listItem;\n \n if (previousSibling && !_isBlockElement(previousSibling)) {\n _appendLineBreak(fragment);\n }\n \n while (listItem = list.firstChild) {\n lastChild = listItem.lastChild;\n while (firstChild = listItem.firstChild) {\n isLastChild = firstChild === lastChild;\n // This needs to be done before appending it to the fragment, as it otherwise will loose style information\n shouldAppendLineBreak = isLastChild && !_isBlockElement(firstChild) && !_isLineBreak(firstChild);\n fragment.appendChild(firstChild);\n if (shouldAppendLineBreak) {\n _appendLineBreak(fragment);\n }\n }\n \n listItem.parentNode.removeChild(listItem);\n }\n list.parentNode.replaceChild(fragment, list);\n }\n \n dom.resolveList = resolveList;\n})(wysihtml5.dom);/__\n * Sandbox for executing javascript, parsing css styles and doing dom operations in a secure way\n \n * Browser Compatibility:\n * - Secure in MSIE 6+, but only when the user hasn't made changes to his security level \"restricted\"\n * - Partially secure in other browsers (Firefox, Opera, Safari, Chrome, ...)\n \n * Please note that this class can't benefit from the HTML5 sandbox attribute for the following reasons:\n * - sandboxing doesn't work correctly with inlined content (src=\"javascript:'...'\")\n * - sandboxing of physical documents causes that the dom isn't accessible anymore from the outside (iframe.contentWindow, ...)\n * - setting the \"allow-same-origin\" flag would fix that, but then still javascript and dom events refuse to fire\n * - therefore the \"allow-scripts\" flag is needed, which then would deactivate any security, as the js executed inside the iframe\n * can do anything as if the sandbox attribute wasn't set\n \n * @param {Function} [readyCallback] Method that gets invoked when the sandbox is ready\n * @param {Object} [config] Optional parameters\n \n * @example\n * new wysihtml5.dom.Sandbox(function(sandbox) {\n * sandbox.getWindow().document.body.innerHTML = '<img src=foo.gif onerror=\"alert(document.cookie)\">';\n * });\n /\n(function(wysihtml5) {\n var /\n * Default configuration\n */\n doc = document,\n /\n * Properties to unset/protect on the window object\n /\n windowProperties = [\n \"parent\", \"top\", \"opener\", \"frameElement\", \"frames\",\n \"localStorage\", \"globalStorage\", \"sessionStorage\", \"indexedDB\"\n ],\n /__\n * Properties on the window object which are set to an empty function\n /\n windowProperties2 = [\n \"open\", \"close\", \"openDialog\", \"showModalDialog\",\n \"alert\", \"confirm\", \"prompt\",\n \"openDatabase\", \"postMessage\",\n \"XMLHttpRequest\", \"XDomainRequest\"\n ],\n /\n * Properties to unset/protect on the document object\n /\n documentProperties = [\n \"referrer\",\n \"write\", \"open\", \"close\"\n ];\n \n wysihtml5.dom.Sandbox = Base.extend(\n /* @scope wysihtml5.dom.Sandbox.prototype / {\n\n constructor: function(readyCallback, config) {\n this.callback = readyCallback || wysihtml5.EMPTY_FUNCTION;\n this.config = wysihtml5.lang.object({}).merge(config).get();\n this.iframe = this._createIframe();\n },\n \n insertInto: function(element) {\n if (typeof(element) === \"string\") {\n element = doc.getElementById(element);\n }\n \n element.appendChild(this.iframe);\n },\n\n getIframe: function() {\n return this.iframe;\n },\n\n getWindow: function() {\n this._readyError();\n },\n\n getDocument: function() {\n this._readyError();\n },\n\n destroy: function() {\n var iframe = this.getIframe();\n iframe.parentNode.removeChild(iframe);\n },\n\n _readyError: function() {\n throw new Error(\"wysihtml5.Sandbox: Sandbox iframe isn't loaded yet\");\n },\n\n /__\n * Creates the sandbox iframe\n \n * Some important notes:\n * - We can't use HTML5 sandbox for now:\n * setting it causes that the iframe's dom can't be accessed from the outside\n * Therefore we need to set the \"allow-same-origin\" flag which enables accessing the iframe's dom\n * But then there's another problem, DOM events (focus, blur, change, keypress, ...) aren't fired.\n * In order to make this happen we need to set the \"allow-scripts\" flag.\n * A combination of allow-scripts and allow-same-origin is almost the same as setting no sandbox attribute at all.\n * - Chrome & Safari, doesn't seem to support sandboxing correctly when the iframe's html is inlined (no physical document)\n * - IE needs to have the security=\"restricted\" attribute set before the iframe is \n * inserted into the dom tree\n * - Believe it or not but in IE \"security\" in document.createElement(\"iframe\") is false, even\n * though it supports it\n * - When an iframe has security=\"restricted\", in IE eval() & execScript() don't work anymore\n * - IE doesn't fire the onload event when the content is inlined in the src attribute, therefore we rely\n * on the onreadystatechange event\n */\n _createIframe: function() {\n var that = this,\n iframe = doc.createElement(\"iframe\");\n iframe.className = \"wysihtml5-sandbox\";\n wysihtml5.dom.setAttributes({\n \"security\": \"restricted\",\n \"allowtransparency\": \"true\",\n \"frameborder\": 0,\n \"width\": 0,\n \"height\": 0,\n \"marginwidth\": 0,\n \"marginheight\": 0\n }).on(iframe);\n\n // Setting the src like this prevents ssl warnings in IE6\n if (wysihtml5.browser.throwsMixedContentWarningWhenIframeSrcIsEmpty()) {\n iframe.src = \"javascript:''\";\n }\n\n iframe.onload = function() {\n iframe.onreadystatechange = iframe.onload = null;\n that._onLoadIframe(iframe);\n };\n\n iframe.onreadystatechange = function() {\n if (/loaded|complete/.test(iframe.readyState)) {\n iframe.onreadystatechange = iframe.onload = null;\n that._onLoadIframe(iframe);\n }\n };\n\n return iframe;\n },\n\n /\n * Callback for when the iframe has finished loading\n /\n _onLoadIframe: function(iframe) {\n // don't resume when the iframe got unloaded (eg. by removing it from the dom)\n if (!wysihtml5.dom.contains(doc.documentElement, iframe)) {\n return;\n }\n\n var that = this,\n iframeWindow = iframe.contentWindow,\n iframeDocument = iframe.contentWindow.document,\n charset = doc.characterSet || doc.charset || \"utf-8\",\n sandboxHtml = this._getHtml({\n charset: charset,\n stylesheets: this.config.stylesheets\n });\n\n // Create the basic dom tree including proper DOCTYPE and charset\n iframeDocument.open(\"text/html\", \"replace\");\n iframeDocument.write(sandboxHtml);\n iframeDocument.close();\n\n this.getWindow = function() { return iframe.contentWindow; };\n this.getDocument = function() { return iframe.contentWindow.document; };\n\n // Catch js errors and pass them to the parent's onerror event\n // addEventListener(\"error\") doesn't work properly in some browsers\n // TODO: apparently this doesn't work in IE9!\n iframeWindow.onerror = function(errorMessage, fileName, lineNumber) {\n throw new Error(\"wysihtml5.Sandbox: \" + errorMessage, fileName, lineNumber);\n };\n\n if (!wysihtml5.browser.supportsSandboxedIframes()) {\n // Unset a bunch of sensitive variables\n // Please note: This isn't hack safe! \n // It more or less just takes care of basic attacks and prevents accidental theft of sensitive information\n // IE is secure though, which is the most important thing, since IE is the only browser, who\n // takes over scripts & styles into contentEditable elements when copied from external websites\n // or applications (Microsoft Word, ...)\n var i, length;\n for (i=0, length=windowProperties.length; i<length; i++) {\n this._unset(iframeWindow, windowProperties[i]);\n }\n for (i=0, length=windowProperties2.length; i<length; i++) {\n this._unset(iframeWindow, windowProperties2[i], wysihtml5.EMPTY_FUNCTION);\n }\n for (i=0, length=documentProperties.length; i<length; i++) {\n this._unset(iframeDocument, documentProperties[i]);\n }\n // This doesn't work in Safari 5 \n // See http://stackoverflow.com/questions/992461/is-it-possible-to-override-document-cookie-in-webkit\n this._unset(iframeDocument, \"cookie\", \"\", true);\n }\n\n this.loaded = true;\n\n // Trigger the callback\n setTimeout(function() { that.callback(that); }, 0);\n },\n\n _getHtml: function(templateVars) {\n var stylesheets = templateVars.stylesheets,\n html = \"\",\n i = 0,\n length;\n stylesheets = typeof(stylesheets) === \"string\" ? [stylesheets] : stylesheets;\n if (stylesheets) {\n length = stylesheets.length;\n for (; i<length; i++) {\n html += '<link rel=\"stylesheet\" href=\"' + stylesheets[i] + '\">';\n }\n }\n templateVars.stylesheets = html;\n\n return wysihtml5.lang.string(\n '<!DOCTYPE html>'\n + '<meta charset=\"#{charset}\">#{stylesheets}'\n + ''\n ).interpolate(templateVars);\n },\n\n /__\n * Method to unset/override existing variables\n * @example\n * // Make cookie unreadable and unwritable\n * this._unset(document, \"cookie\", \"\", true);\n /\n _unset: function(object, property, value, setter) {\n try { object[property] = value; } catch(e) {}\n\n try { object.defineGetter(property, function() { return value; }); } catch(e) {}\n if (setter) {\n try { object.defineSetter(property, function() {}); } catch(e) {}\n }\n\n if (!wysihtml5.browser.crashesWhenDefineProperty(property)) {\n try {\n var config = {\n get: function() { return value; }\n };\n if (setter) {\n config.set = function() {};\n }\n Object.defineProperty(object, property, config);\n } catch(e) {}\n }\n }\n });\n})(wysihtml5);\n(function() {\n var mapping = {\n \"className\": \"class\"\n };\n wysihtml5.dom.setAttributes = function(attributes) {\n return {\n on: function(element) {\n for (var i in attributes) {\n element.setAttribute(mapping[i] || i, attributes[i]);\n }\n }\n }\n };\n})();wysihtml5.dom.setStyles = function(styles) {\n return {\n on: function(element) {\n var style = element.style;\n if (typeof(styles) === \"string\") {\n style.cssText += \";\" + styles;\n return;\n }\n for (var i in styles) {\n if (i === \"float\") {\n style.cssFloat = styles[i];\n style.styleFloat = styles[i];\n } else {\n style[i] = styles[i];\n }\n }\n }\n };\n};/\n * Simulate HTML5 placeholder attribute\n \n * Needed since\n * - div[contentEditable] elements don't support it\n * - older browsers (such as IE8 and Firefox 3.6) don't support it at all\n \n * @param {Object} parent Instance of main wysihtml5.Editor class\n * @param {Element} view Instance of wysihtml5.views. class\n * @param {String} placeholderText\n \n * @example\n * wysihtml.dom.simulatePlaceholder(this, composer, \"Foobar\");\n /\n(function(dom) {\n dom.simulatePlaceholder = function(editor, view, placeholderText) {\n var CLASS_NAME = \"placeholder\",\n unset = function() {\n if (view.hasPlaceholderSet()) {\n view.clear();\n }\n dom.removeClass(view.element, CLASS_NAME);\n },\n set = function() {\n if (view.isEmpty()) {\n view.setValue(placeholderText);\n dom.addClass(view.element, CLASS_NAME);\n }\n };\n\n editor\n .observe(\"set_placeholder\", set)\n .observe(\"unset_placeholder\", unset)\n .observe(\"focus:composer\", unset)\n .observe(\"paste:composer\", unset)\n .observe(\"blur:composer\", set);\n\n set();\n };\n})(wysihtml5.dom);\n(function(dom) {\n var documentElement = document.documentElement;\n if (\"textContent\" in documentElement) {\n dom.setTextContent = function(element, text) {\n element.textContent = text;\n };\n\n dom.getTextContent = function(element) {\n return element.textContent;\n };\n } else if (\"innerText\" in documentElement) {\n dom.setTextContent = function(element, text) {\n element.innerText = text;\n };\n\n dom.getTextContent = function(element) {\n return element.innerText;\n };\n } else {\n dom.setTextContent = function(element, text) {\n element.nodeValue = text;\n };\n\n dom.getTextContent = function(element) {\n return element.nodeValue;\n };\n }\n})(wysihtml5.dom);\n\n/__\n * Fix most common html formatting misbehaviors of browsers implementation when inserting\n * content via copy & paste contentEditable\n \n * @author Christopher Blum\n /\nwysihtml5.quirks.cleanPastedHTML = (function() {\n // TODO: We probably need more rules here\n var defaultRules = {\n // When pasting underlined links into a contentEditable, IE thinks, it has to insert to keep the styling\n \"a u\": wysihtml5.dom.replaceWithChildNodes\n };\n \n function cleanPastedHTML(elementOrHtml, rules, context) {\n rules = rules || defaultRules;\n context = context || elementOrHtml.ownerDocument || document;\n \n var element,\n isString = typeof(elementOrHtml) === \"string\",\n method,\n matches,\n matchesLength,\n i,\n j = 0;\n if (isString) {\n element = wysihtml5.dom.getAsDom(elementOrHtml, context);\n } else {\n element = elementOrHtml;\n }\n \n for (i in rules) {\n matches = element.querySelectorAll(i);\n method = rules[i];\n matchesLength = matches.length;\n for (; j<matchesLength; j++) {\n method(matches[j]);\n }\n }\n \n matches = elementOrHtml = rules = null;\n \n return isString ? element.innerHTML : element;\n }\n \n return cleanPastedHTML;\n})();/__\n * IE and Opera leave an empty paragraph in the contentEditable element after clearing it\n \n * @param {Object} contentEditableElement The contentEditable element to observe for clearing events\n * @exaple\n * wysihtml5.quirks.ensureProperClearing(myContentEditableElement);\n /\n(function(wysihtml5) {\n var dom = wysihtml5.dom;\n \n wysihtml5.quirks.ensureProperClearing = (function() {\n var clearIfNecessary = function(event) {\n var element = this;\n setTimeout(function() {\n var innerHTML = element.innerHTML.toLowerCase();\n if (innerHTML == \"
\" ||\n innerHTML == \"
\") {\n element.innerHTML = \"\";\n }\n }, 0);\n };\n\n return function(composer) {\n dom.observe(composer.element, [\"cut\", \"keydown\"], clearIfNecessary);\n };\n })();\n\n\n\n /__\n * In Opera when the caret is in the first and only item of a list (
|
) and the list is the first child of the contentEditable element, it's impossible to delete the list by hitting backspace\n \n * @param {Object} contentEditableElement The contentEditable element to observe for clearing events\n * @exaple\n * wysihtml5.quirks.ensureProperClearing(myContentEditableElement);\n /\n wysihtml5.quirks.ensureProperClearingOfLists = (function() {\n var ELEMENTS_THAT_CONTAIN_LI = [\"OL\", \"UL\", \"MENU\"];\n\n var clearIfNecessary = function(element, contentEditableElement) {\n if (!contentEditableElement.firstChild || !wysihtml5.lang.array(ELEMENTS_THAT_CONTAIN_LI).contains(contentEditableElement.firstChild.nodeName)) {\n return;\n }\n\n var list = dom.getParentElement(element, { nodeName: ELEMENTS_THAT_CONTAIN_LI });\n if (!list) {\n return;\n }\n\n var listIsFirstChildOfContentEditable = list == contentEditableElement.firstChild;\n if (!listIsFirstChildOfContentEditable) {\n return;\n }\n\n var hasOnlyOneListItem = list.childNodes.length <= 1;\n if (!hasOnlyOneListItem) {\n return;\n }\n\n var onlyListItemIsEmpty = list.firstChild ? list.firstChild.innerHTML === \"\" : true;\n if (!onlyListItemIsEmpty) {\n return;\n }\n\n list.parentNode.removeChild(list);\n };\n\n return function(composer) {\n dom.observe(composer.element, \"keydown\", function(event) {\n if (event.keyCode !== wysihtml5.BACKSPACE_KEY) {\n return;\n }\n\n var element = composer.selection.getSelectedNode();\n clearIfNecessary(element, composer.element);\n });\n };\n })();\n\n})(wysihtml5);\n// See https://bugzilla.mozilla.org/show_bug.cgi?id=664398\n//\n// In Firefox this:\n// var d = document.createElement(\"div\");\n// d.innerHTML ='<a href=\"~\">';\n// d.innerHTML;\n// will result in:\n// <a href=\"%7E\">\n// which is wrong\n(function(wysihtml5) {\n var TILDE_ESCAPED = \"%7E\";\n wysihtml5.quirks.getCorrectInnerHTML = function(element) {\n var innerHTML = element.innerHTML;\n if (innerHTML.indexOf(TILDEESCAPED) === -1) {\n return innerHTML;\n }\n \n var elementsWithTilde = element.querySelectorAll(\"[href='~'], [src_='~']\"),\n url,\n urlToSearch,\n length,\n i;\n for (i=0, length=elementsWithTilde.length; i<length; i++) {\n url = elementsWithTilde[i].href || elementsWithTilde[i].src;\n urlToSearch = wysihtml5.lang.string(url).replace(\"~\").by(TILDE_ESCAPED);\n innerHTML = wysihtml5.lang.string(innerHTML).replace(urlToSearch).by(url);\n }\n return innerHTML;\n };\n})(wysihtml5);/__\n * Some browsers don't insert line breaks when hitting return in a contentEditable element\n * - Opera & IE insert new
on return\n * - Chrome & Safari insert new
on return\n * - Firefox inserts on return (yippie!)\n \n * @param {Element} element\n \n * @example\n * wysihtml5.quirks.insertLineBreakOnReturn(element);\n /\n(function(wysihtml5) {\n var dom = wysihtml5.dom,\n USE_NATIVE_LINE_BREAK_WHEN_CARET_INSIDE_TAGS = [\"LI\", \"P\", \"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\"],\n LIST_TAGS = [\"UL\", \"OL\", \"MENU\"];\n \n wysihtml5.quirks.insertLineBreakOnReturn = function(composer) {\n function unwrap(selectedNode) {\n var parentElement = dom.getParentElement(selectedNode, { nodeName: [\"P\", \"DIV\"] }, 2);\n if (!parentElement) {\n return;\n }\n\n var invisibleSpace = document.createTextNode(wysihtml5.INVISIBLE_SPACE);\n dom.insert(invisibleSpace).before(parentElement);\n dom.replaceWithChildNodes(parentElement);\n composer.selection.selectNode(invisibleSpace);\n }\n\n function keyDown(event) {\n var keyCode = event.keyCode;\n if (event.shiftKey || (keyCode !== wysihtml5.ENTER_KEY && keyCode !== wysihtml5.BACKSPACE_KEY)) {\n return;\n }\n\n var element = event.target,\n selectedNode = composer.selection.getSelectedNode(),\n blockElement = dom.getParentElement(selectedNode, { nodeName: USE_NATIVE_LINE_BREAK_WHEN_CARET_INSIDE_TAGS }, 4);\n if (blockElement) {\n // Some browsers create
elements after leaving a list\n // check after keydown of backspace and return whether a
got inserted and unwrap it\n if (blockElement.nodeName === \"LI\" && (keyCode === wysihtml5.ENTER_KEY || keyCode === wysihtml5.BACKSPACE_KEY)) {\n setTimeout(function() {\n var selectedNode = composer.selection.getSelectedNode(),\n list,\n div;\n if (!selectedNode) {\n return;\n }\n\n list = dom.getParentElement(selectedNode, {\n nodeName: LIST_TAGS\n }, 2);\n\n if (list) {\n return;\n }\n\n unwrap(selectedNode);\n }, 0);\n } else if (blockElement.nodeName.match(/H[1-6]/) && keyCode === wysihtml5.ENTER_KEY) {\n setTimeout(function() {\n unwrap(composer.selection.getSelectedNode());\n }, 0);\n } \n return;\n }\n\n if (keyCode === wysihtml5.ENTER_KEY && !wysihtml5.browser.insertsLineBreaksOnReturn()) {\n composer.commands.exec(\"insertLineBreak\");\n event.preventDefault();\n }\n }\n \n // keypress doesn't fire when you hit backspace\n dom.observe(composer.element.ownerDocument, \"keydown\", keyDown);\n };\n})(wysihtml5);/\n * Force rerendering of a given element\n * Needed to fix display misbehaviors of IE\n \n * @param {Element} element The element object which needs to be rerendered\n * @example\n * wysihtml5.quirks.redraw(document.body);\n /\n(function(wysihtml5) {\n var CLASS_NAME = \"wysihtml5-quirks-redraw\";\n \n wysihtml5.quirks.redraw = function(element) {\n wysihtml5.dom.addClass(element, CLASS_NAME);\n wysihtml5.dom.removeClass(element, CLASS_NAME);\n \n // Following hack is needed for firefox to make sure that image resize handles are properly removed\n try {\n var doc = element.ownerDocument;\n doc.execCommand(\"italic\", false, null);\n doc.execCommand(\"italic\", false, null);\n } catch(e) {}\n };\n})(wysihtml5);/\n * Selection API\n \n * @example\n * var selection = new wysihtml5.Selection(editor);\n /\n(function(wysihtml5) {\n var dom = wysihtml5.dom;\n \n function getCumulativeOffsetTop(element) {\n var top = 0;\n if (element.parentNode) {\n do {\n top += element.offsetTop || 0;\n element = element.offsetParent;\n } while (element);\n }\n return top;\n }\n \n wysihtml5.Selection = Base.extend(\n /* @scope wysihtml5.Selection.prototype _/ {\n constructor: function(editor) {\n // Make sure that our external range library is initialized\n window.rangy.init();\n \n this.editor = editor;\n this.composer = editor.composer;\n this.doc = this.composer.doc;\n },\n \n /\n * Get the current selection as a bookmark to be able to later restore it\n \n * @return {Object} An object that represents the current selection\n /\n getBookmark: function() {\n var range = this.getRange();\n return range && range.cloneRange();\n },\n\n /\n * Restore a selection retrieved via wysihtml5.Selection.prototype.getBookmark\n \n * @param {Object} bookmark An object that represents the current selection\n /\n setBookmark: function(bookmark) {\n if (!bookmark) {\n return;\n }\n\n this.setSelection(bookmark);\n },\n\n /\n * Set the caret in front of the given node\n \n * @param {Object} node The element or text node where to position the caret in front of\n * @example\n * selection.setBefore(myElement);\n /\n setBefore: function(node) {\n var range = rangy.createRange(this.doc);\n range.setStartBefore(node);\n range.setEndBefore(node);\n return this.setSelection(range);\n },\n\n /\n * Set the caret after the given node\n \n * @param {Object} node The element or text node where to position the caret in front of\n * @example\n * selection.setBefore(myElement);\n /\n setAfter: function(node) {\n var range = rangy.createRange(this.doc);\n range.setStartAfter(node);\n range.setEndAfter(node);\n return this.setSelection(range);\n },\n\n /__\n * Ability to select/mark nodes\n \n * @param {Element} node The node/element to select\n * @example\n * selection.selectNode(document.getElementById(\"my-image\"));\n /\n selectNode: function(node) {\n var range = rangy.createRange(this.doc),\n isElement = node.nodeType === wysihtml5.ELEMENT_NODE,\n canHaveHTML = \"canHaveHTML\" in node ? node.canHaveHTML : (node.nodeName !== \"IMG\"),\n content = isElement ? node.innerHTML : node.data,\n isEmpty = (content === \"\" || content === wysihtml5.INVISIBLE_SPACE),\n displayStyle = dom.getStyle(\"display\").from(node),\n isBlockElement = (displayStyle === \"block\" || displayStyle === \"list-item\");\n\n if (isEmpty && isElement && canHaveHTML) {\n // Make sure that caret is visible in node by inserting a zero width no breaking space\n try { node.innerHTML = wysihtml5.INVISIBLE_SPACE; } catch(e) {}\n }\n\n if (canHaveHTML) {\n range.selectNodeContents(node);\n } else {\n range.selectNode(node);\n }\n\n if (canHaveHTML && isEmpty && isElement) {\n range.collapse(isBlockElement);\n } else if (canHaveHTML && isEmpty) {\n range.setStartAfter(node);\n range.setEndAfter(node);\n }\n\n this.setSelection(range);\n },\n\n /\n * Get the node which contains the selection\n \n * @param {Boolean} [controlRange](only IE) Whether it should return the selected ControlRange element when the selection type is a \"ControlRange\"\n * @return {Object} The node that contains the caret\n * @example\n * var nodeThatContainsCaret = selection.getSelectedNode();\n /\n getSelectedNode: function(controlRange) {\n var selection,\n range;\n\n if (controlRange && this.doc.selection && this.doc.selection.type === \"Control\") {\n range = this.doc.selection.createRange();\n if (range && range.length) {\n return range.item(0);\n }\n }\n\n selection = this.getSelection(this.doc);\n if (selection.focusNode === selection.anchorNode) {\n return selection.focusNode;\n } else {\n range = this.getRange(this.doc);\n return range ? range.commonAncestorContainer : this.doc.body;\n }\n },\n\n executeAndRestore: function(method, restoreScrollPosition) {\n var body = this.doc.body,\n oldScrollTop = restoreScrollPosition && body.scrollTop,\n oldScrollLeft = restoreScrollPosition && body.scrollLeft,\n className = \"_wysihtml5-temp-placeholder\",\n placeholderHTML = '<span class=\"' + className + '\">' + wysihtml5.INVISIBLE_SPACE + '',\n range = this.getRange(this.doc),\n newRange;\n \n // Nothing selected, execute and say goodbye\n if (!range) {\n method(body, body);\n return;\n }\n \n var node = range.createContextualFragment(placeholderHTML);\n range.insertNode(node);\n \n // Make sure that a potential error doesn't cause our placeholder element to be left as a placeholder\n try {\n method(range.startContainer, range.endContainer);\n } catch(e3) {\n setTimeout(function() { throw e3; }, 0);\n }\n \n caretPlaceholder = this.doc.querySelector(\".\" + className);\n if (caretPlaceholder) {\n newRange = rangy.createRange(this.doc);\n newRange.selectNode(caretPlaceholder);\n newRange.deleteContents();\n this.setSelection(newRange);\n } else {\n // fallback for when all hell breaks loose\n body.focus();\n }\n\n if (restoreScrollPosition) {\n body.scrollTop = oldScrollTop;\n body.scrollLeft = oldScrollLeft;\n }\n\n // Remove it again, just to make sure that the placeholder is definitely out of the dom tree\n try {\n caretPlaceholder.parentNode.removeChild(caretPlaceholder);\n } catch(e4) {}\n },\n\n /\n * Different approach of preserving the selection (doesn't modify the dom)\n * Takes all text nodes in the selection and saves the selection position in the first and last one\n */\n executeAndRestoreSimple: function(method) {\n var range = this.getRange(),\n body = this.doc.body,\n newRange,\n firstNode,\n lastNode,\n textNodes,\n rangeBackup;\n\n // Nothing selected, execute and say goodbye\n if (!range) {\n method(body, body);\n return;\n }\n\n textNodes = range.getNodes([3]);\n firstNode = textNodes[0] || range.startContainer;\n lastNode = textNodes[textNodes.length - 1] || range.endContainer;\n\n rangeBackup = {\n collapsed: range.collapsed,\n startContainer: firstNode,\n startOffset: firstNode === range.startContainer ? range.startOffset : 0,\n endContainer: lastNode,\n endOffset: lastNode === range.endContainer ? range.endOffset : lastNode.length\n };\n\n try {\n method(range.startContainer, range.endContainer);\n } catch(e) {\n setTimeout(function() { throw e; }, 0);\n }\n\n newRange = rangy.createRange(this.doc);\n try { newRange.setStart(rangeBackup.startContainer, rangeBackup.startOffset); } catch(e1) {}\n try { newRange.setEnd(rangeBackup.endContainer, rangeBackup.endOffset); } catch(e2) {}\n try { this.setSelection(newRange); } catch(e3) {}\n },\n\n /\n * Insert html at the caret position and move the cursor after the inserted html\n \n * @param {String} html HTML string to insert\n * @example\n * selection.insertHTML(\"
foobar
\");\n /\n insertHTML: function(html) {\n var range = rangy.createRange(this.doc),\n node = range.createContextualFragment(html),\n lastChild = node.lastChild;\n this.insertNode(node);\n if (lastChild) {\n this.setAfter(lastChild);\n }\n },\n\n /\n * Insert a node at the caret position and move the cursor behind it\n \n * @param {Object} node HTML string to insert\n * @example\n * selection.insertNode(document.createTextNode(\"foobar\"));\n /\n insertNode: function(node) {\n var range = this.getRange();\n if (range) {\n range.insertNode(node);\n }\n },\n\n /\n * Wraps current selection with the given node\n \n * @param {Object} node The node to surround the selected elements with\n /\n surround: function(node) {\n var range = this.getRange();\n if (!range) {\n return;\n }\n\n try {\n // This only works when the range boundaries are not overlapping other elements\n range.surroundContents(node);\n this.selectNode(node);\n } catch(e) {\n // fallback\n node.appendChild(range.extractContents());\n range.insertNode(node);\n }\n },\n\n /\n * Scroll the current caret position into the view\n * FIXME: This is a bit hacky, there might be a smarter way of doing this\n \n * @example\n * selection.scrollIntoView();\n /\n scrollIntoView: function() {\n var doc = this.doc,\n hasScrollBars = doc.documentElement.scrollHeight > doc.documentElement.offsetHeight,\n tempElement = doc._wysihtml5ScrollIntoViewElement = doc._wysihtml5ScrollIntoViewElement || (function() {\n var element = doc.createElement(\"span\");\n // The element needs content in order to be able to calculate it's position properly\n element.innerHTML = wysihtml5.INVISIBLE_SPACE;\n return element;\n })(),\n offsetTop;\n\n if (hasScrollBars) {\n this.insertNode(tempElement);\n offsetTop = _getCumulativeOffsetTop(tempElement);\n tempElement.parentNode.removeChild(tempElement);\n if (offsetTop > doc.body.scrollTop) {\n doc.body.scrollTop = offsetTop;\n }\n }\n },\n\n /\n * Select line where the caret is in\n /\n selectLine: function() {\n if (wysihtml5.browser.supportsSelectionModify()) {\n this._selectLine_W3C();\n } else if (this.doc.selection) {\n this._selectLine_MSIE();\n }\n },\n\n /__\n * See https://developer.mozilla.org/en/DOM/Selection/modify\n/\n _selectLine_W3C: function() {\n var win = this.doc.defaultView,\n selection = win.getSelection();\n selection.modify(\"extend\", \"left\", \"lineboundary\");\n selection.modify(\"extend\", \"right\", \"lineboundary\");\n },\n\n _selectLine_MSIE: function() {\n var range = this.doc.selection.createRange(),\n rangeTop = range.boundingTop,\n rangeHeight = range.boundingHeight,\n scrollWidth = this.doc.body.scrollWidth,\n rangeBottom,\n rangeEnd,\n measureNode,\n i,\n j;\n\n if (!range.moveToPoint) {\n return;\n }\n\n if (rangeTop === 0) {\n // Don't know why, but when the selection ends at the end of a line\n // range.boundingTop is 0\n measureNode = this.doc.createElement(\"span\");\n this.insertNode(measureNode);\n rangeTop = measureNode.offsetTop;\n measureNode.parentNode.removeChild(measureNode);\n }\n\n rangeTop += 1;\n\n for (i=-10; i<scrollWidth; i+=2) {\n try {\n range.moveToPoint(i, rangeTop);\n break;\n } catch(e1) {}\n }\n\n // Investigate the following in order to handle multi line selections\n // rangeBottom = rangeTop + (rangeHeight ? (rangeHeight - 1) : 0);\n rangeBottom = rangeTop;\n rangeEnd = this.doc.selection.createRange();\n for (j=scrollWidth; j>=0; j--) {\n try {\n rangeEnd.moveToPoint(j, rangeBottom);\n break;\n } catch(e2) {}\n }\n\n range.setEndPoint(\"EndToEnd\", rangeEnd);\n range.select();\n },\n\n getText: function() {\n var selection = this.getSelection();\n return selection ? selection.toString() : \"\";\n },\n\n getNodes: function(nodeType, filter) {\n var range = this.getRange();\n if (range) {\n return range.getNodes([nodeType], filter);\n } else {\n return [];\n }\n },\n \n getRange: function() {\n var selection = this.getSelection();\n return selection && selection.rangeCount && selection.getRangeAt(0);\n },\n\n getSelection: function() {\n return rangy.getSelection(this.doc.defaultView || this.doc.parentWindow);\n },\n\n setSelection: function(range) {\n var win = this.doc.defaultView || this.doc.parentWindow,\n selection = rangy.getSelection(win);\n return selection.setSingleRange(range);\n }\n });\n \n})(wysihtml5);\n/\n * Inspired by the rangy CSS Applier module written by Tim Down and licensed under the MIT license.\n * http://code.google.com/p/rangy/\n\n * changed in order to be able ...\n * - to use custom tags\n * - to detect and replace similar css classes via reg exp\n /\n(function(wysihtml5, rangy) {\n var defaultTagName = \"span\";\n \n var REG_EXP_WHITE_SPACE = /\s+/g;\n \n function hasClass(el, cssClass, regExp) {\n if (!el.className) {\n return false;\n }\n \n var matchingClassNames = el.className.match(regExp) || [];\n return matchingClassNames[matchingClassNames.length - 1] === cssClass;\n }\n\n function addClass(el, cssClass, regExp) {\n if (el.className) {\n removeClass(el, regExp);\n el.className += \" \" + cssClass;\n } else {\n el.className = cssClass;\n }\n }\n\n function removeClass(el, regExp) {\n if (el.className) {\n el.className = el.className.replace(regExp, \"\");\n }\n }\n \n function hasSameClasses(el1, el2) {\n return el1.className.replace(REG_EXP_WHITE_SPACE, \" \") == el2.className.replace(REG_EXP_WHITE_SPACE, \" \");\n }\n\n function replaceWithOwnChildren(el) {\n var parent = el.parentNode;\n while (el.firstChild) {\n parent.insertBefore(el.firstChild, el);\n }\n parent.removeChild(el);\n }\n\n function elementsHaveSameNonClassAttributes(el1, el2) {\n if (el1.attributes.length != el2.attributes.length) {\n return false;\n }\n for (var i = 0, len = el1.attributes.length, attr1, attr2, name; i < len; ++i) {\n attr1 = el1.attributes[i];\n name = attr1.name;\n if (name != \"class\") {\n attr2 = el2.attributes.getNamedItem(name);\n if (attr1.specified != attr2.specified) {\n return false;\n }\n if (attr1.specified && attr1.nodeValue !== attr2.nodeValue) {\n return false;\n }\n }\n }\n return true;\n }\n\n function isSplitPoint(node, offset) {\n if (rangy.dom.isCharacterDataNode(node)) {\n if (offset == 0) {\n return !!node.previousSibling;\n } else if (offset == node.length) {\n return !!node.nextSibling;\n } else {\n return true;\n }\n }\n\n return offset > 0 && offset < node.childNodes.length;\n }\n\n function splitNodeAt(node, descendantNode, descendantOffset) {\n var newNode;\n if (rangy.dom.isCharacterDataNode(descendantNode)) {\n if (descendantOffset == 0) {\n descendantOffset = rangy.dom.getNodeIndex(descendantNode);\n descendantNode = descendantNode.parentNode;\n } else if (descendantOffset == descendantNode.length) {\n descendantOffset = rangy.dom.getNodeIndex(descendantNode) + 1;\n descendantNode = descendantNode.parentNode;\n } else {\n newNode = rangy.dom.splitDataNode(descendantNode, descendantOffset);\n }\n }\n if (!newNode) {\n newNode = descendantNode.cloneNode(false);\n if (newNode.id) {\n newNode.removeAttribute(\"id\");\n }\n var child;\n while ((child = descendantNode.childNodes[descendantOffset])) {\n newNode.appendChild(child);\n }\n rangy.dom.insertAfter(newNode, descendantNode);\n }\n return (descendantNode == node) ? newNode : splitNodeAt(node, newNode.parentNode, rangy.dom.getNodeIndex(newNode));\n }\n \n function Merge(firstNode) {\n this.isElementMerge = (firstNode.nodeType == wysihtml5.ELEMENT_NODE);\n this.firstTextNode = this.isElementMerge ? firstNode.lastChild : firstNode;\n this.textNodes = [this.firstTextNode];\n }\n\n Merge.prototype = {\n doMerge: function() {\n var textBits = [], textNode, parent, text;\n for (var i = 0, len = this.textNodes.length; i < len; ++i) {\n textNode = this.textNodes[i];\n parent = textNode.parentNode;\n textBits[i] = textNode.data;\n if (i) {\n parent.removeChild(textNode);\n if (!parent.hasChildNodes()) {\n parent.parentNode.removeChild(parent);\n }\n }\n }\n this.firstTextNode.data = text = textBits.join(\"\");\n return text;\n },\n\n getLength: function() {\n var i = this.textNodes.length, len = 0;\n while (i--) {\n len += this.textNodes[i].length;\n }\n return len;\n },\n\n toString: function() {\n var textBits = [];\n for (var i = 0, len = this.textNodes.length; i < len; ++i) {\n textBits[i] = \"'\" + this.textNodes[i].data + \"'\";\n }\n return \"[Merge(\" + textBits.join(\",\") + \")]\";\n }\n };\n\n function HTMLApplier(tagNames, cssClass, similarClassRegExp, normalize) {\n this.tagNames = tagNames || [defaultTagName];\n this.cssClass = cssClass || \"\";\n this.similarClassRegExp = similarClassRegExp;\n this.normalize = normalize;\n this.applyToAnyTagName = false;\n }\n\n HTMLApplier.prototype = {\n getAncestorWithClass: function(node) {\n var cssClassMatch;\n while (node) {\n cssClassMatch = this.cssClass ? hasClass(node, this.cssClass, this.similarClassRegExp) : true;\n if (node.nodeType == wysihtml5.ELEMENT_NODE && rangy.dom.arrayContains(this.tagNames, node.tagName.toLowerCase()) && cssClassMatch) {\n return node;\n }\n node = node.parentNode;\n }\n return false;\n },\n\n // Normalizes nodes after applying a CSS class to a Range.\n postApply: function(textNodes, range) {\n var firstNode = textNodes[0], lastNode = textNodes[textNodes.length - 1];\n\n var merges = [], currentMerge;\n\n var rangeStartNode = firstNode, rangeEndNode = lastNode;\n var rangeStartOffset = 0, rangeEndOffset = lastNode.length;\n\n var textNode, precedingTextNode;\n\n for (var i = 0, len = textNodes.length; i < len; ++i) {\n textNode = textNodes[i];\n precedingTextNode = this.getAdjacentMergeableTextNode(textNode.parentNode, false);\n if (precedingTextNode) {\n if (!currentMerge) {\n currentMerge = new Merge(precedingTextNode);\n merges.push(currentMerge);\n }\n currentMerge.textNodes.push(textNode);\n if (textNode === firstNode) {\n rangeStartNode = currentMerge.firstTextNode;\n rangeStartOffset = rangeStartNode.length;\n }\n if (textNode === lastNode) {\n rangeEndNode = currentMerge.firstTextNode;\n rangeEndOffset = currentMerge.getLength();\n }\n } else {\n currentMerge = null;\n }\n }\n\n // Test whether the first node after the range needs merging\n var nextTextNode = this.getAdjacentMergeableTextNode(lastNode.parentNode, true);\n if (nextTextNode) {\n if (!currentMerge) {\n currentMerge = new Merge(lastNode);\n merges.push(currentMerge);\n }\n currentMerge.textNodes.push(nextTextNode);\n }\n\n // Do the merges\n if (merges.length) {\n for (i = 0, len = merges.length; i < len; ++i) {\n merges[i].doMerge();\n }\n // Set the range boundaries\n range.setStart(rangeStartNode, rangeStartOffset);\n range.setEnd(rangeEndNode, rangeEndOffset);\n }\n },\n \n getAdjacentMergeableTextNode: function(node, forward) {\n var isTextNode = (node.nodeType == wysihtml5.TEXT_NODE);\n var el = isTextNode ? node.parentNode : node;\n var adjacentNode;\n var propName = forward ? \"nextSibling\" : \"previousSibling\";\n if (isTextNode) {\n // Can merge if the node's previous/next sibling is a text node\n adjacentNode = node[propName];\n if (adjacentNode && adjacentNode.nodeType == wysihtml5.TEXT_NODE) {\n return adjacentNode;\n }\n } else {\n // Compare element with its sibling\n adjacentNode = el[propName];\n if (adjacentNode && this.areElementsMergeable(node, adjacentNode)) {\n return adjacentNode[forward ? \"firstChild\" : \"lastChild\"];\n }\n }\n return null;\n },\n \n areElementsMergeable: function(el1, el2) {\n return rangy.dom.arrayContains(this.tagNames, (el1.tagName || \"\").toLowerCase())\n && rangy.dom.arrayContains(this.tagNames, (el2.tagName || \"\").toLowerCase())\n && hasSameClasses(el1, el2)\n && elementsHaveSameNonClassAttributes(el1, el2);\n },\n\n createContainer: function(doc) {\n var el = doc.createElement(this.tagNames[0]);\n if (this.cssClass) {\n el.className = this.cssClass;\n }\n return el;\n },\n\n applyToTextNode: function(textNode) {\n var parent = textNode.parentNode;\n if (parent.childNodes.length == 1 && rangy.dom.arrayContains(this.tagNames, parent.tagName.toLowerCase())) {\n if (this.cssClass) {\n addClass(parent, this.cssClass, this.similarClassRegExp);\n }\n } else {\n var el = this.createContainer(rangy.dom.getDocument(textNode));\n textNode.parentNode.insertBefore(el, textNode);\n el.appendChild(textNode);\n }\n },\n\n isRemovable: function(el) {\n return rangy.dom.arrayContains(this.tagNames, el.tagName.toLowerCase()) && wysihtml5.lang.string(el.className).trim() == this.cssClass;\n },\n\n undoToTextNode: function(textNode, range, ancestorWithClass) {\n if (!range.containsNode(ancestorWithClass)) {\n // Split out the portion of the ancestor from which we can remove the CSS class\n var ancestorRange = range.cloneRange();\n ancestorRange.selectNode(ancestorWithClass);\n\n if (ancestorRange.isPointInRange(range.endContainer, range.endOffset) && isSplitPoint(range.endContainer, range.endOffset)) {\n splitNodeAt(ancestorWithClass, range.endContainer, range.endOffset);\n range.setEndAfter(ancestorWithClass);\n }\n if (ancestorRange.isPointInRange(range.startContainer, range.startOffset) && isSplitPoint(range.startContainer, range.startOffset)) {\n ancestorWithClass = splitNodeAt(ancestorWithClass, range.startContainer, range.startOffset);\n }\n }\n \n if (this.similarClassRegExp) {\n removeClass(ancestorWithClass, this.similarClassRegExp);\n }\n if (this.isRemovable(ancestorWithClass)) {\n replaceWithOwnChildren(ancestorWithClass);\n }\n },\n\n applyToRange: function(range) {\n var textNodes = range.getNodes([wysihtml5.TEXT_NODE]);\n if (!textNodes.length) {\n try {\n var node = this.createContainer(range.endContainer.ownerDocument);\n range.surroundContents(node);\n this.selectNode(range, node);\n return;\n } catch(e) {}\n }\n \n range.splitBoundaries();\n textNodes = range.getNodes([wysihtml5.TEXT_NODE]);\n \n if (textNodes.length) {\n var textNode;\n\n for (var i = 0, len = textNodes.length; i < len; ++i) {\n textNode = textNodes[i];\n if (!this.getAncestorWithClass(textNode)) {\n this.applyToTextNode(textNode);\n }\n }\n \n range.setStart(textNodes[0], 0);\n textNode = textNodes[textNodes.length - 1];\n range.setEnd(textNode, textNode.length);\n \n if (this.normalize) {\n this.postApply(textNodes, range);\n }\n }\n },\n\n undoToRange: function(range) {\n var textNodes = range.getNodes([wysihtml5.TEXT_NODE]), textNode, ancestorWithClass;\n if (textNodes.length) {\n range.splitBoundaries();\n textNodes = range.getNodes([wysihtml5.TEXT_NODE]);\n } else {\n var doc = range.endContainer.ownerDocument,\n node = doc.createTextNode(wysihtml5.INVISIBLE_SPACE);\n range.insertNode(node);\n range.selectNode(node);\n textNodes = [node];\n }\n \n for (var i = 0, len = textNodes.length; i < len; ++i) {\n textNode = textNodes[i];\n ancestorWithClass = this.getAncestorWithClass(textNode);\n if (ancestorWithClass) {\n this.undoToTextNode(textNode, range, ancestorWithClass);\n }\n }\n \n if (len == 1) {\n this.selectNode(range, textNodes[0]);\n } else {\n range.setStart(textNodes[0], 0);\n textNode = textNodes[textNodes.length - 1];\n range.setEnd(textNode, textNode.length);\n\n if (this.normalize) {\n this.postApply(textNodes, range);\n }\n }\n },\n \n selectNode: function(range, node) {\n var isElement = node.nodeType === wysihtml5.ELEMENT_NODE,\n canHaveHTML = \"canHaveHTML\" in node ? node.canHaveHTML : true,\n content = isElement ? node.innerHTML : node.data,\n isEmpty = (content === \"\" || content === wysihtml5.INVISIBLE_SPACE);\n\n if (isEmpty && isElement && canHaveHTML) {\n // Make sure that caret is visible in node by inserting a zero width no breaking space\n try { node.innerHTML = wysihtml5.INVISIBLE_SPACE; } catch(e) {}\n }\n range.selectNodeContents(node);\n if (isEmpty && isElement) {\n range.collapse(false);\n } else if (isEmpty) {\n range.setStartAfter(node);\n range.setEndAfter(node);\n }\n },\n \n getTextSelectedByRange: function(textNode, range) {\n var textRange = range.cloneRange();\n textRange.selectNodeContents(textNode);\n\n var intersectionRange = textRange.intersection(range);\n var text = intersectionRange ? intersectionRange.toString() : \"\";\n textRange.detach();\n\n return text;\n },\n\n isAppliedToRange: function(range) {\n var ancestors = [],\n ancestor,\n textNodes = range.getNodes([wysihtml5.TEXT_NODE]);\n if (!textNodes.length) {\n ancestor = this.getAncestorWithClass(range.startContainer);\n return ancestor ? [ancestor] : false;\n }\n \n for (var i = 0, len = textNodes.length, selectedText; i < len; ++i) {\n selectedText = this.getTextSelectedByRange(textNodes[i], range);\n ancestor = this.getAncestorWithClass(textNodes[i]);\n if (selectedText != \"\" && !ancestor) {\n return false;\n } else {\n ancestors.push(ancestor);\n }\n }\n return ancestors;\n },\n\n toggleRange: function(range) {\n if (this.isAppliedToRange(range)) {\n this.undoToRange(range);\n } else {\n this.applyToRange(range);\n }\n }\n };\n\n wysihtml5.selection.HTMLApplier = HTMLApplier;\n \n})(wysihtml5, rangy);/\n * Rich Text Query/Formatting Commands\n * \n * @example\n * var commands = new wysihtml5.Commands(editor);\n /\nwysihtml5.Commands = Base.extend(\n /* @scope wysihtml5.Commands.prototype / {\n constructor: function(editor) {\n this.editor = editor;\n this.composer = editor.composer;\n this.doc = this.composer.doc;\n },\n \n /__\n * Check whether the browser supports the given command\n \n * @param {String} command The command string which to check (eg. \"bold\", \"italic\", \"insertUnorderedList\")\n * @example\n * commands.supports(\"createLink\");\n /\n support: function(command) {\n return wysihtml5.browser.supportsCommand(this.doc, command);\n },\n \n /__\n * Check whether the browser supports the given command\n \n * @param {String} command The command string which to execute (eg. \"bold\", \"italic\", \"insertUnorderedList\")\n * @param {String} [value] The command value parameter, needed for some commands (\"createLink\", \"insertImage\", ...), optional for commands that don't require one (\"bold\", \"underline\", ...)\n * @example\n * commands.exec(\"insertImage\", \"http://a1.twimg.com/profile_images/113868655/schrei_twitter_reasonably_small.jpg\");\n/\n exec: function(command, value) {\n var obj = wysihtml5.commands[command],\n args = wysihtml5.lang.array(arguments).get(),\n method = obj && obj.exec,\n result = null;\n \n this.editor.fire(\"beforecommand:composer\");\n \n if (method) {\n args.unshift(this.composer);\n result = method.apply(obj, args);\n } else {\n try {\n // try/catch for buggy firefox\n result = this.doc.execCommand(command, false, value);\n } catch(e) {}\n }\n \n this.editor.fire(\"aftercommand:composer\");\n return result;\n },\n \n /__\n * Check whether the current command is active\n * If the caret is within a bold text, then calling this with command \"bold\" should return true\n \n * @param {String} command The command string which to check (eg. \"bold\", \"italic\", \"insertUnorderedList\")\n * @param {String} [commandValue] The command value parameter (eg. for \"insertImage\" the image src)\n * @return {Boolean} Whether the command is active\n * @example\n * var isCurrentSelectionBold = commands.state(\"bold\");\n /\n state: function(command, commandValue) {\n var obj = wysihtml5.commands[command],\n args = wysihtml5.lang.array(arguments).get(),\n method = obj && obj.state;\n if (method) {\n args.unshift(this.composer);\n return method.apply(obj, args);\n } else {\n try {\n // try/catch for buggy firefox\n return this.doc.queryCommandState(command);\n } catch(e) {\n return false;\n }\n }\n },\n \n /__\n * Get the current command's value\n \n * @param {String} command The command string which to check (eg. \"formatBlock\")\n * @return {String} The command value\n * @example\n * var currentBlockElement = commands.value(\"formatBlock\");\n */\n value: function(command) {\n var obj = wysihtml5.commands[command],\n method = obj && obj.value;\n if (method) {\n return method.call(obj, this.composer, command);\n } else {\n try {\n // try/catch for buggy firefox\n return this.doc.queryCommandValue(command);\n } catch(e) {\n return null;\n }\n }\n }\n});\n(function(wysihtml5) {\n var undef;\n \n wysihtml5.commands.bold = {\n exec: function(composer, command) {\n return wysihtml5.commands.formatInline.exec(composer, command, \"b\");\n },\n\n state: function(composer, command, color) {\n // element.ownerDocument.queryCommandState(\"bold\") results:\n // firefox: only \n // chrome: , ,
That looks pretty old. There's no github info on the Atmosphere page but it looks like it's https://github.com/nmacmunn/meteor-allow-env/. From looking at the package.js, it's written for Meteor <= 0.8.3. How did you even get it to find inject-initial? :) In any event, the problem seems to be that side, so I'd either try find an alternative package or see if the author is willing to update it.
While using it in my meteor application i am getting the below error
W20150603-16:45:52.065(5.5)? (STDERR) TypeError: Object n(attributeValue) {\n if (!attributeValue || !attributeValue.match(REG_EXP)) {\n return null;\n }\n return attributeValue.replace(REG_EXP, function(match) {\n return match.toLowerCase();\n });\n };\n })(),\n \n alt: (function() {\n var REGEXP = /[^ a-z0-9-]/gi;\n return function(attributeValue) {\n if (!attributeValue) {\n return \"\";\n }\n return attributeValue.replace(REG_EXP, \"\");\n };\n })(),\n \n numbers: (function() {\n var REG_EXP = /\D/g;\n return function(attributeValue) {\n attributeValue = (attributeValue || \"\").replace(REG_EXP, \"\");\n return attributeValue || null;\n };\n })()\n };\n \n // ------------ class converter (converts an html attribute to a class name) ------------ \\n var addClassMethods = {\n align_img: (function() {\n var mapping = {\n left: \"wysiwyg-float-left\",\n right: \"wysiwyg-float-right\"\n };\n return function(attributeValue) {\n return mapping[String(attributeValue).toLowerCase()];\n };\n })(),\n \n align_text: (function() {\n var mapping = {\n left: \"wysiwyg-text-align-left\",\n right: \"wysiwyg-text-align-right\",\n center: \"wysiwyg-text-align-center\",\n justify: \"wysiwyg-text-align-justify\"\n };\n return function(attributeValue) {\n return mapping[String(attributeValue).toLowerCase()];\n };\n })(),\n \n clear_br: (function() {\n var mapping = {\n left: \"wysiwyg-clear-left\",\n right: \"wysiwyg-clear-right\",\n both: \"wysiwyg-clear-both\",\n all: \"wysiwyg-clear-both\"\n };\n return function(attributeValue) {\n return mapping[String(attributeValue).toLowerCase()];\n };\n })(),\n \n size_font: (function() {\n var mapping = {\n \"1\": \"wysiwyg-font-size-xx-small\",\n \"2\": \"wysiwyg-font-size-small\",\n \"3\": \"wysiwyg-font-size-medium\",\n \"4\": \"wysiwyg-font-size-large\",\n \"5\": \"wysiwyg-font-size-x-large\",\n \"6\": \"wysiwyg-font-size-xx-large\",\n \"7\": \"wysiwyg-font-size-xx-large\",\n \"-\": \"wysiwyg-font-size-smaller\",\n \"+\": \"wysiwyg-font-size-larger\"\n };\n return function(attributeValue) {\n return mapping[String(attributeValue).charAt(0)];\n };\n })()\n };\n \n return parse;\n})();/*\n * Checks for empty text node childs and removes them\n \n * @param {Element} node The element in which to cleanup\n * @example\n * wysihtml5.dom.removeEmptyTextNodes(element);\n */\nwysihtml5.dom.removeEmptyTextNodes = function(node) {\n var childNode,\n childNodes = wysihtml5.lang.array(node.childNodes).get(),\n childNodesLength = childNodes.length,\n i = 0;\n for (; i<childNodesLength; i++) {\n childNode = childNodes[i];\n if (childNode.nodeType === wysihtml5.TEXTNODE && childNode.data === \"\") {\n childNode.parentNode.removeChild(childNode);\n }\n }\n};\n/*\n \ Renames an element (eg. a to a \n * \n */\nwysihtml5.dom.replaceWithChildNodes = function(node) {\n if (!node.parentNode) {\n return;\n }\n \n if (!node.firstChild) {\n node.parentNode.removeChild(node);\n return;\n }\n \n var fragment = node.ownerDocument.createDocumentFragment();\n while (node.firstChild) {\n fragment.appendChild(node.firstChild);\n }\n node.parentNode.replaceChild(fragment, node);\n node = fragment = null;\n};\n/\n * Unwraps an unordered/ordered list\n \n * @param {Element} element The list element which should be unwrapped\n \n * @example\n * \n * <ul id=\"list\">\n * eminem \n * dr. dre \n * 50 Cent \n * \n \n * \n \n * \n * eminem
\" ||\n innerHTML == \"
\") {\n element.innerHTML = \"\";\n }\n }, 0);\n };\n\n return function(composer) {\n dom.observe(composer.element, [\"cut\", \"keydown\"], clearIfNecessary);\n };\n })();\n\n\n\n /__\n * In Opera when the caret is in the first and only item of a list ( on return\n * - Firefox inserts
) and keeps its childs\n \n * @param {Element} element The list element which should be renamed\n * @param {Element} newNodeName The desired tag name\n \n * @example\n * \n * <ul id=\"list\">\n *eminem \n * dr. dre \n * 50 Cent \n * \n \n * \n \n * \n *
\n *- eminem
\n * - dr. dre
\n * - 50 Cent
\n *
\n /\nwysihtml5.dom.renameElement = function(element, newNodeName) {\n var newElement = element.ownerDocument.createElement(newNodeName),\n firstChild;\n while (firstChild = element.firstChild) {\n newElement.appendChild(firstChild);\n }\n wysihtml5.dom.copyAttributes([\"align\", \"className\"]).from(element).to(newElement);\n element.parentNode.replaceChild(newElement, element);\n return newElement;\n};/\n * Takes an element, removes it and replaces it with it's childs\n * \n * @param {Object} node The node which to replace with it's child nodes\n * @example\n * <div id=\"foo\">\n * hello\n *\n * dr. dre
\n * 50 Cent
\n /\n(function(dom) {\n function _isBlockElement(node) {\n return dom.getStyle(\"display\").from(node) === \"block\";\n }\n \n function _isLineBreak(node) {\n return node.nodeName === \"BR\";\n }\n \n function _appendLineBreak(element) {\n var lineBreak = element.ownerDocument.createElement(\"br\");\n element.appendChild(lineBreak);\n }\n \n function resolveList(list) {\n if (list.nodeName !== \"MENU\" && list.nodeName !== \"UL\" && list.nodeName !== \"OL\") {\n return;\n }\n \n var doc = list.ownerDocument,\n fragment = doc.createDocumentFragment(),\n previousSibling = list.previousElementSibling || list.previousSibling,\n firstChild,\n lastChild,\n isLastChild,\n shouldAppendLineBreak,\n listItem;\n \n if (previousSibling && !_isBlockElement(previousSibling)) {\n _appendLineBreak(fragment);\n }\n \n while (listItem = list.firstChild) {\n lastChild = listItem.lastChild;\n while (firstChild = listItem.firstChild) {\n isLastChild = firstChild === lastChild;\n // This needs to be done before appending it to the fragment, as it otherwise will loose style information\n shouldAppendLineBreak = isLastChild && !_isBlockElement(firstChild) && !_isLineBreak(firstChild);\n fragment.appendChild(firstChild);\n if (shouldAppendLineBreak) {\n _appendLineBreak(fragment);\n }\n }\n \n listItem.parentNode.removeChild(listItem);\n }\n list.parentNode.replaceChild(fragment, list);\n }\n \n dom.resolveList = resolveList;\n})(wysihtml5.dom);/__\n * Sandbox for executing javascript, parsing css styles and doing dom operations in a secure way\n \n * Browser Compatibility:\n * - Secure in MSIE 6+, but only when the user hasn't made changes to his security level \"restricted\"\n * - Partially secure in other browsers (Firefox, Opera, Safari, Chrome, ...)\n \n * Please note that this class can't benefit from the HTML5 sandbox attribute for the following reasons:\n * - sandboxing doesn't work correctly with inlined content (src=\"javascript:'...'\")\n * - sandboxing of physical documents causes that the dom isn't accessible anymore from the outside (iframe.contentWindow, ...)\n * - setting the \"allow-same-origin\" flag would fix that, but then still javascript and dom events refuse to fire\n * - therefore the \"allow-scripts\" flag is needed, which then would deactivate any security, as the js executed inside the iframe\n * can do anything as if the sandbox attribute wasn't set\n \n * @param {Function} [readyCallback] Method that gets invoked when the sandbox is ready\n * @param {Object} [config] Optional parameters\n \n * @example\n * new wysihtml5.dom.Sandbox(function(sandbox) {\n * sandbox.getWindow().document.body.innerHTML = '<img src=foo.gif onerror=\"alert(document.cookie)\">';\n * });\n /\n(function(wysihtml5) {\n var /\n * Default configuration\n */\n doc = document,\n /\n * Properties to unset/protect on the window object\n /\n windowProperties = [\n \"parent\", \"top\", \"opener\", \"frameElement\", \"frames\",\n \"localStorage\", \"globalStorage\", \"sessionStorage\", \"indexedDB\"\n ],\n /__\n * Properties on the window object which are set to an empty function\n /\n windowProperties2 = [\n \"open\", \"close\", \"openDialog\", \"showModalDialog\",\n \"alert\", \"confirm\", \"prompt\",\n \"openDatabase\", \"postMessage\",\n \"XMLHttpRequest\", \"XDomainRequest\"\n ],\n /\n * Properties to unset/protect on the document object\n /\n documentProperties = [\n \"referrer\",\n \"write\", \"open\", \"close\"\n ];\n \n wysihtml5.dom.Sandbox = Base.extend(\n /* @scope wysihtml5.dom.Sandbox.prototype / {\n\n constructor: function(readyCallback, config) {\n this.callback = readyCallback || wysihtml5.EMPTY_FUNCTION;\n this.config = wysihtml5.lang.object({}).merge(config).get();\n this.iframe = this._createIframe();\n },\n \n insertInto: function(element) {\n if (typeof(element) === \"string\") {\n element = doc.getElementById(element);\n }\n \n element.appendChild(this.iframe);\n },\n\n getIframe: function() {\n return this.iframe;\n },\n\n getWindow: function() {\n this._readyError();\n },\n\n getDocument: function() {\n this._readyError();\n },\n\n destroy: function() {\n var iframe = this.getIframe();\n iframe.parentNode.removeChild(iframe);\n },\n\n _readyError: function() {\n throw new Error(\"wysihtml5.Sandbox: Sandbox iframe isn't loaded yet\");\n },\n\n /__\n * Creates the sandbox iframe\n \n * Some important notes:\n * - We can't use HTML5 sandbox for now:\n * setting it causes that the iframe's dom can't be accessed from the outside\n * Therefore we need to set the \"allow-same-origin\" flag which enables accessing the iframe's dom\n * But then there's another problem, DOM events (focus, blur, change, keypress, ...) aren't fired.\n * In order to make this happen we need to set the \"allow-scripts\" flag.\n * A combination of allow-scripts and allow-same-origin is almost the same as setting no sandbox attribute at all.\n * - Chrome & Safari, doesn't seem to support sandboxing correctly when the iframe's html is inlined (no physical document)\n * - IE needs to have the security=\"restricted\" attribute set before the iframe is \n * inserted into the dom tree\n * - Believe it or not but in IE \"security\" in document.createElement(\"iframe\") is false, even\n * though it supports it\n * - When an iframe has security=\"restricted\", in IE eval() & execScript() don't work anymore\n * - IE doesn't fire the onload event when the content is inlined in the src attribute, therefore we rely\n * on the onreadystatechange event\n */\n _createIframe: function() {\n var that = this,\n iframe = doc.createElement(\"iframe\");\n iframe.className = \"wysihtml5-sandbox\";\n wysihtml5.dom.setAttributes({\n \"security\": \"restricted\",\n \"allowtransparency\": \"true\",\n \"frameborder\": 0,\n \"width\": 0,\n \"height\": 0,\n \"marginwidth\": 0,\n \"marginheight\": 0\n }).on(iframe);\n\n // Setting the src like this prevents ssl warnings in IE6\n if (wysihtml5.browser.throwsMixedContentWarningWhenIframeSrcIsEmpty()) {\n iframe.src = \"javascript:''\";\n }\n\n iframe.onload = function() {\n iframe.onreadystatechange = iframe.onload = null;\n that._onLoadIframe(iframe);\n };\n\n iframe.onreadystatechange = function() {\n if (/loaded|complete/.test(iframe.readyState)) {\n iframe.onreadystatechange = iframe.onload = null;\n that._onLoadIframe(iframe);\n }\n };\n\n return iframe;\n },\n\n /\n * Callback for when the iframe has finished loading\n /\n _onLoadIframe: function(iframe) {\n // don't resume when the iframe got unloaded (eg. by removing it from the dom)\n if (!wysihtml5.dom.contains(doc.documentElement, iframe)) {\n return;\n }\n\n var that = this,\n iframeWindow = iframe.contentWindow,\n iframeDocument = iframe.contentWindow.document,\n charset = doc.characterSet || doc.charset || \"utf-8\",\n sandboxHtml = this._getHtml({\n charset: charset,\n stylesheets: this.config.stylesheets\n });\n\n // Create the basic dom tree including proper DOCTYPE and charset\n iframeDocument.open(\"text/html\", \"replace\");\n iframeDocument.write(sandboxHtml);\n iframeDocument.close();\n\n this.getWindow = function() { return iframe.contentWindow; };\n this.getDocument = function() { return iframe.contentWindow.document; };\n\n // Catch js errors and pass them to the parent's onerror event\n // addEventListener(\"error\") doesn't work properly in some browsers\n // TODO: apparently this doesn't work in IE9!\n iframeWindow.onerror = function(errorMessage, fileName, lineNumber) {\n throw new Error(\"wysihtml5.Sandbox: \" + errorMessage, fileName, lineNumber);\n };\n\n if (!wysihtml5.browser.supportsSandboxedIframes()) {\n // Unset a bunch of sensitive variables\n // Please note: This isn't hack safe! \n // It more or less just takes care of basic attacks and prevents accidental theft of sensitive information\n // IE is secure though, which is the most important thing, since IE is the only browser, who\n // takes over scripts & styles into contentEditable elements when copied from external websites\n // or applications (Microsoft Word, ...)\n var i, length;\n for (i=0, length=windowProperties.length; i<length; i++) {\n this._unset(iframeWindow, windowProperties[i]);\n }\n for (i=0, length=windowProperties2.length; i<length; i++) {\n this._unset(iframeWindow, windowProperties2[i], wysihtml5.EMPTY_FUNCTION);\n }\n for (i=0, length=documentProperties.length; i<length; i++) {\n this._unset(iframeDocument, documentProperties[i]);\n }\n // This doesn't work in Safari 5 \n // See http://stackoverflow.com/questions/992461/is-it-possible-to-override-document-cookie-in-webkit\n this._unset(iframeDocument, \"cookie\", \"\", true);\n }\n\n this.loaded = true;\n\n // Trigger the callback\n setTimeout(function() { that.callback(that); }, 0);\n },\n\n _getHtml: function(templateVars) {\n var stylesheets = templateVars.stylesheets,\n html = \"\",\n i = 0,\n length;\n stylesheets = typeof(stylesheets) === \"string\" ? [stylesheets] : stylesheets;\n if (stylesheets) {\n length = stylesheets.length;\n for (; i<length; i++) {\n html += '<link rel=\"stylesheet\" href=\"' + stylesheets[i] + '\">';\n }\n }\n templateVars.stylesheets = html;\n\n return wysihtml5.lang.string(\n '<!DOCTYPE html>'\n + '<meta charset=\"#{charset}\">#{stylesheets}'\n + ''\n ).interpolate(templateVars);\n },\n\n /__\n * Method to unset/override existing variables\n * @example\n * // Make cookie unreadable and unwritable\n * this._unset(document, \"cookie\", \"\", true);\n /\n _unset: function(object, property, value, setter) {\n try { object[property] = value; } catch(e) {}\n\n try { object.defineGetter(property, function() { return value; }); } catch(e) {}\n if (setter) {\n try { object.defineSetter(property, function() {}); } catch(e) {}\n }\n\n if (!wysihtml5.browser.crashesWhenDefineProperty(property)) {\n try {\n var config = {\n get: function() { return value; }\n };\n if (setter) {\n config.set = function() {};\n }\n Object.defineProperty(object, property, config);\n } catch(e) {}\n }\n }\n });\n})(wysihtml5);\n(function() {\n var mapping = {\n \"className\": \"class\"\n };\n wysihtml5.dom.setAttributes = function(attributes) {\n return {\n on: function(element) {\n for (var i in attributes) {\n element.setAttribute(mapping[i] || i, attributes[i]);\n }\n }\n }\n };\n})();wysihtml5.dom.setStyles = function(styles) {\n return {\n on: function(element) {\n var style = element.style;\n if (typeof(styles) === \"string\") {\n style.cssText += \";\" + styles;\n return;\n }\n for (var i in styles) {\n if (i === \"float\") {\n style.cssFloat = styles[i];\n style.styleFloat = styles[i];\n } else {\n style[i] = styles[i];\n }\n }\n }\n };\n};/\n * Simulate HTML5 placeholder attribute\n \n * Needed since\n * - div[contentEditable] elements don't support it\n * - older browsers (such as IE8 and Firefox 3.6) don't support it at all\n \n * @param {Object} parent Instance of main wysihtml5.Editor class\n * @param {Element} view Instance of wysihtml5.views. class\n * @param {String} placeholderText\n \n * @example\n * wysihtml.dom.simulatePlaceholder(this, composer, \"Foobar\");\n /\n(function(dom) {\n dom.simulatePlaceholder = function(editor, view, placeholderText) {\n var CLASS_NAME = \"placeholder\",\n unset = function() {\n if (view.hasPlaceholderSet()) {\n view.clear();\n }\n dom.removeClass(view.element, CLASS_NAME);\n },\n set = function() {\n if (view.isEmpty()) {\n view.setValue(placeholderText);\n dom.addClass(view.element, CLASS_NAME);\n }\n };\n\n editor\n .observe(\"set_placeholder\", set)\n .observe(\"unset_placeholder\", unset)\n .observe(\"focus:composer\", unset)\n .observe(\"paste:composer\", unset)\n .observe(\"blur:composer\", set);\n\n set();\n };\n})(wysihtml5.dom);\n(function(dom) {\n var documentElement = document.documentElement;\n if (\"textContent\" in documentElement) {\n dom.setTextContent = function(element, text) {\n element.textContent = text;\n };\n\n dom.getTextContent = function(element) {\n return element.textContent;\n };\n } else if (\"innerText\" in documentElement) {\n dom.setTextContent = function(element, text) {\n element.innerText = text;\n };\n\n dom.getTextContent = function(element) {\n return element.innerText;\n };\n } else {\n dom.setTextContent = function(element, text) {\n element.nodeValue = text;\n };\n\n dom.getTextContent = function(element) {\n return element.nodeValue;\n };\n }\n})(wysihtml5.dom);\n\n/__\n * Fix most common html formatting misbehaviors of browsers implementation when inserting\n * content via copy & paste contentEditable\n \n * @author Christopher Blum\n /\nwysihtml5.quirks.cleanPastedHTML = (function() {\n // TODO: We probably need more rules here\n var defaultRules = {\n // When pasting underlined links into a contentEditable, IE thinks, it has to insert to keep the styling\n \"a u\": wysihtml5.dom.replaceWithChildNodes\n };\n \n function cleanPastedHTML(elementOrHtml, rules, context) {\n rules = rules || defaultRules;\n context = context || elementOrHtml.ownerDocument || document;\n \n var element,\n isString = typeof(elementOrHtml) === \"string\",\n method,\n matches,\n matchesLength,\n i,\n j = 0;\n if (isString) {\n element = wysihtml5.dom.getAsDom(elementOrHtml, context);\n } else {\n element = elementOrHtml;\n }\n \n for (i in rules) {\n matches = element.querySelectorAll(i);\n method = rules[i];\n matchesLength = matches.length;\n for (; j<matchesLength; j++) {\n method(matches[j]);\n }\n }\n \n matches = elementOrHtml = rules = null;\n \n return isString ? element.innerHTML : element;\n }\n \n return cleanPastedHTML;\n})();/__\n * IE and Opera leave an empty paragraph in the contentEditable element after clearing it\n \n * @param {Object} contentEditableElement The contentEditable element to observe for clearing events\n * @exaple\n * wysihtml5.quirks.ensureProperClearing(myContentEditableElement);\n /\n(function(wysihtml5) {\n var dom = wysihtml5.dom;\n \n wysihtml5.quirks.ensureProperClearing = (function() {\n var clearIfNecessary = function(event) {\n var element = this;\n setTimeout(function() {\n var innerHTML = element.innerHTML.toLowerCase();\n if (innerHTML == \"
- |
) and the list is the first child of the contentEditable element, it's impossible to delete the list by hitting backspace\n \n * @param {Object} contentEditableElement The contentEditable element to observe for clearing events\n * @exaple\n * wysihtml5.quirks.ensureProperClearing(myContentEditableElement);\n /\n wysihtml5.quirks.ensureProperClearingOfLists = (function() {\n var ELEMENTS_THAT_CONTAIN_LI = [\"OL\", \"UL\", \"MENU\"];\n\n var clearIfNecessary = function(element, contentEditableElement) {\n if (!contentEditableElement.firstChild || !wysihtml5.lang.array(ELEMENTS_THAT_CONTAIN_LI).contains(contentEditableElement.firstChild.nodeName)) {\n return;\n }\n\n var list = dom.getParentElement(element, { nodeName: ELEMENTS_THAT_CONTAIN_LI });\n if (!list) {\n return;\n }\n\n var listIsFirstChildOfContentEditable = list == contentEditableElement.firstChild;\n if (!listIsFirstChildOfContentEditable) {\n return;\n }\n\n var hasOnlyOneListItem = list.childNodes.length <= 1;\n if (!hasOnlyOneListItem) {\n return;\n }\n\n var onlyListItemIsEmpty = list.firstChild ? list.firstChild.innerHTML === \"\" : true;\n if (!onlyListItemIsEmpty) {\n return;\n }\n\n list.parentNode.removeChild(list);\n };\n\n return function(composer) {\n dom.observe(composer.element, \"keydown\", function(event) {\n if (event.keyCode !== wysihtml5.BACKSPACE_KEY) {\n return;\n }\n\n var element = composer.selection.getSelectedNode();\n clearIfNecessary(element, composer.element);\n });\n };\n })();\n\n})(wysihtml5);\n// See https://bugzilla.mozilla.org/show_bug.cgi?id=664398\n//\n// In Firefox this:\n// var d = document.createElement(\"div\");\n// d.innerHTML ='<a href=\"~\">';\n// d.innerHTML;\n// will result in:\n// <a href=\"%7E\">\n// which is wrong\n(function(wysihtml5) {\n var TILDE_ESCAPED = \"%7E\";\n wysihtml5.quirks.getCorrectInnerHTML = function(element) {\n var innerHTML = element.innerHTML;\n if (innerHTML.indexOf(TILDEESCAPED) === -1) {\n return innerHTML;\n }\n \n var elementsWithTilde = element.querySelectorAll(\"[href='~'], [src_='~']\"),\n url,\n urlToSearch,\n length,\n i;\n for (i=0, length=elementsWithTilde.length; i<length; i++) {\n url = elementsWithTilde[i].href || elementsWithTilde[i].src;\n urlToSearch = wysihtml5.lang.string(url).replace(\"~\").by(TILDE_ESCAPED);\n innerHTML = wysihtml5.lang.string(innerHTML).replace(urlToSearch).by(url);\n }\n return innerHTML;\n };\n})(wysihtml5);/__\n * Some browsers don't insert line breaks when hitting return in a contentEditable element\n * - Opera & IE insert newon return\n * - Chrome & Safari insert new
on return (yippie!)\n \n * @param {Element} element\n \n * @example\n * wysihtml5.quirks.insertLineBreakOnReturn(element);\n /\n(function(wysihtml5) {\n var dom = wysihtml5.dom,\n USE_NATIVE_LINE_BREAK_WHEN_CARET_INSIDE_TAGS = [\"LI\", \"P\", \"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\"],\n LIST_TAGS = [\"UL\", \"OL\", \"MENU\"];\n \n wysihtml5.quirks.insertLineBreakOnReturn = function(composer) {\n function unwrap(selectedNode) {\n var parentElement = dom.getParentElement(selectedNode, { nodeName: [\"P\", \"DIV\"] }, 2);\n if (!parentElement) {\n return;\n }\n\n var invisibleSpace = document.createTextNode(wysihtml5.INVISIBLE_SPACE);\n dom.insert(invisibleSpace).before(parentElement);\n dom.replaceWithChildNodes(parentElement);\n composer.selection.selectNode(invisibleSpace);\n }\n\n function keyDown(event) {\n var keyCode = event.keyCode;\n if (event.shiftKey || (keyCode !== wysihtml5.ENTER_KEY && keyCode !== wysihtml5.BACKSPACE_KEY)) {\n return;\n }\n\n var element = event.target,\n selectedNode = composer.selection.getSelectedNode(),\n blockElement = dom.getParentElement(selectedNode, { nodeName: USE_NATIVE_LINE_BREAK_WHEN_CARET_INSIDE_TAGS }, 4);\n if (blockElement) {\n // Some browsers create
elements after leaving a list\n // check after keydown of backspace and return whether a
got inserted and unwrap it\n if (blockElement.nodeName === \"LI\" && (keyCode === wysihtml5.ENTER_KEY || keyCode === wysihtml5.BACKSPACE_KEY)) {\n setTimeout(function() {\n var selectedNode = composer.selection.getSelectedNode(),\n list,\n div;\n if (!selectedNode) {\n return;\n }\n\n list = dom.getParentElement(selectedNode, {\n nodeName: LIST_TAGS\n }, 2);\n\n if (list) {\n return;\n }\n\n unwrap(selectedNode);\n }, 0);\n } else if (blockElement.nodeName.match(/H[1-6]/) && keyCode === wysihtml5.ENTER_KEY) {\n setTimeout(function() {\n unwrap(composer.selection.getSelectedNode());\n }, 0);\n } \n return;\n }\n\n if (keyCode === wysihtml5.ENTER_KEY && !wysihtml5.browser.insertsLineBreaksOnReturn()) {\n composer.commands.exec(\"insertLineBreak\");\n event.preventDefault();\n }\n }\n \n // keypress doesn't fire when you hit backspace\n dom.observe(composer.element.ownerDocument, \"keydown\", keyDown);\n };\n})(wysihtml5);/\n * Force rerendering of a given element\n * Needed to fix display misbehaviors of IE\n \n * @param {Element} element The element object which needs to be rerendered\n * @example\n * wysihtml5.quirks.redraw(document.body);\n /\n(function(wysihtml5) {\n var CLASS_NAME = \"wysihtml5-quirks-redraw\";\n \n wysihtml5.quirks.redraw = function(element) {\n wysihtml5.dom.addClass(element, CLASS_NAME);\n wysihtml5.dom.removeClass(element, CLASS_NAME);\n \n // Following hack is needed for firefox to make sure that image resize handles are properly removed\n try {\n var doc = element.ownerDocument;\n doc.execCommand(\"italic\", false, null);\n doc.execCommand(\"italic\", false, null);\n } catch(e) {}\n };\n})(wysihtml5);/\n * Selection API\n \n * @example\n * var selection = new wysihtml5.Selection(editor);\n /\n(function(wysihtml5) {\n var dom = wysihtml5.dom;\n \n function getCumulativeOffsetTop(element) {\n var top = 0;\n if (element.parentNode) {\n do {\n top += element.offsetTop || 0;\n element = element.offsetParent;\n } while (element);\n }\n return top;\n }\n \n wysihtml5.Selection = Base.extend(\n /* @scope wysihtml5.Selection.prototype _/ {\n constructor: function(editor) {\n // Make sure that our external range library is initialized\n window.rangy.init();\n \n this.editor = editor;\n this.composer = editor.composer;\n this.doc = this.composer.doc;\n },\n \n /\n * Get the current selection as a bookmark to be able to later restore it\n \n * @return {Object} An object that represents the current selection\n /\n getBookmark: function() {\n var range = this.getRange();\n return range && range.cloneRange();\n },\n\n /\n * Restore a selection retrieved via wysihtml5.Selection.prototype.getBookmark\n \n * @param {Object} bookmark An object that represents the current selection\n /\n setBookmark: function(bookmark) {\n if (!bookmark) {\n return;\n }\n\n this.setSelection(bookmark);\n },\n\n /\n * Set the caret in front of the given node\n \n * @param {Object} node The element or text node where to position the caret in front of\n * @example\n * selection.setBefore(myElement);\n /\n setBefore: function(node) {\n var range = rangy.createRange(this.doc);\n range.setStartBefore(node);\n range.setEndBefore(node);\n return this.setSelection(range);\n },\n\n /\n * Set the caret after the given node\n \n * @param {Object} node The element or text node where to position the caret in front of\n * @example\n * selection.setBefore(myElement);\n /\n setAfter: function(node) {\n var range = rangy.createRange(this.doc);\n range.setStartAfter(node);\n range.setEndAfter(node);\n return this.setSelection(range);\n },\n\n /__\n * Ability to select/mark nodes\n \n * @param {Element} node The node/element to select\n * @example\n * selection.selectNode(document.getElementById(\"my-image\"));\n /\n selectNode: function(node) {\n var range = rangy.createRange(this.doc),\n isElement = node.nodeType === wysihtml5.ELEMENT_NODE,\n canHaveHTML = \"canHaveHTML\" in node ? node.canHaveHTML : (node.nodeName !== \"IMG\"),\n content = isElement ? node.innerHTML : node.data,\n isEmpty = (content === \"\" || content === wysihtml5.INVISIBLE_SPACE),\n displayStyle = dom.getStyle(\"display\").from(node),\n isBlockElement = (displayStyle === \"block\" || displayStyle === \"list-item\");\n\n if (isEmpty && isElement && canHaveHTML) {\n // Make sure that caret is visible in node by inserting a zero width no breaking space\n try { node.innerHTML = wysihtml5.INVISIBLE_SPACE; } catch(e) {}\n }\n\n if (canHaveHTML) {\n range.selectNodeContents(node);\n } else {\n range.selectNode(node);\n }\n\n if (canHaveHTML && isEmpty && isElement) {\n range.collapse(isBlockElement);\n } else if (canHaveHTML && isEmpty) {\n range.setStartAfter(node);\n range.setEndAfter(node);\n }\n\n this.setSelection(range);\n },\n\n /\n * Get the node which contains the selection\n \n * @param {Boolean} [controlRange](only IE) Whether it should return the selected ControlRange element when the selection type is a \"ControlRange\"\n * @return {Object} The node that contains the caret\n * @example\n * var nodeThatContainsCaret = selection.getSelectedNode();\n /\n getSelectedNode: function(controlRange) {\n var selection,\n range;\n\n if (controlRange && this.doc.selection && this.doc.selection.type === \"Control\") {\n range = this.doc.selection.createRange();\n if (range && range.length) {\n return range.item(0);\n }\n }\n\n selection = this.getSelection(this.doc);\n if (selection.focusNode === selection.anchorNode) {\n return selection.focusNode;\n } else {\n range = this.getRange(this.doc);\n return range ? range.commonAncestorContainer : this.doc.body;\n }\n },\n\n executeAndRestore: function(method, restoreScrollPosition) {\n var body = this.doc.body,\n oldScrollTop = restoreScrollPosition && body.scrollTop,\n oldScrollLeft = restoreScrollPosition && body.scrollLeft,\n className = \"_wysihtml5-temp-placeholder\",\n placeholderHTML = '<span class=\"' + className + '\">' + wysihtml5.INVISIBLE_SPACE + '',\n range = this.getRange(this.doc),\n newRange;\n \n // Nothing selected, execute and say goodbye\n if (!range) {\n method(body, body);\n return;\n }\n \n var node = range.createContextualFragment(placeholderHTML);\n range.insertNode(node);\n \n // Make sure that a potential error doesn't cause our placeholder element to be left as a placeholder\n try {\n method(range.startContainer, range.endContainer);\n } catch(e3) {\n setTimeout(function() { throw e3; }, 0);\n }\n \n caretPlaceholder = this.doc.querySelector(\".\" + className);\n if (caretPlaceholder) {\n newRange = rangy.createRange(this.doc);\n newRange.selectNode(caretPlaceholder);\n newRange.deleteContents();\n this.setSelection(newRange);\n } else {\n // fallback for when all hell breaks loose\n body.focus();\n }\n\n if (restoreScrollPosition) {\n body.scrollTop = oldScrollTop;\n body.scrollLeft = oldScrollLeft;\n }\n\n // Remove it again, just to make sure that the placeholder is definitely out of the dom tree\n try {\n caretPlaceholder.parentNode.removeChild(caretPlaceholder);\n } catch(e4) {}\n },\n\n /\n * Different approach of preserving the selection (doesn't modify the dom)\n * Takes all text nodes in the selection and saves the selection position in the first and last one\n */\n executeAndRestoreSimple: function(method) {\n var range = this.getRange(),\n body = this.doc.body,\n newRange,\n firstNode,\n lastNode,\n textNodes,\n rangeBackup;\n\n // Nothing selected, execute and say goodbye\n if (!range) {\n method(body, body);\n return;\n }\n\n textNodes = range.getNodes([3]);\n firstNode = textNodes[0] || range.startContainer;\n lastNode = textNodes[textNodes.length - 1] || range.endContainer;\n\n rangeBackup = {\n collapsed: range.collapsed,\n startContainer: firstNode,\n startOffset: firstNode === range.startContainer ? range.startOffset : 0,\n endContainer: lastNode,\n endOffset: lastNode === range.endContainer ? range.endOffset : lastNode.length\n };\n\n try {\n method(range.startContainer, range.endContainer);\n } catch(e) {\n setTimeout(function() { throw e; }, 0);\n }\n\n newRange = rangy.createRange(this.doc);\n try { newRange.setStart(rangeBackup.startContainer, rangeBackup.startOffset); } catch(e1) {}\n try { newRange.setEnd(rangeBackup.endContainer, rangeBackup.endOffset); } catch(e2) {}\n try { this.setSelection(newRange); } catch(e3) {}\n },\n\n /\n * Insert html at the caret position and move the cursor after the inserted html\n \n * @param {String} html HTML string to insert\n * @example\n * selection.insertHTML(\"
foobar
\");\n /\n insertHTML: function(html) {\n var range = rangy.createRange(this.doc),\n node = range.createContextualFragment(html),\n lastChild = node.lastChild;\n this.insertNode(node);\n if (lastChild) {\n this.setAfter(lastChild);\n }\n },\n\n /\n * Insert a node at the caret position and move the cursor behind it\n \n * @param {Object} node HTML string to insert\n * @example\n * selection.insertNode(document.createTextNode(\"foobar\"));\n /\n insertNode: function(node) {\n var range = this.getRange();\n if (range) {\n range.insertNode(node);\n }\n },\n\n /\n * Wraps current selection with the given node\n \n * @param {Object} node The node to surround the selected elements with\n /\n surround: function(node) {\n var range = this.getRange();\n if (!range) {\n return;\n }\n\n try {\n // This only works when the range boundaries are not overlapping other elements\n range.surroundContents(node);\n this.selectNode(node);\n } catch(e) {\n // fallback\n node.appendChild(range.extractContents());\n range.insertNode(node);\n }\n },\n\n /\n * Scroll the current caret position into the view\n * FIXME: This is a bit hacky, there might be a smarter way of doing this\n \n * @example\n * selection.scrollIntoView();\n /\n scrollIntoView: function() {\n var doc = this.doc,\n hasScrollBars = doc.documentElement.scrollHeight > doc.documentElement.offsetHeight,\n tempElement = doc._wysihtml5ScrollIntoViewElement = doc._wysihtml5ScrollIntoViewElement || (function() {\n var element = doc.createElement(\"span\");\n // The element needs content in order to be able to calculate it's position properly\n element.innerHTML = wysihtml5.INVISIBLE_SPACE;\n return element;\n })(),\n offsetTop;\n\n if (hasScrollBars) {\n this.insertNode(tempElement);\n offsetTop = _getCumulativeOffsetTop(tempElement);\n tempElement.parentNode.removeChild(tempElement);\n if (offsetTop > doc.body.scrollTop) {\n doc.body.scrollTop = offsetTop;\n }\n }\n },\n\n /\n * Select line where the caret is in\n /\n selectLine: function() {\n if (wysihtml5.browser.supportsSelectionModify()) {\n this._selectLine_W3C();\n } else if (this.doc.selection) {\n this._selectLine_MSIE();\n }\n },\n\n /__\n * See https://developer.mozilla.org/en/DOM/Selection/modify\n /\n _selectLine_W3C: function() {\n var win = this.doc.defaultView,\n selection = win.getSelection();\n selection.modify(\"extend\", \"left\", \"lineboundary\");\n selection.modify(\"extend\", \"right\", \"lineboundary\");\n },\n\n _selectLine_MSIE: function() {\n var range = this.doc.selection.createRange(),\n rangeTop = range.boundingTop,\n rangeHeight = range.boundingHeight,\n scrollWidth = this.doc.body.scrollWidth,\n rangeBottom,\n rangeEnd,\n measureNode,\n i,\n j;\n\n if (!range.moveToPoint) {\n return;\n }\n\n if (rangeTop === 0) {\n // Don't know why, but when the selection ends at the end of a line\n // range.boundingTop is 0\n measureNode = this.doc.createElement(\"span\");\n this.insertNode(measureNode);\n rangeTop = measureNode.offsetTop;\n measureNode.parentNode.removeChild(measureNode);\n }\n\n rangeTop += 1;\n\n for (i=-10; i<scrollWidth; i+=2) {\n try {\n range.moveToPoint(i, rangeTop);\n break;\n } catch(e1) {}\n }\n\n // Investigate the following in order to handle multi line selections\n // rangeBottom = rangeTop + (rangeHeight ? (rangeHeight - 1) : 0);\n rangeBottom = rangeTop;\n rangeEnd = this.doc.selection.createRange();\n for (j=scrollWidth; j>=0; j--) {\n try {\n rangeEnd.moveToPoint(j, rangeBottom);\n break;\n } catch(e2) {}\n }\n\n range.setEndPoint(\"EndToEnd\", rangeEnd);\n range.select();\n },\n\n getText: function() {\n var selection = this.getSelection();\n return selection ? selection.toString() : \"\";\n },\n\n getNodes: function(nodeType, filter) {\n var range = this.getRange();\n if (range) {\n return range.getNodes([nodeType], filter);\n } else {\n return [];\n }\n },\n \n getRange: function() {\n var selection = this.getSelection();\n return selection && selection.rangeCount && selection.getRangeAt(0);\n },\n\n getSelection: function() {\n return rangy.getSelection(this.doc.defaultView || this.doc.parentWindow);\n },\n\n setSelection: function(range) {\n var win = this.doc.defaultView || this.doc.parentWindow,\n selection = rangy.getSelection(win);\n return selection.setSingleRange(range);\n }\n });\n \n})(wysihtml5);\n/\n * Inspired by the rangy CSS Applier module written by Tim Down and licensed under the MIT license.\n * http://code.google.com/p/rangy/\n \n * changed in order to be able ...\n * - to use custom tags\n * - to detect and replace similar css classes via reg exp\n /\n(function(wysihtml5, rangy) {\n var defaultTagName = \"span\";\n \n var REG_EXP_WHITE_SPACE = /\s+/g;\n \n function hasClass(el, cssClass, regExp) {\n if (!el.className) {\n return false;\n }\n \n var matchingClassNames = el.className.match(regExp) || [];\n return matchingClassNames[matchingClassNames.length - 1] === cssClass;\n }\n\n function addClass(el, cssClass, regExp) {\n if (el.className) {\n removeClass(el, regExp);\n el.className += \" \" + cssClass;\n } else {\n el.className = cssClass;\n }\n }\n\n function removeClass(el, regExp) {\n if (el.className) {\n el.className = el.className.replace(regExp, \"\");\n }\n }\n \n function hasSameClasses(el1, el2) {\n return el1.className.replace(REG_EXP_WHITE_SPACE, \" \") == el2.className.replace(REG_EXP_WHITE_SPACE, \" \");\n }\n\n function replaceWithOwnChildren(el) {\n var parent = el.parentNode;\n while (el.firstChild) {\n parent.insertBefore(el.firstChild, el);\n }\n parent.removeChild(el);\n }\n\n function elementsHaveSameNonClassAttributes(el1, el2) {\n if (el1.attributes.length != el2.attributes.length) {\n return false;\n }\n for (var i = 0, len = el1.attributes.length, attr1, attr2, name; i < len; ++i) {\n attr1 = el1.attributes[i];\n name = attr1.name;\n if (name != \"class\") {\n attr2 = el2.attributes.getNamedItem(name);\n if (attr1.specified != attr2.specified) {\n return false;\n }\n if (attr1.specified && attr1.nodeValue !== attr2.nodeValue) {\n return false;\n }\n }\n }\n return true;\n }\n\n function isSplitPoint(node, offset) {\n if (rangy.dom.isCharacterDataNode(node)) {\n if (offset == 0) {\n return !!node.previousSibling;\n } else if (offset == node.length) {\n return !!node.nextSibling;\n } else {\n return true;\n }\n }\n\n return offset > 0 && offset < node.childNodes.length;\n }\n\n function splitNodeAt(node, descendantNode, descendantOffset) {\n var newNode;\n if (rangy.dom.isCharacterDataNode(descendantNode)) {\n if (descendantOffset == 0) {\n descendantOffset = rangy.dom.getNodeIndex(descendantNode);\n descendantNode = descendantNode.parentNode;\n } else if (descendantOffset == descendantNode.length) {\n descendantOffset = rangy.dom.getNodeIndex(descendantNode) + 1;\n descendantNode = descendantNode.parentNode;\n } else {\n newNode = rangy.dom.splitDataNode(descendantNode, descendantOffset);\n }\n }\n if (!newNode) {\n newNode = descendantNode.cloneNode(false);\n if (newNode.id) {\n newNode.removeAttribute(\"id\");\n }\n var child;\n while ((child = descendantNode.childNodes[descendantOffset])) {\n newNode.appendChild(child);\n }\n rangy.dom.insertAfter(newNode, descendantNode);\n }\n return (descendantNode == node) ? newNode : splitNodeAt(node, newNode.parentNode, rangy.dom.getNodeIndex(newNode));\n }\n \n function Merge(firstNode) {\n this.isElementMerge = (firstNode.nodeType == wysihtml5.ELEMENT_NODE);\n this.firstTextNode = this.isElementMerge ? firstNode.lastChild : firstNode;\n this.textNodes = [this.firstTextNode];\n }\n\n Merge.prototype = {\n doMerge: function() {\n var textBits = [], textNode, parent, text;\n for (var i = 0, len = this.textNodes.length; i < len; ++i) {\n textNode = this.textNodes[i];\n parent = textNode.parentNode;\n textBits[i] = textNode.data;\n if (i) {\n parent.removeChild(textNode);\n if (!parent.hasChildNodes()) {\n parent.parentNode.removeChild(parent);\n }\n }\n }\n this.firstTextNode.data = text = textBits.join(\"\");\n return text;\n },\n\n getLength: function() {\n var i = this.textNodes.length, len = 0;\n while (i--) {\n len += this.textNodes[i].length;\n }\n return len;\n },\n\n toString: function() {\n var textBits = [];\n for (var i = 0, len = this.textNodes.length; i < len; ++i) {\n textBits[i] = \"'\" + this.textNodes[i].data + \"'\";\n }\n return \"[Merge(\" + textBits.join(\",\") + \")]\";\n }\n };\n\n function HTMLApplier(tagNames, cssClass, similarClassRegExp, normalize) {\n this.tagNames = tagNames || [defaultTagName];\n this.cssClass = cssClass || \"\";\n this.similarClassRegExp = similarClassRegExp;\n this.normalize = normalize;\n this.applyToAnyTagName = false;\n }\n\n HTMLApplier.prototype = {\n getAncestorWithClass: function(node) {\n var cssClassMatch;\n while (node) {\n cssClassMatch = this.cssClass ? hasClass(node, this.cssClass, this.similarClassRegExp) : true;\n if (node.nodeType == wysihtml5.ELEMENT_NODE && rangy.dom.arrayContains(this.tagNames, node.tagName.toLowerCase()) && cssClassMatch) {\n return node;\n }\n node = node.parentNode;\n }\n return false;\n },\n\n // Normalizes nodes after applying a CSS class to a Range.\n postApply: function(textNodes, range) {\n var firstNode = textNodes[0], lastNode = textNodes[textNodes.length - 1];\n\n var merges = [], currentMerge;\n\n var rangeStartNode = firstNode, rangeEndNode = lastNode;\n var rangeStartOffset = 0, rangeEndOffset = lastNode.length;\n\n var textNode, precedingTextNode;\n\n for (var i = 0, len = textNodes.length; i < len; ++i) {\n textNode = textNodes[i];\n precedingTextNode = this.getAdjacentMergeableTextNode(textNode.parentNode, false);\n if (precedingTextNode) {\n if (!currentMerge) {\n currentMerge = new Merge(precedingTextNode);\n merges.push(currentMerge);\n }\n currentMerge.textNodes.push(textNode);\n if (textNode === firstNode) {\n rangeStartNode = currentMerge.firstTextNode;\n rangeStartOffset = rangeStartNode.length;\n }\n if (textNode === lastNode) {\n rangeEndNode = currentMerge.firstTextNode;\n rangeEndOffset = currentMerge.getLength();\n }\n } else {\n currentMerge = null;\n }\n }\n\n // Test whether the first node after the range needs merging\n var nextTextNode = this.getAdjacentMergeableTextNode(lastNode.parentNode, true);\n if (nextTextNode) {\n if (!currentMerge) {\n currentMerge = new Merge(lastNode);\n merges.push(currentMerge);\n }\n currentMerge.textNodes.push(nextTextNode);\n }\n\n // Do the merges\n if (merges.length) {\n for (i = 0, len = merges.length; i < len; ++i) {\n merges[i].doMerge();\n }\n // Set the range boundaries\n range.setStart(rangeStartNode, rangeStartOffset);\n range.setEnd(rangeEndNode, rangeEndOffset);\n }\n },\n \n getAdjacentMergeableTextNode: function(node, forward) {\n var isTextNode = (node.nodeType == wysihtml5.TEXT_NODE);\n var el = isTextNode ? node.parentNode : node;\n var adjacentNode;\n var propName = forward ? \"nextSibling\" : \"previousSibling\";\n if (isTextNode) {\n // Can merge if the node's previous/next sibling is a text node\n adjacentNode = node[propName];\n if (adjacentNode && adjacentNode.nodeType == wysihtml5.TEXT_NODE) {\n return adjacentNode;\n }\n } else {\n // Compare element with its sibling\n adjacentNode = el[propName];\n if (adjacentNode && this.areElementsMergeable(node, adjacentNode)) {\n return adjacentNode[forward ? \"firstChild\" : \"lastChild\"];\n }\n }\n return null;\n },\n \n areElementsMergeable: function(el1, el2) {\n return rangy.dom.arrayContains(this.tagNames, (el1.tagName || \"\").toLowerCase())\n && rangy.dom.arrayContains(this.tagNames, (el2.tagName || \"\").toLowerCase())\n && hasSameClasses(el1, el2)\n && elementsHaveSameNonClassAttributes(el1, el2);\n },\n\n createContainer: function(doc) {\n var el = doc.createElement(this.tagNames[0]);\n if (this.cssClass) {\n el.className = this.cssClass;\n }\n return el;\n },\n\n applyToTextNode: function(textNode) {\n var parent = textNode.parentNode;\n if (parent.childNodes.length == 1 && rangy.dom.arrayContains(this.tagNames, parent.tagName.toLowerCase())) {\n if (this.cssClass) {\n addClass(parent, this.cssClass, this.similarClassRegExp);\n }\n } else {\n var el = this.createContainer(rangy.dom.getDocument(textNode));\n textNode.parentNode.insertBefore(el, textNode);\n el.appendChild(textNode);\n }\n },\n\n isRemovable: function(el) {\n return rangy.dom.arrayContains(this.tagNames, el.tagName.toLowerCase()) && wysihtml5.lang.string(el.className).trim() == this.cssClass;\n },\n\n undoToTextNode: function(textNode, range, ancestorWithClass) {\n if (!range.containsNode(ancestorWithClass)) {\n // Split out the portion of the ancestor from which we can remove the CSS class\n var ancestorRange = range.cloneRange();\n ancestorRange.selectNode(ancestorWithClass);\n\n if (ancestorRange.isPointInRange(range.endContainer, range.endOffset) && isSplitPoint(range.endContainer, range.endOffset)) {\n splitNodeAt(ancestorWithClass, range.endContainer, range.endOffset);\n range.setEndAfter(ancestorWithClass);\n }\n if (ancestorRange.isPointInRange(range.startContainer, range.startOffset) && isSplitPoint(range.startContainer, range.startOffset)) {\n ancestorWithClass = splitNodeAt(ancestorWithClass, range.startContainer, range.startOffset);\n }\n }\n \n if (this.similarClassRegExp) {\n removeClass(ancestorWithClass, this.similarClassRegExp);\n }\n if (this.isRemovable(ancestorWithClass)) {\n replaceWithOwnChildren(ancestorWithClass);\n }\n },\n\n applyToRange: function(range) {\n var textNodes = range.getNodes([wysihtml5.TEXT_NODE]);\n if (!textNodes.length) {\n try {\n var node = this.createContainer(range.endContainer.ownerDocument);\n range.surroundContents(node);\n this.selectNode(range, node);\n return;\n } catch(e) {}\n }\n \n range.splitBoundaries();\n textNodes = range.getNodes([wysihtml5.TEXT_NODE]);\n \n if (textNodes.length) {\n var textNode;\n\n for (var i = 0, len = textNodes.length; i < len; ++i) {\n textNode = textNodes[i];\n if (!this.getAncestorWithClass(textNode)) {\n this.applyToTextNode(textNode);\n }\n }\n \n range.setStart(textNodes[0], 0);\n textNode = textNodes[textNodes.length - 1];\n range.setEnd(textNode, textNode.length);\n \n if (this.normalize) {\n this.postApply(textNodes, range);\n }\n }\n },\n\n undoToRange: function(range) {\n var textNodes = range.getNodes([wysihtml5.TEXT_NODE]), textNode, ancestorWithClass;\n if (textNodes.length) {\n range.splitBoundaries();\n textNodes = range.getNodes([wysihtml5.TEXT_NODE]);\n } else {\n var doc = range.endContainer.ownerDocument,\n node = doc.createTextNode(wysihtml5.INVISIBLE_SPACE);\n range.insertNode(node);\n range.selectNode(node);\n textNodes = [node];\n }\n \n for (var i = 0, len = textNodes.length; i < len; ++i) {\n textNode = textNodes[i];\n ancestorWithClass = this.getAncestorWithClass(textNode);\n if (ancestorWithClass) {\n this.undoToTextNode(textNode, range, ancestorWithClass);\n }\n }\n \n if (len == 1) {\n this.selectNode(range, textNodes[0]);\n } else {\n range.setStart(textNodes[0], 0);\n textNode = textNodes[textNodes.length - 1];\n range.setEnd(textNode, textNode.length);\n\n if (this.normalize) {\n this.postApply(textNodes, range);\n }\n }\n },\n \n selectNode: function(range, node) {\n var isElement = node.nodeType === wysihtml5.ELEMENT_NODE,\n canHaveHTML = \"canHaveHTML\" in node ? node.canHaveHTML : true,\n content = isElement ? node.innerHTML : node.data,\n isEmpty = (content === \"\" || content === wysihtml5.INVISIBLE_SPACE);\n\n if (isEmpty && isElement && canHaveHTML) {\n // Make sure that caret is visible in node by inserting a zero width no breaking space\n try { node.innerHTML = wysihtml5.INVISIBLE_SPACE; } catch(e) {}\n }\n range.selectNodeContents(node);\n if (isEmpty && isElement) {\n range.collapse(false);\n } else if (isEmpty) {\n range.setStartAfter(node);\n range.setEndAfter(node);\n }\n },\n \n getTextSelectedByRange: function(textNode, range) {\n var textRange = range.cloneRange();\n textRange.selectNodeContents(textNode);\n\n var intersectionRange = textRange.intersection(range);\n var text = intersectionRange ? intersectionRange.toString() : \"\";\n textRange.detach();\n\n return text;\n },\n\n isAppliedToRange: function(range) {\n var ancestors = [],\n ancestor,\n textNodes = range.getNodes([wysihtml5.TEXT_NODE]);\n if (!textNodes.length) {\n ancestor = this.getAncestorWithClass(range.startContainer);\n return ancestor ? [ancestor] : false;\n }\n \n for (var i = 0, len = textNodes.length, selectedText; i < len; ++i) {\n selectedText = this.getTextSelectedByRange(textNodes[i], range);\n ancestor = this.getAncestorWithClass(textNodes[i]);\n if (selectedText != \"\" && !ancestor) {\n return false;\n } else {\n ancestors.push(ancestor);\n }\n }\n return ancestors;\n },\n\n toggleRange: function(range) {\n if (this.isAppliedToRange(range)) {\n this.undoToRange(range);\n } else {\n this.applyToRange(range);\n }\n }\n };\n\n wysihtml5.selection.HTMLApplier = HTMLApplier;\n \n})(wysihtml5, rangy);/\n * Rich Text Query/Formatting Commands\n * \n * @example\n * var commands = new wysihtml5.Commands(editor);\n /\nwysihtml5.Commands = Base.extend(\n /* @scope wysihtml5.Commands.prototype / {\n constructor: function(editor) {\n this.editor = editor;\n this.composer = editor.composer;\n this.doc = this.composer.doc;\n },\n \n /__\n * Check whether the browser supports the given command\n \n * @param {String} command The command string which to check (eg. \"bold\", \"italic\", \"insertUnorderedList\")\n * @example\n * commands.supports(\"createLink\");\n /\n support: function(command) {\n return wysihtml5.browser.supportsCommand(this.doc, command);\n },\n \n /__\n * Check whether the browser supports the given command\n \n * @param {String} command The command string which to execute (eg. \"bold\", \"italic\", \"insertUnorderedList\")\n * @param {String} [value] The command value parameter, needed for some commands (\"createLink\", \"insertImage\", ...), optional for commands that don't require one (\"bold\", \"underline\", ...)\n * @example\n * commands.exec(\"insertImage\", \"http://a1.twimg.com/profile_images/113868655/schrei_twitter_reasonably_small.jpg\");\n /\n exec: function(command, value) {\n var obj = wysihtml5.commands[command],\n args = wysihtml5.lang.array(arguments).get(),\n method = obj && obj.exec,\n result = null;\n \n this.editor.fire(\"beforecommand:composer\");\n \n if (method) {\n args.unshift(this.composer);\n result = method.apply(obj, args);\n } else {\n try {\n // try/catch for buggy firefox\n result = this.doc.execCommand(command, false, value);\n } catch(e) {}\n }\n \n this.editor.fire(\"aftercommand:composer\");\n return result;\n },\n \n /__\n * Check whether the current command is active\n * If the caret is within a bold text, then calling this with command \"bold\" should return true\n \n * @param {String} command The command string which to check (eg. \"bold\", \"italic\", \"insertUnorderedList\")\n * @param {String} [commandValue] The command value parameter (eg. for \"insertImage\" the image src)\n * @return {Boolean} Whether the command is active\n * @example\n * var isCurrentSelectionBold = commands.state(\"bold\");\n /\n state: function(command, commandValue) {\n var obj = wysihtml5.commands[command],\n args = wysihtml5.lang.array(arguments).get(),\n method = obj && obj.state;\n if (method) {\n args.unshift(this.composer);\n return method.apply(obj, args);\n } else {\n try {\n // try/catch for buggy firefox\n return this.doc.queryCommandState(command);\n } catch(e) {\n return false;\n }\n }\n },\n \n /__\n * Get the current command's value\n \n * @param {String} command The command string which to check (eg. \"formatBlock\")\n * @return {String} The command value\n * @example\n * var currentBlockElement = commands.value(\"formatBlock\");\n */\n value: function(command) {\n var obj = wysihtml5.commands[command],\n method = obj && obj.value;\n if (method) {\n return method.call(obj, this.composer, command);\n } else {\n try {\n // try/catch for buggy firefox\n return this.doc.queryCommandValue(command);\n } catch(e) {\n return null;\n }\n }\n }\n});\n(function(wysihtml5) {\n var undef;\n \n wysihtml5.commands.bold = {\n exec: function(composer, command) {\n return wysihtml5.commands.formatInline.exec(composer, command, \"b\");\n },\n\n state: function(composer, command, color) {\n // element.ownerDocument.queryCommandState(\"bold\") results:\n // firefox: only \n // chrome: , ,,
, ...\n // ie: , \n // opera: , \n return wysihtml5.commands.formatInline.state(composer, command, \"b\");\n },\n\n value: function() {\n return undef;\n }\n };\n})(wysihtml5);\n\n(function(wysihtml5) {\n var undef,\n NODE_NAME = \"A\",\n dom = wysihtml5.dom;\n \n function _removeFormat(composer, anchors) {\n var length = anchors.length,\n i = 0,\n anchor,\n codeElement,\n textContent;\n for (; i<length; i++) {\n anchor = anchors[i];\n codeElement = dom.getParentElement(anchor, { nodeName: \"code\" });\n textContent = dom.getTextContent(anchor);\n\n // if contains url-like text content, rename it to
to prevent re-autolinking\n // else replace with its childNodes\n if (textContent.match(dom.autoLink.URL_REG_EXP) && !codeElement) {\n //
element is used to prevent later auto-linking of the content\n codeElement = dom.renameElement(anchor, \"code\");\n } else {\n dom.replaceWithChildNodes(anchor);\n }\n }\n }\n\n function _format(composer, attributes) {\n var doc = composer.doc,\n tempClass = \"_wysihtml5-temp-\" + (+new Date()),\n tempClassRegExp = /non-matching-class/g,\n i = 0,\n length,\n anchors,\n anchor,\n hasElementChild,\n isEmpty,\n elementToSetCaretAfter,\n textContent,\n whiteSpace,\n j;\n wysihtml5.commands.formatInline.exec(composer, undef, NODE_NAME, tempClass, tempClassRegExp);\n anchors = doc.querySelectorAll(NODENAME + \".\" + tempClass);\n length = anchors.length;\n for (; i<length; i++) {\n anchor = anchors[i];\n anchor.removeAttribute(\"class\");\n for (j in attributes) {\n anchor.setAttribute(j, attributes[j]);\n }\n }\n\n elementToSetCaretAfter = anchor;\n if (length === 1) {\n textContent = dom.getTextContent(anchor);\n hasElementChild = !!anchor.querySelector(\"\");\n isEmpty = textContent === \"\" || textContent === wysihtml5.INVISIBLE_SPACE;\n if (!hasElementChild && isEmpty) {\n dom.setTextContent(anchor, attributes.text || anchor.href);\n whiteSpace = doc.createTextNode(\" \");\n composer.selection.setAfter(anchor);\n composer.selection.insertNode(whiteSpace);\n elementToSetCaretAfter = whiteSpace;\n }\n }\n composer.selection.setAfter(elementToSetCaretAfter);\n }\n \n wysihtml5.commands.createLink = {\n /\n * TODO: Use HTMLApplier or formatInline here\n \n * Turns selection into a link\n * If selection is already a link, it removes the link and wraps it with a
element\n * The
/\n exec: function(composer, command, value) {\n var anchors = this.state(composer, command);\n if (anchors) {\n // Selection contains links\n composer.selection.executeAndRestore(function() {\n _removeFormat(composer, anchors);\n });\n } else {\n // Create links\n value = typeof(value) === \"object\" ? value : { href: value };\n _format(composer, value);\n }\n },\n\n state: function(composer, command) {\n return wysihtml5.commands.formatInline.state(composer, command, \"A\");\n },\n\n value: function() {\n return undef;\n }\n };\n})(wysihtml5);/\n * document.execCommand(\"fontSize\") will create either inline styles (firefox, chrome) or use font tags\n * which we don't want\n * Instead we set a css class\n _/\n(function(wysihtml5) {\n var undef,\n REG_EXP = /wysiwyg-font-size-[a-z-]+/g;\n \n wysihtml5.commands.fontSize = {\n exec: function(composer, command, size) {\n return wysihtml5.commands.formatInline.exec(composer, command, \"span\", \"wysiwyg-font-size-\" + size, REG_EXP);\n },\n\n state: function(composer, command, size) {\n return wysihtml5.commands.formatInline.state(composer, command, \"span\", \"wysiwyg-font-size-\" + size, REGEXP);\n },\n\n value: function() {\n return undef;\n }\n };\n})(wysihtml5);\n/\n \ document.execCommand(\"foreColor\") will create either inline styles (firefox, chrome) or use font tags\ has no method 'replace' W20150603-16:45:52.066(5.5)? (STDERR) at ServerResponse.http.OutgoingMessage.write (packages/meteorhacks:inject-data/lib/server.js:48:1) W20150603-16:45:52.066(5.5)? (STDERR) at ServerResponse.http.OutgoingMessage.write (packages/gadicohen:inject-initial/lib/inject-core.js:26:1) W20150603-16:45:52.066(5.5)? (STDERR) at ServerResponse.res.write (/home/karabi/.meteor/packages/webapp/.1.2.0.1k7up1h++os+web.browser+web.cordova/npm/node_modules/connect/lib/middleware/compress.js:110:17) W20150603-16:45:52.066(5.5)? (STDERR) at write (_stream_readable.js:602:24) W20150603-16:45:52.066(5.5)? (STDERR) at flow (_stream_readable.js:611:7) W20150603-16:45:52.066(5.5)? (STDERR) at ReadStream.pipeOnReadable (_streamreadable.js:643:5) W20150603-16:45:52.066(5.5)? (STDERR) at ReadStream.emit (events.js:92:17) W20150603-16:45:52.066(5.5)? (STDERR) at emitReadable (_stream_readable.js:427:10) W20150603-16:45:52.067(5.5)? (STDERR) at emitReadable (_stream_readable.js:423:5) W20150603-16:45:52.067(5.5)? (STDERR) at readableAddChunk (_stream_readable.js:166:9)element is needed to avoid auto linking\n * \n * @example\n * // either ...\n * wysihtml5.commands.createLink.exec(composer, \"createLink\", \"http://www.google.de\");\n * // ... or ...\n * wysihtml5.commands.createLink.exec(composer, \"createLink\", { href: \"http://www.google.de\", target: \"_blank\" });\n
Heh, that's quite an error :> Can you show us exactly how you're using inject-initial in your app?
It is used by allow env https://atmospherejs.com/mrt/allow-env
That looks pretty old. There's no github info on the Atmosphere page but it looks like it's https://github.com/nmacmunn/meteor-allow-env/. From looking at the
package.js
, it's written for Meteor <= 0.8.3. How did you even get it to find inject-initial? :) In any event, the problem seems to be that side, so I'd either try find an alternative package or see if the author is willing to update it.