meteorhacks / meteor-inject-initial

Allow injection of arbitrary data to initial Meteor HTML page
Other
78 stars 11 forks source link

Meteor application restarting over and again #15

Closed Karabi-Choudhury closed 8 years ago

Karabi-Choudhury commented 9 years ago

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 *
    1. eminem
    2. \n *
    3. dr. dre
    4. \n *
    5. 50 Cent
    6. \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: , ,

    ,

    , ...\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 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 /\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)

    gadicc commented 9 years ago

    Heh, that's quite an error :> Can you show us exactly how you're using inject-initial in your app?

    Karabi-Choudhury commented 9 years ago

    It is used by allow env https://atmospherejs.com/mrt/allow-env

    gadicc commented 9 years ago

    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.