meteorhacks / inject-data

A way to inject data to the client with initial HTML
MIT License
18 stars 28 forks source link

Doesn't work with Meteor 1.1 #1

Closed michaelrokosh closed 9 years ago

michaelrokosh commented 9 years ago
.meteor/local/build/programs/server/packages/meteorhacks_inject-data.js:113
W20150401-15:27:19.896(3)? (STDERR)     chunk = chunk.replace('</head>', injectHtml + '\n</head>');           // 4
W20150401-15:27:19.896(3)? (STDERR)                   ^
W20150401-15:27:19.902(3)? (STDERR) TypeError: Object rve.apply(this, wysihtml5.lang.array(arguments).get());\n  },\n\n  fire: function(eventName, payload) {\n    this.events = this.events || {};\n    var handlers = this.events[eventName] || [],\n        i        = 0;\n    for (; i<handlers.length; i++) {\n      handlers[i].call(this, payload);\n    }\n    return this;\n  },\n\n  stopObserving: function(eventName, handler) {\n    this.events = this.events || {};\n    var i = 0,\n        handlers,\n        newHandlers;\n    if (eventName) {\n      handlers    = this.events[eventName] || [],\n      newHandlers = [];\n      for (; i<handlers.length; i++) {\n        if (handlers[i] !== handler && handler) {\n          newHandlers.push(handlers[i]);\n        }\n      }\n      this.events[eventName] = newHandlers;\n    } else {\n      // Clean up all events\n      this.events = {};\n    }\n    return this;\n  }\n});wysihtml5.lang.object = function(obj) {\n  return {\n    /**\n     * @example\n     *    wysihtml5.lang.object({ foo: 1, bar: 1 }).merge({ bar: 2, baz: 3 }).get();\n     *    // => { foo: 1, bar: 2, baz: 3 }\n     */\n    merge: function(otherObj) {\n      for (var i in otherObj) {\n        obj[i] = otherObj[i];\n      }\n      return this;\n    },\n    \n    get: function() {\n      return obj;\n    },\n    \n    /**\n     * @example\n     *    wysihtml5.lang.object({ foo: 1 }).clone();\n     *    // => { foo: 1 }\n     */\n    clone: function() {\n      var newObj = {},\n          i;\n      for (i in obj) {\n        newObj[i] = obj[i];\n      }\n      return newObj;\n    },\n    \n    /**\n     * @example\n     *    wysihtml5.lang.object([]).isArray();\n     *    // => true\n     */\n    isArray: function() {\n      return Object.prototype.toString.call(obj) === \"[object Array]\";\n    }\n  };\n};(function() {\n  var WHITE_SPACE_START = /^\\s+/,\n      WHITE_SPACE_END   = /\\s+$/;\n  wysihtml5.lang.string = function(str) {\n    str = String(str);\n    return {\n      /**\n       * @example\n       *    wysihtml5.lang.string(\"   foo   \").trim();\n       *    // => \"foo\"\n       */\n      trim: function() {\n        return str.replace(WHITE_SPACE_START, \"\").replace(WHITE_SPACE_END, \"\");\n      },\n      \n      /**\n       * @example\n       *    wysihtml5.lang.string(\"Hello #{name}\").interpolate({ name: \"Christopher\" });\n       *    // => \"Hello Christopher\"\n       */\n      interpolate: function(vars) {\n        for (var i in vars) {\n          str = this.replace(\"#{\" + i + \"}\").by(vars[i]);\n        }\n        return str;\n      },\n      \n      /**\n       * @example\n       *    wysihtml5.lang.string(\"Hello Tom\").replace(\"Tom\").with(\"Hans\");\n       *    // => \"Hello Hans\"\n       */\n      replace: function(search) {\n        return {\n          by: function(replace) {\n            return str.split(search).join(replace);\n          }\n        }\n      }\n    };\n  };\n})();/**\n * Find urls in descendant text nodes of an element and auto-links them\n * Inspired by http://james.padolsey.com/javascript/find-and-replace-text-with-javascript/\n *\n * @param {Element} element Container element in which to search for urls\n *\n * @example\n *    <div id=\"text-container\">Please click here: www.google.com</div>\n *    <script>wysihtml5.dom.autoLink(document.getElementById(\"text-container\"));</script>\n */\n(function(wysihtml5) {\n  var /**\n       * Don't auto-link urls that are contained in the following elements:\n       */\n      IGNORE_URLS_IN        = wysihtml5.lang.array([\"CODE\", \"PRE\", \"A\", \"SCRIPT\", \"HEAD\", \"TITLE\", \"STYLE\"]),\n      /**\n       * revision 1:\n       *    /(\\S+\\.{1}[^\\s\\,\\.\\!]+)/g\n       *\n       * revision 2:\n       *    /(\\b(((https?|ftp):\\/\\/)|(www\\.))[-A-Z0-9+&@#\\/%?=~_|!:,.;\\[\\]]*[-A-Z0-9+&@#\\/%=~_|])/gim\n       *\n       * put this in the beginning if you don't wan't to match within a word\n       *    (^|[\\>\\(\\{\\[\\s\\>])\n       */\n      URL_REG_EXP           = /((https?:\\/\\/|www\\.)[^\\s<]{3,})/gi,\n      TRAILING_CHAR_REG_EXP = /([^\\w\\/\\-](,?))$/i,\n      MAX_DISPLAY_LENGTH    = 100,\n      BRACKETS              = { \")\": \"(\", \"]\": \"[\", \"}\": \"{\" };\n  \n  function autoLink(element) {\n    if (_hasParentThatShouldBeIgnored(element)) {\n      return element;\n    }\n\n    if (element === element.ownerDocument.documentElement) {\n      element = element.ownerDocument.body;\n    }\n\n    return _parseNode(element);\n  }\n  \n  /**\n   * This is basically a rebuild of\n   * the rails auto_link_urls text helper\n   */\n  function _convertUrlsToLinks(str) {\n    return str.replace(URL_REG_EXP, function(match, url) {\n      var punctuation = (url.match(TRAILING_CHAR_REG_EXP) || [])[1] || \"\",\n          opening     = BRACKETS[punctuation];\n      url = url.replace(TRAILING_CHAR_REG_EXP, \"\");\n\n      if (url.split(opening).length > url.split(punctuation).length) {\n        url = url + punctuation;\n        punctuation = \"\";\n      }\n      var realUrl    = url,\n          displayUrl = url;\n      if (url.length > MAX_DISPLAY_LENGTH) {\n        displayUrl = displayUrl.substr(0, MAX_DISPLAY_LENGTH) + \"...\";\n      }\n      // Add http prefix if necessary\n      if (realUrl.substr(0, 4) === \"www.\") {\n        realUrl = \"http://\" + realUrl;\n      }\n      \n      return '<a href=\"' + realUrl + '\">' + displayUrl + '</a>' + punctuation;\n    });\n  }\n  \n  /**\n   * Creates or (if already cached) returns a temp element\n   * for the given document object\n   */\n  function _getTempElement(context) {\n    var tempElement = context._wysihtml5_tempElement;\n    if (!tempElement) {\n      tempElement = context._wysihtml5_tempElement = context.createElement(\"div\");\n    }\n    return tempElement;\n  }\n  \n  /**\n   * Replaces the original text nodes with the newly auto-linked dom tree\n   */\n  function _wrapMatchesInNode(textNode) {\n    var parentNode  = textNode.parentNode,\n        tempElement = _getTempElement(parentNode.ownerDocument);\n    \n    // We need to insert an empty/temporary <span /> to fix IE quirks\n    // Elsewise IE would strip white space in the beginning\n    tempElement.innerHTML = \"<span></span>\" + _convertUrlsToLinks(textNode.data);\n    tempElement.removeChild(tempElement.firstChild);\n    \n    while (tempElement.firstChild) {\n      // inserts tempElement.firstChild before textNode\n      parentNode.insertBefore(tempElement.firstChild, textNode);\n    }\n    parentNode.removeChild(textNode);\n  }\n  \n  function _hasParentThatShouldBeIgnored(node) {\n    var nodeName;\n    while (node.parentNode) {\n      node = node.parentNode;\n      nodeName = node.nodeName;\n      if (IGNORE_URLS_IN.contains(nodeName)) {\n        return true;\n      } else if (nodeName === \"body\") {\n        return false;\n      }\n    }\n    return false;\n  }\n  \n  function _parseNode(element) {\n    if (IGNORE_URLS_IN.contains(element.nodeName)) {\n      return;\n    }\n    \n    if (element.nodeType === wysihtml5.TEXT_NODE && element.data.match(URL_REG_EXP)) {\n      _wrapMatchesInNode(element);\n      return;\n    }\n    \n    var childNodes        = wysihtml5.lang.array(element.childNodes).get(),\n        childNodesLength  = childNodes.length,\n        i                 = 0;\n    \n    for (; i<childNodesLength; i++) {\n      _parseNode(childNodes[i]);\n    }\n    \n    return element;\n  }\n  \n  wysihtml5.dom.autoLink = autoLink;\n  \n  // Reveal url reg exp to the outside\n  wysihtml5.dom.autoLink.URL_REG_EXP = URL_REG_EXP;\n})(wysihtml5);(function(wysihtml5) {\n  var supportsClassList = wysihtml5.browser.supportsClassList(),\n      api               = wysihtml5.dom;\n  \n  api.addClass = function(element, className) {\n    if (supportsClassList) {\n      return element.classList.add(className);\n    }\n    if (api.hasClass(element, className)) {\n      return;\n    }\n    element.className += \" \" + className;\n  };\n  \n  api.removeClass = function(element, className) {\n    if (supportsClassList) {\n      return element.classList.remove(className);\n    }\n    \n    element.className = element.className.replace(new RegExp(\"(^|\\\\s+)\" + className + \"(\\\\s+|$)\"), \" \");\n  };\n  \n  api.hasClass = function(element, className) {\n    if (supportsClassList) {\n      return element.classList.contains(className);\n    }\n    \n    var elementClassName = element.className;\n    return (elementClassName.length > 0 && (elementClassName == className || new RegExp(\"(^|\\\\s)\" + className + \"(\\\\s|$)\").test(elementClassName)));\n  };\n})(wysihtml5);\nwysihtml5.dom.contains = (function() {\n  var documentElement = document.documentElement;\n  if (documentElement.contains) {\n    return function(container, element) {\n      if (element.nodeType !== wysihtml5.ELEMENT_NODE) {\n        element = element.parentNode;\n      }\n      return container !== element && container.contains(element);\n    };\n  } else if (documentElement.compareDocumentPosition) {\n    return function(container, element) {\n      // https://developer.mozilla.org/en/DOM/Node.compareDocumentPosition\n      return !!(container.compareDocumentPosition(element) & 16);\n    };\n  }\n})();/**\n * Converts an HTML fragment/element into a unordered/ordered list\n *\n * @param {Element} element The element which should be turned into a list\n * @param {String} listType The list type in which to convert the tree (either \"ul\" or \"ol\")\n * @return {Element} The created list\n *\n * @example\n *    <!-- Assume the following dom: -->\n *    <span id=\"pseudo-list\">\n *      eminem<br>\n *      dr. dre\n *      <div>50 Cent</div>\n *    </span>\n *\n *    <script>\n *      wysihtml5.dom.convertToList(document.getElementById(\"pseudo-list\"), \"ul\");\n *    </script>\n *\n *    <!-- Will result in: -->\n *    <ul>\n *      <li>eminem</li>\n *      <li>dr. dre</li>\n *      <li>50 Cent</li>\n *    </ul>\n */\nwysihtml5.dom.convertToList = (function() {\n  function _createListItem(doc, list) {\n    var listItem = doc.createElement(\"li\");\n    list.appendChild(listItem);\n    return listItem;\n  }\n  \n  function _createList(doc, type) {\n    return doc.createElement(type);\n  }\n  \n  function convertToList(element, listType) {\n    if (element.nodeName === \"UL\" || element.nodeName === \"OL\" || element.nodeName === \"MENU\") {\n      // Already a list\n      return element;\n    }\n    \n    var doc               = element.ownerDocument,\n        list              = _createList(doc, listType),\n        lineBreaks        = element.querySelectorAll(\"br\"),\n        lineBreaksLength  = lineBreaks.length,\n        childNodes,\n        childNodesLength,\n        childNode,\n        lineBreak,\n        parentNode,\n        isBlockElement,\n        isLineBreak,\n        currentListItem,\n        i;\n    \n    // First find <br> at the end of inline elements and move them behind them\n    for (i=0; i<lineBreaksLength; i++) {\n      lineBreak = lineBreaks[i];\n      while ((parentNode = lineBreak.parentNode) && parentNode !== element && parentNode.lastChild === lineBreak) {\n        if (wysihtml5.dom.getStyle(\"display\").from(parentNode) === \"block\") {\n          parentNode.removeChild(lineBreak);\n          break;\n        }\n        wysihtml5.dom.insert(lineBreak).after(lineBreak.parentNode);\n      }\n    }\n    \n    childNodes        = wysihtml5.lang.array(element.childNodes).get();\n    childNodesLength  = childNodes.length;\n    \n    for (i=0; i<childNodesLength; i++) {\n      currentListItem   = currentListItem || _createListItem(doc, list);\n      childNode         = childNodes[i];\n      isBlockElement    = wysihtml5.dom.getStyle(\"display\").from(childNode) === \"block\";\n      isLineBreak       = childNode.nodeName === \"BR\";\n      \n      if (isBlockElement) {\n        // Append blockElement to current <li> if empty, otherwise create a new one\n        currentListItem = currentListItem.firstChild ? _createListItem(doc, list) : currentListItem;\n        currentListItem.appendChild(childNode);\n        currentListItem = null;\n        continue;\n      }\n      \n      if (isLineBreak) {\n        // Only create a new list item in the next iteration when the current one has already content\n        currentListItem = currentListItem.firstChild ? null : currentListItem;\n        continue;\n      }\n      \n      currentListItem.appendChild(childNode);\n    }\n    \n    element.parentNode.replaceChild(list, element);\n    return list;\n  }\n  \n  return convertToList;\n})();/**\n * Copy a set of attributes from one element to another\n *\n * @param {Array} attributesToCopy List of attributes which should be copied\n * @return {Object} Returns an object which offers the \"from\" method which can be invoked with the element where to\n *    copy the attributes from., this again returns an object which provides a method named \"to\" which can be invoked \n *    with the element where to copy the attributes to (see example)\n *\n * @example\n *    var textarea    = document.querySelector(\"textarea\"),\n *        div         = document.querySelector(\"div[contenteditable=true]\"),\n *        anotherDiv  = document.querySelector(\"div.preview\");\n *    wysihtml5.dom.copyAttributes([\"spellcheck\", \"value\", \"placeholder\"]).from(textarea).to(div).andTo(anotherDiv);\n *\n */\nwysihtml5.dom.copyAttributes = function(attributesToCopy) {\n  return {\n    from: function(elementToCopyFrom) {\n      return {\n        to: function(elementToCopyTo) {\n          var attribute,\n              i         = 0,\n              length    = attributesToCopy.length;\n          for (; i<length; i++) {\n            attribute = attributesToCopy[i];\n            if (typeof(elementToCopyFrom[attribute]) !== \"undefined\" && elementToCopyFrom[attribute] !== \"\") {\n              elementToCopyTo[attribute] = elementToCopyFrom[attribute];\n            }\n          }\n          return { andTo: arguments.callee };\n        }\n      };\n    }\n  };\n};/**\n * Copy a set of styles from one element to another\n * Please note that this only works properly across browsers when the element from which to copy the styles\n * is in the dom\n *\n * Interesting article on how to copy styles\n *\n * @param {Array} stylesToCopy List of styles which should be copied\n * @return {Object} Returns an object which offers the \"from\" method which can be invoked with the element where to\n *    copy the styles from., this again returns an object which provides a method named \"to\" which can be invoked \n *    with the element where to copy the styles to (see example)\n *\n * @example\n *    var textarea    = document.querySelector(\"textarea\"),\n *        div         = document.querySelector(\"div[contenteditable=true]\"),\n *        anotherDiv  = document.querySelector(\"div.preview\");\n *    wysihtml5.dom.copyStyles([\"overflow-y\", \"width\", \"height\"]).from(textarea).to(div).andTo(anotherDiv);\n *\n */\n(function(dom) {\n  \n  /**\n   * Mozilla, WebKit and Opera recalculate the computed width when box-sizing: boder-box; is set\n   * So if an element has \"width: 200px; -moz-box-sizing: border-box; border: 1px;\" then \n   * its computed css width will be 198px\n   */\n  var BOX_SIZING_PROPERTIES = [\"-webkit-box-sizing\", \"-moz-box-sizing\", \"-ms-box-sizing\", \"box-sizing\"];\n  \n  var shouldIgnoreBoxSizingBorderBox = function(element) {\n    if (hasBoxSizingBorderBox(element)) {\n       return parseInt(dom.getStyle(\"width\").from(element), 10) < element.offsetWidth;\n    }\n    return false;\n  };\n  \n  var hasBoxSizingBorderBox = function(element) {\n    var i       = 0,\n        length  = BOX_SIZING_PROPERTIES.length;\n    for (; i<length; i++) {\n      if (dom.getStyle(BOX_SIZING_PROPERTIES[i]).from(element) === \"border-box\") {\n        return BOX_SIZING_PROPERTIES[i];\n      }\n    }\n  };\n  \n  dom.copyStyles = function(stylesToCopy) {\n    return {\n      from: function(element) {\n        if (shouldIgnoreBoxSizingBorderBox(element)) {\n          stylesToCopy = wysihtml5.lang.array(stylesToCopy).without(BOX_SIZING_PROPERTIES);\n        }\n        \n        var cssText = \"\",\n            length  = stylesToCopy.length,\n            i       = 0,\n            property;\n        for (; i<length; i++) {\n          property = stylesToCopy[i];\n          cssText += property + \":\" + dom.getStyle(property).from(element) + \";\";\n        }\n        \n        return {\n          to: function(element) {\n            dom.setStyles(cssText).on(element);\n            return { andTo: arguments.callee };\n          }\n        };\n      }\n    };\n  };\n})(wysihtml5.dom);/**\n * Event Delegation\n *\n * @example\n *    wysihtml5.dom.delegate(document.body, \"a\", \"click\", function() {\n *      // foo\n *    });\n */\n(function(wysihtml5) {\n  \n  wysihtml5.dom.delegate = function(container, selector, eventName, handler) {\n    return wysihtml5.dom.observe(container, eventName, function(event) {\n      var target    = event.target,\n          match     = wysihtml5.lang.array(container.querySelectorAll(selector));\n      \n      while (target && target !== container) {\n        if (match.contains(target)) {\n          handler.call(target, event);\n          break;\n        }\n        target = target.parentNode;\n      }\n    });\n  };\n  \n})(wysihtml5);/**\n * Returns the given html wrapped in a div element\n *\n * Fixing IE's inability to treat unknown elements (HTML5 section, article, ...) correctly\n * when inserted via innerHTML\n * \n * @param {String} html The html which should be wrapped in a dom element\n * @param {Obejct} [context] Document object of the context the html belongs to\n *\n * @example\n *    wysihtml5.dom.getAsDom(\"<article>foo</article>\");\n */\nwysihtml5.dom.getAsDom = (function() {\n  \n  var _innerHTMLShiv = function(html, context) {\n    var tempElement = context.createElement(\"div\");\n    tempElement.style.display = \"none\";\n    context.body.appendChild(tempElement);\n    // IE throws an exception when trying to insert <frameset></frameset> via innerHTML\n    try { tempElement.innerHTML = html; } catch(e) {}\n    context.body.removeChild(tempElement);\n    return tempElement;\n  };\n  \n  /**\n   * Make sure IE supports HTML5 tags, which is accomplished by simply creating one instance of each element\n   */\n  var _ensureHTML5Compatibility = function(context) {\n    if (context._wysihtml5_supportsHTML5Tags) {\n      return;\n    }\n    for (var i=0, length=HTML5_ELEMENTS.length; i<length; i++) {\n      context.createElement(HTML5_ELEMENTS[i]);\n    }\n    context._wysihtml5_supportsHTML5Tags = true;\n  };\n  \n  \n  /**\n   * List of html5 tags\n   * taken from http://simon.html5.org/html5-elements\n   */\n  var HTML5_ELEMENTS = [\n    \"abbr\", \"article\", \"aside\", \"audio\", \"bdi\", \"canvas\", \"command\", \"datalist\", \"details\", \"figcaption\",\n    \"figure\", \"footer\", \"header\", \"hgroup\", \"keygen\", \"mark\", \"meter\", \"nav\", \"output\", \"progress\",\n    \"rp\", \"rt\", \"ruby\", \"svg\", \"section\", \"source\", \"summary\", \"time\", \"track\", \"video\", \"wbr\"\n  ];\n  \n  return function(html, context) {\n    context = context || document;\n    var tempElement;\n    if (typeof(html) === \"object\" && html.nodeType) {\n      tempElement = context.createElement(\"div\");\n      tempElement.appendChild(html);\n    } else if (wysihtml5.browser.supportsHTML5Tags(context)) {\n      tempElement = context.createElement(\"div\");\n      tempElement.innerHTML = html;\n    } else {\n      _ensureHTML5Compatibility(context);\n      tempElement = _innerHTMLShiv(html, context);\n    }\n    return tempElement;\n  };\n})();/**\n * Walks the dom tree from the given node up until it finds a match\n * Designed for optimal performance.\n *\n * @param {Element} node The from which to check the parent nodes\n * @param {Object} matchingSet Object to match against (possible properties: nodeName, className, classRegExp)\n * @param {Number} [levels] How many parents should the function check up from the current node (defaults to 50)\n * @return {null|Element} Returns the first element that matched the desiredNodeName(s)\n * @example\n *    var listElement = wysihtml5.dom.getParentElement(document.querySelector(\"li\"), { nodeName: [\"MENU\", \"UL\", \"OL\"] });\n *    // ... or ...\n *    var unorderedListElement = wysihtml5.dom.getParentElement(document.querySelector(\"li\"), { nodeName: \"UL\" });\n *    // ... or ...\n *    var coloredElement = wysihtml5.dom.getParentElement(myTextNode, { nodeName: \"SPAN\", className: \"wysiwyg-color-red\", classRegExp: /wysiwyg-color-[a-z]/g });\n */\nwysihtml5.dom.getParentElement = (function() {\n  \n  function _isSameNodeName(nodeName, desiredNodeNames) {\n    if (!desiredNodeNames || !desiredNodeNames.length) {\n      return true;\n    }\n    \n    if (typeof(desiredNodeNames) === \"string\") {\n      return nodeName === desiredNodeNames;\n    } else {\n      return wysihtml5.lang.array(desiredNodeNames).contains(nodeName);\n    }\n  }\n  \n  function _isElement(node) {\n    return node.nodeType === wysihtml5.ELEMENT_NODE;\n  }\n  \n  function _hasClassName(element, className, classRegExp) {\n    var classNames = (element.className || \"\").match(classRegExp) || [];\n    if (!className) {\n      return !!classNames.length;\n    }\n    return classNames[classNames.length - 1] === className;\n  }\n  \n  function _getParentElementWithNodeName(node, nodeName, levels) {\n    while (levels-- && node && node.nodeName !== \"BODY\") {\n      if (_isSameNodeName(node.nodeName, nodeName)) {\n        return node;\n      }\n      node = node.parentNode;\n    }\n    return null;\n  }\n  \n  function _getParentElementWithNodeNameAndClassName(node, nodeName, className, classRegExp, levels) {\n    while (levels-- && node && node.nodeName !== \"BODY\") {\n      if (_isElement(node) &&\n          _isSameNodeName(node.nodeName, nodeName) &&\n          _hasClassName(node, className, classRegExp)) {\n        return node;\n      }\n      node = node.parentNode;\n    }\n    return null;\n  }\n  \n  return function(node, matchingSet, levels) {\n    levels = levels || 50; // Go max 50 nodes upwards from current node\n    if (matchingSet.className || matchingSet.classRegExp) {\n      return _getParentElementWithNodeNameAndClassName(\n        node, matchingSet.nodeName, matchingSet.className, matchingSet.classRegExp, levels\n      );\n    } else {\n      return _getParentElementWithNodeName(\n        node, matchingSet.nodeName, levels\n      );\n    }\n  };\n})();\n/**\n * Get element's style for a specific css property\n *\n * @param {Element} element The element on which to retrieve the style\n * @param {String} property The CSS property to retrieve (\"float\", \"display\", \"text-align\", ...)\n *\n * @example\n *    wysihtml5.dom.getStyle(\"display\").from(document.body);\n *    // => \"block\"\n */\nwysihtml5.dom.getStyle = (function() {\n  var stylePropertyMapping = {\n        \"float\": (\"styleFloat\" in document.createElement(\"div\").style) ? \"styleFloat\" : \"cssFloat\"\n      },\n      REG_EXP_CAMELIZE = /\\-[a-z]/g;\n  \n  function camelize(str) {\n    return str.replace(REG_EXP_CAMELIZE, function(match) {\n      return match.charAt(1).toUpperCase();\n    });\n  }\n  \n  return function(property) {\n    return {\n      from: function(element) {\n        if (element.nodeType !== wysihtml5.ELEMENT_NODE) {\n          return;\n        }\n        \n        var doc               = element.ownerDocument,\n            camelizedProperty = stylePropertyMapping[property] || camelize(property),\n            style             = element.style,\n            currentStyle      = element.currentStyle,\n            styleValue        = style[camelizedProperty];\n        if (styleValue) {\n          return styleValue;\n        }\n        \n        // currentStyle is no standard and only supported by Opera and IE but it has one important advantage over the standard-compliant\n        // window.getComputedStyle, since it returns css property values in their original unit:\n        // If you set an elements width to \"50%\", window.getComputedStyle will give you it's current width in px while currentStyle\n        // gives you the original \"50%\".\n        // Opera supports both, currentStyle and window.getComputedStyle, that's why checking for currentStyle should have higher prio\n        if (currentStyle) {\n          try {\n                return currentStyle[camelizedProperty];\n          } catch(e) {\n            //ie will occasionally fail for unknown reasons. swallowing exception\n          }\n        }\n\n        var win                 = doc.defaultView || doc.parentWindow,\n            needsOverflowReset  = (property === \"height\" || property === \"width\") && element.nodeName === \"TEXTAREA\",\n            originalOverflow,\n            returnValue;\n\n        if (win.getComputedStyle) {\n          // Chrome and Safari both calculate a wrong width and height for textareas when they have scroll bars\n          // therfore we remove and restore the scrollbar and calculate the value in between\n          if (needsOverflowReset) {\n            originalOverflow = style.overflow;\n            style.overflow = \"hidden\";\n          }\n          returnValue = win.getComputedStyle(element, null).getPropertyValue(property);\n          if (needsOverflowReset) {\n            style.overflow = originalOverflow || \"\";\n          }\n          return returnValue;\n        }\n      }\n    };\n  };\n})();/**\n * High performant way to check whether an element with a specific tag name is in the given document\n * Optimized for being heavily executed\n * Unleashes the power of live node lists\n *\n * @param {Object} doc The document object of the context where to check\n * @param {String} tagName Upper cased tag name\n * @example\n *    wysihtml5.dom.hasElementWithTagName(document, \"IMG\");\n */\nwysihtml5.dom.hasElementWithTagName = (function() {\n  var LIVE_CACHE          = {},\n      DOCUMENT_IDENTIFIER = 1;\n  \n  function _getDocumentIdentifier(doc) {\n    return doc._wysihtml5_identifier || (doc._wysihtml5_identifier = DOCUMENT_IDENTIFIER++);\n  }\n  \n  return function(doc, tagName) {\n    var key         = _getDocumentIdentifier(doc) + \":\" + tagName,\n        cacheEntry  = LIVE_CACHE[key];\n    if (!cacheEntry) {\n      cacheEntry = LIVE_CACHE[key] = doc.getElementsByTagName(tagName);\n    }\n    \n    return cacheEntry.length > 0;\n  };\n})();/**\n * High performant way to check whether an element with a specific class name is in the given document\n * Optimized for being heavily executed\n * Unleashes the power of live node lists\n *\n * @param {Object} doc The document object of the context where to check\n * @param {String} tagName Upper cased tag name\n * @example\n *    wysihtml5.dom.hasElementWithClassName(document, \"foobar\");\n */\n(function(wysihtml5) {\n  var LIVE_CACHE          = {},\n      DOCUMENT_IDENTIFIER = 1;\n\n  function _getDocumentIdentifier(doc) {\n    return doc._wysihtml5_identifier || (doc._wysihtml5_identifier = DOCUMENT_IDENTIFIER++);\n  }\n  \n  wysihtml5.dom.hasElementWithClassName = function(doc, className) {\n    // getElementsByClassName is not supported by IE<9\n    // but is sometimes mocked via library code (which then doesn't return live node lists)\n    if (!wysihtml5.browser.supportsNativeGetElementsByClassName()) {\n      return !!doc.querySelector(\".\" + className);\n    }\n\n    var key         = _getDocumentIdentifier(doc) + \":\" + className,\n        cacheEntry  = LIVE_CACHE[key];\n    if (!cacheEntry) {\n      cacheEntry = LIVE_CACHE[key] = doc.getElementsByClassName(className);\n    }\n\n    return cacheEntry.length > 0;\n  };\n})(wysihtml5);\nwysihtml5.dom.insert = function(elementToInsert) {\n  return {\n    after: function(element) {\n      element.parentNode.insertBefore(elementToInsert, element.nextSibling);\n    },\n    \n    before: function(element) {\n      element.parentNode.insertBefore(elementToInsert, element);\n    },\n    \n    into: function(element) {\n      element.appendChild(elementToInsert);\n    }\n  };\n};wysihtml5.dom.insertCSS = function(rules) {\n  rules = rules.join(\"\\n\");\n  \n  return {\n    into: function(doc) {\n      var head         = doc.head || doc.getElementsByTagName(\"head\")[0],\n          styleElement = doc.createElement(\"style\");\n\n      styleElement.type = \"text/css\";\n\n      if (styleElement.styleSheet) {\n        styleElement.styleSheet.cssText = rules;\n      } else {\n        styleElement.appendChild(doc.createTextNode(rules));\n      }\n\n      if (head) {\n        head.appendChild(styleElement);\n      }\n    }\n  };\n};/**\n * Method to set dom events\n *\n * @example\n *    wysihtml5.dom.observe(iframe.contentWindow.document.body, [\"focus\", \"blur\"], function() { ... });\n */\nwysihtml5.dom.observe = function(element, eventNames, handler) {\n  eventNames = typeof(eventNames) === \"string\" ? [eventNames] : eventNames;\n  \n  var handlerWrapper,\n      eventName,\n      i       = 0,\n      length  = eventNames.length;\n  \n  for (; i<length; i++) {\n    eventName = eventNames[i];\n    if (element.addEventListener) {\n      element.addEventListener(eventName, handler, false);\n    } else {\n      handlerWrapper = function(event) {\n        if (!(\"target\" in event)) {\n          event.target = event.srcElement;\n        }\n        event.preventDefault = event.preventDefault || function() {\n          this.returnValue = false;\n        };\n        event.stopPropagation = event.stopPropagation || function() {\n          this.cancelBubble = true;\n        };\n        handler.call(element, event);\n      };\n      element.attachEvent(\"on\" + eventName, handlerWrapper);\n    }\n  }\n  \n  return {\n    stop: function() {\n      var eventName,\n          i       = 0,\n          length  = eventNames.length;\n      for (; i<length; i++) {\n        eventName = eventNames[i];\n        if (element.removeEventListener) {\n          element.removeEventListener(eventName, handler, false);\n        } else {\n          element.detachEvent(\"on\" + eventName, handlerWrapper);\n        }\n      }\n    }\n  };\n};\n/**\n * HTML Sanitizer\n * Rewrites the HTML based on given rules\n *\n * @param {Element|String} elementOrHtml HTML String to be sanitized OR element whose content should be sanitized\n * @param {Object} [rules] List of rules for rewriting the HTML, if there's no rule for an element it will\n *    be converted to a \"span\". Each rule is a key/value pair where key is the tag to convert, and value the\n *    desired substitution.\n * @param {Object} context Document object in which to parse the html, needed to sandbox the parsing\n *\n * @return {Element|String} Depends on the elementOrHtml parameter. When html then the sanitized html as string elsewise the element.\n *\n * @example\n *    var userHTML = '<div id=\"foo\" onclick=\"alert(1);\"><p><font color=\"red\">foo</font><script>alert(1);</script></p></div>';\n *    wysihtml5.dom.parse(userHTML, {\n *      tags {\n *        p:      \"div\",      // Rename p tags to div tags\n *        font:   \"span\"      // Rename font tags to span tags\n *        div:    true,       // Keep them, also possible (same result when passing: \"div\" or true)\n *        script: undefined   // Remove script elements\n *      }\n *    });\n *    // => <div><div><span>foo bar</span></div></div>\n *\n *    var userHTML = '<table><tbody><tr><td>I'm a table!</td></tr></tbody></table>';\n *    wysihtml5.dom.parse(userHTML);\n *    // => '<span><span><span><span>I'm a table!</span></span></span></span>'\n *\n *    var userHTML = '<div>foobar<br>foobar</div>';\n *    wysihtml5.dom.parse(userHTML, {\n *      tags: {\n *        div: undefined,\n *        br:  true\n *      }\n *    });\n *    // => ''\n *\n *    var userHTML = '<div class=\"red\">foo</div><div class=\"pink\">bar</div>';\n *    wysihtml5.dom.parse(userHTML, {\n *      classes: {\n *        red:    1,\n *        green:  1\n *      },\n *      tags: {\n *        div: {\n *          rename_tag:     \"p\"\n *        }\n *      }\n *    });\n *    // => '<p class=\"red\">foo</p><p>bar</p>'\n */\nwysihtml5.dom.parse = (function() {\n  \n  /**\n   * It's not possible to use a XMLParser/DOMParser as HTML5 is not always well-formed XML\n   * new DOMParser().parseFromString('<img src=\"foo.gif\">') will cause a parseError since the\n   * node isn't closed\n   *\n   * Therefore we've to use the browser's ordinary HTML parser invoked by setting innerHTML.\n   */\n  var NODE_TYPE_MAPPING = {\n        \"1\": _handleElement,\n        \"3\": _handleText\n      },\n      // Rename unknown tags to this\n      DEFAULT_NODE_NAME   = \"span\",\n      WHITE_SPACE_REG_EXP = /\\s+/,\n      defaultRules        = { tags: {}, classes: {} },\n      currentRules        = {};\n  \n  /**\n   * Iterates over all childs of the element, recreates them, appends them into a document fragment\n   * which later replaces the entire body content\n   */\n  function parse(elementOrHtml, rules, context, cleanUp) {\n    wysihtml5.lang.object(currentRules).merge(defaultRules).merge(rules).get();\n    \n    context           = context || elementOrHtml.ownerDocument || document;\n    var fragment      = context.createDocumentFragment(),\n        isString      = typeof(elementOrHtml) === \"string\",\n        element,\n        newNode,\n        firstChild;\n    \n    if (isString) {\n      element = wysihtml5.dom.getAsDom(elementOrHtml, context);\n    } else {\n      element = elementOrHtml;\n    }\n    \n    while (element.firstChild) {\n      firstChild  = element.firstChild;\n      element.removeChild(firstChild);\n      newNode = _convert(firstChild, cleanUp);\n      if (newNode) {\n        fragment.appendChild(newNode);\n      }\n    }\n    \n    // Clear element contents\n    element.innerHTML = \"\";\n    \n    // Insert new DOM tree\n    element.appendChild(fragment);\n    \n    return isString ? wysihtml5.quirks.getCorrectInnerHTML(element) : element;\n  }\n  \n  function _convert(oldNode, cleanUp) {\n    var oldNodeType     = oldNode.nodeType,\n        oldChilds       = oldNode.childNodes,\n        oldChildsLength = oldChilds.length,\n        newNode,\n        method          = NODE_TYPE_MAPPING[oldNodeType],\n        i               = 0;\n    \n    newNode = method && method(oldNode);\n    \n    if (!newNode) {\n      return null;\n    }\n    \n    for (i=0; i<oldChildsLength; i++) {\n      newChild = _convert(oldChilds[i], cleanUp);\n      if (newChild) {\n        newNode.appendChild(newChild);\n      }\n    }\n    \n    // Cleanup senseless <span> elements\n    if (cleanUp &&\n        newNode.childNodes.length <= 1 &&\n        newNode.nodeName.toLowerCase() === DEFAULT_NODE_NAME &&\n        !newNode.attributes.length) {\n      return newNode.firstChild;\n    }\n    \n    return newNode;\n  }\n  \n  function _handleElement(oldNode) {\n    var rule,\n        newNode,\n        endTag,\n        tagRules    = currentRules.tags,\n        nodeName    = oldNode.nodeName.toLowerCase(),\n        scopeName   = oldNode.scopeName;\n    \n    /**\n     * We already parsed that element\n     * ignore it! (yes, this sometimes happens in IE8 when the html is invalid)\n     */\n    if (oldNode._wysihtml5) {\n      return null;\n    }\n    oldNode._wysihtml5 = 1;\n    \n    if (oldNode.className === \"wysihtml5-temp\") {\n      return null;\n    }\n    \n    /**\n     * IE is the only browser who doesn't include the namespace in the\n     * nodeName, that's why we have to prepend it by ourselves\n     * scopeName is a proprietary IE feature\n     * read more here http://msdn.microsoft.com/en-us/library/ms534388(v=vs.85).aspx\n     */\n    if (scopeName && scopeName != \"HTML\") {\n      nodeName = scopeName + \":\" + nodeName;\n    }\n    \n    /**\n     * Repair node\n     * IE is a bit bitchy when it comes to invalid nested markup which includes unclosed tags\n     * A <p> doesn't need to be closed according HTML4-5 spec, we simply replace it with a <div> to preserve its content and layout\n     */\n    if (\"outerHTML\" in oldNode) {\n      if (!wysihtml5.browser.autoClosesUnclosedTags() &&\n          oldNode.nodeName === \"P\" &&\n          oldNode.outerHTML.slice(-4).toLowerCase() !== \"</p>\") {\n        nodeName = \"div\";\n      }\n    }\n    \n    if (nodeName in tagRules) {\n      rule = tagRules[nodeName];\n      if (!rule || rule.remove) {\n        return null;\n      }\n      \n      rule = typeof(rule) === \"string\" ? { rename_tag: rule } : rule;\n    } else if (oldNode.firstChild) {\n      rule = { rename_tag: DEFAULT_NODE_NAME };\n    } else {\n      // Remove empty unknown elements\n      return null;\n    }\n    \n    newNode = oldNode.ownerDocument.createElement(rule.rename_tag || nodeName);\n    _handleAttributes(oldNode, newNode, rule);\n    \n    oldNode = null;\n    return newNode;\n  }\n  \n  function _handleAttributes(oldNode, newNode, rule) {\n    var attributes          = {},                         // fresh new set of attributes to set on newNode\n        setClass            = rule.set_class,             // classes to set\n        addClass            = rule.add_class,             // add classes based on existing attributes\n        setAttributes       = rule.set_attributes,        // attributes to set on the current node\n        checkAttributes     = rule.check_attributes,      // check/convert values of attributes\n        allowedClasses      = currentRules.classes,\n        i                   = 0,\n        classes             = [],\n        newClasses          = [],\n        newUniqueClasses    = [],\n        oldClasses          = [],\n        classesLength,\n        newClassesLength,\n        currentClass,\n        newClass,\n        attributeName,\n        newAttributeValue,\n        method;\n    \n    if (setAttributes) {\n      attributes = wysihtml5.lang.object(setAttributes).clone();\n    }\n    \n    if (checkAttributes) {\n      for (attributeName in checkAttributes) {\n        method = attributeCheckMethods[checkAttributes[attributeName]];\n        if (!method) {\n          continue;\n        }\n        newAttributeValue = method(_getAttribute(oldNode, attributeName));\n        if (typeof(newAttributeValue) === \"string\") {\n          attributes[attributeName] = newAttributeValue;\n        }\n      }\n    }\n    \n    if (setClass) {\n      classes.push(setClass);\n    }\n    \n    if (addClass) {\n      for (attributeName in addClass) {\n        method = addClassMethods[addClass[attributeName]];\n        if (!method) {\n          continue;\n        }\n        newClass = method(_getAttribute(oldNode, attributeName));\n        if (typeof(newClass) === \"string\") {\n          classes.push(newClass);\n        }\n      }\n    }\n    \n    // make sure that wysihtml5 temp class doesn't get stripped out\n    allowedClasses[\"_wysihtml5-temp-placeholder\"] = 1;\n    \n    // add old classes last\n    oldClasses = oldNode.getAttribute(\"class\");\n    if (oldClasses) {\n      classes = classes.concat(oldClasses.split(WHITE_SPACE_REG_EXP));\n    }\n    classesLength = classes.length;\n    for (; i<classesLength; i++) {\n      currentClass = classes[i];\n      if (allowedClasses[currentClass]) {\n        newClasses.push(currentClass);\n      }\n    }\n    \n    // remove duplicate entries and preserve class specificity\n    newClassesLength = newClasses.length;\n    while (newClassesLength--) {\n      currentClass = newClasses[newClassesLength];\n      if (!wysihtml5.lang.array(newUniqueClasses).contains(currentClass)) {\n        newUniqueClasses.unshift(currentClass);\n      }\n    }\n    \n    if (newUniqueClasses.length) {\n      attributes[\"class\"] = newUniqueClasses.join(\" \");\n    }\n    \n    // set attributes on newNode\n    for (attributeName in attributes) {\n      // Setting attributes can cause a js error in IE under certain circumstances\n      // eg. on a <img> under https when it's new attribute value is non-https\n      // TODO: Investigate this further and check for smarter handling\n      try {\n        newNode.setAttribute(attributeName, attributes[attributeName]);\n      } catch(e) {}\n    }\n    \n    // IE8 sometimes loses the width/height attributes when those are set before the \"src\"\n    // so we make sure to set them again\n    if (attributes.src) {\n      if (typeof(attributes.width) !== \"undefined\") {\n        newNode.setAttribute(\"width\", attributes.width);\n      }\n      if (typeof(attributes.height) !== \"undefined\") {\n        newNode.setAttribute(\"height\", attributes.height);\n      }\n    }\n  }\n  \n  /**\n   * IE gives wrong results for hasAttribute/getAttribute, for example:\n   *    var td = document.createElement(\"td\");\n   *    td.getAttribute(\"rowspan\"); // => \"1\" in IE\n   *\n   * Therefore we have to check the element's outerHTML for the attribute\n   */\n  var HAS_GET_ATTRIBUTE_BUG = !wysihtml5.browser.supportsGetAttributeCorrectly();\n  function _getAttribute(node, attributeName) {\n    attributeName = attributeName.toLowerCase();\n    var nodeName = node.nodeName;\n    if (nodeName == \"IMG\" && attributeName == \"src\" && _isLoadedImage(node) === true) {\n      // Get 'src' attribute value via object property since this will always contain the\n      // full absolute url (http://...)\n      // this fixes a very annoying bug in firefox (ver 3.6 & 4) and IE 8 where images copied from the same host\n      // will have relative paths, which the sanitizer strips out (see attributeCheckMethods.url)\n      return node.src;\n    } else if (HAS_GET_ATTRIBUTE_BUG && \"outerHTML\" in node) {\n      // Don't trust getAttribute/hasAttribute in IE 6-8, instead check the element's outerHTML\n      var outerHTML      = node.outerHTML.toLowerCase(),\n          // TODO: This might not work for attributes without value: <input disabled>\n          hasAttribute   = outerHTML.indexOf(\" \" + attributeName +  \"=\") != -1;\n      \n      return hasAttribute ? node.getAttribute(attributeName) : null;\n    } else{\n      return node.getAttribute(attributeName);\n    }\n  }\n  \n  /**\n   * Check whether the given node is a proper loaded image\n   * FIXME: Returns undefined when unknown (Chrome, Safari)\n   */\n  function _isLoadedImage(node) {\n    try {\n      return node.complete && !node.mozMatchesSelector(\":-moz-broken\");\n    } catch(e) {\n      if (node.complete && node.readyState === \"complete\") {\n        return true;\n      }\n    }\n  }\n  \n  function _handleText(oldNode) {\n    return oldNode.ownerDocument.createTextNode(oldNode.data);\n  }\n  \n  \n  // ------------ attribute checks ------------ \\\\\n  var attributeCheckMethods = {\n    url: (function() {\n      var REG_EXP = /^https?:\\/\\//i;\n      return function(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 REG_EXP = /[^ 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.TEXT_NODE && childNode.data === \"\") {\n      childNode.parentNode.removeChild(childNode);\n    }\n  }\n};\n/**\n * Renames an element (eg. a <div> to a <p>) 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 *    <!-- Assume the following dom: -->\n *    <ul id=\"list\">\n *      <li>eminem</li>\n *      <li>dr. dre</li>\n *      <li>50 Cent</li>\n *    </ul>\n *\n *    <script>\n *      wysihtml5.dom.renameElement(document.getElementById(\"list\"), \"ol\");\n *    </script>\n *\n *    <!-- Will result in: -->\n *    <ol>\n *      <li>eminem</li>\n *      <li>dr. dre</li>\n *      <li>50 Cent</li>\n *    </ol>\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 *      <span>hello</span>\n *    </div>\n *    <script>\n *      // Remove #foo and replace with it's children\n *      wysihtml5.dom.replaceWithChildNodes(document.getElementById(\"foo\"));\n *    </script>\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 *    <!-- Assume the following dom: -->\n *    <ul id=\"list\">\n *      <li>eminem</li>\n *      <li>dr. dre</li>\n *      <li>50 Cent</li>\n *    </ul>\n *\n *    <script>\n *      wysihtml5.dom.resolveList(document.getElementById(\"list\"));\n *    </script>\n *\n *    <!-- Will result in: -->\n *    eminem<br>\n *    dr. dre<br>\n *    50 Cent<br>\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:'<html>...</html>'\")\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:'<html></html>'\";\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><html><head>'\n        + '<meta charset=\"#{charset}\">#{stylesheets}</head>'\n        + '<body></body></html>'\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 <a> into a contentEditable, IE thinks, it has to insert <u> 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 == \"<p>&nbsp;</p>\" ||\n            innerHTML == \"<p>&nbsp;</p><p>&nbsp;</p>\") {\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 (<ul><li>|</li></ul>) 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 has no method 'replace'
W20150401-15:27:19.902(3)? (STDERR)     at ServerResponse.http.OutgoingMessage.write (packages/meteorhacks:inject-data/lib/server.js:48:1)
W20150401-15:27:19.903(3)? (STDERR)     at ServerResponse.res.write (/Users/mike/.meteor/packages/webapp/.1.2.0.awacga++os+web.browser+web.cordova/npm/node_modules/connect/lib/middleware/compress.js:110:17)
W20150401-15:27:19.903(3)? (STDERR)     at write (_stream_readable.js:602:24)
W20150401-15:27:19.903(3)? (STDERR)     at flow (_stream_readable.js:611:7)
W20150401-15:27:19.903(3)? (STDERR)     at ReadStream.pipeOnReadable (_stream_readable.js:643:5)
W20150401-15:27:19.903(3)? (STDERR)     at ReadStream.emit (events.js:92:17)
W20150401-15:27:19.903(3)? (STDERR)     at emitReadable_ (_stream_readable.js:427:10)
W20150401-15:27:19.903(3)? (STDERR)     at emitReadable (_stream_readable.js:423:5)
W20150401-15:27:19.903(3)? (STDERR)     at readableAddChunk (_stream_readable.js:166:9)
W20150401-15:27:19.903(3)? (STDERR)     at ReadStream.Readable.push (_stream_readable.js:128:10)
arunoda commented 9 years ago

Okay. I'll have a look at this.

arunoda commented 9 years ago

BTW: Is this with Fast Render or directly using this.

michaelrokosh commented 9 years ago

@arunoda this is with Fast Render.

arunoda commented 9 years ago

I fixed this issues with 4af34bf7c44c6436ae319b9db0047a9b82fc9c7e try to update FR.

arunoda commented 9 years ago

Hope this is fixed.