vendor/assets/javascripts/wysihtml5x.js in wysihtml5x-rails-0.4.8 vs vendor/assets/javascripts/wysihtml5x.js in wysihtml5x-rails-0.4.9

- old
+ new

@@ -23,22 +23,22 @@ if(!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; };/** - * @license wysihtml5x v0.4.8 + * @license wysihtml5x v0.4.9 * https://github.com/Edicy/wysihtml5 * * Author: Christopher Blum (https://github.com/tiff) * Secondary author of extended features: Oliver Pulges (https://github.com/pulges) * * Copyright (C) 2012 XING AG * Licensed under the MIT license (MIT) * */ var wysihtml5 = { - version: "0.4.8", + version: "0.4.9", // namespaces commands: {}, dom: {}, quirks: {}, @@ -5811,14 +5811,19 @@ wysihtml5.lang.object(currentRules).merge(defaultRules).merge(config.rules).get(); var context = config.context || elementOrHtml.ownerDocument || document, fragment = context.createDocumentFragment(), isString = typeof(elementOrHtml) === "string", + clearInternals = false, element, newNode, firstChild; + if (config.clearInternals === true) { + clearInternals = true; + } + if (config.uneditableClass) { uneditableClass = config.uneditableClass; } if (isString) { @@ -5827,15 +5832,17 @@ element = elementOrHtml; } while (element.firstChild) { firstChild = element.firstChild; - newNode = _convert(firstChild, config.cleanUp); - element.removeChild(firstChild); + newNode = _convert(firstChild, config.cleanUp, clearInternals); if (newNode) { fragment.appendChild(newNode); } + if (firstChild !== newNode) { + element.removeChild(firstChild); + } } // Clear element contents element.innerHTML = ""; @@ -5843,35 +5850,42 @@ element.appendChild(fragment); return isString ? wysihtml5.quirks.getCorrectInnerHTML(element) : element; } - function _convert(oldNode, cleanUp) { + function _convert(oldNode, cleanUp, clearInternals) { var oldNodeType = oldNode.nodeType, oldChilds = oldNode.childNodes, oldChildsLength = oldChilds.length, method = NODE_TYPE_MAPPING[oldNodeType], i = 0, fragment, newNode, newChild; + // Passes directly elemets with uneditable class if (uneditableClass && oldNodeType === 1 && wysihtml5.dom.hasClass(oldNode, uneditableClass)) { return oldNode; } - newNode = method && method(oldNode); + newNode = method && method(oldNode, clearInternals); + // Remove or unwrap node in case of return value null or false if (!newNode) { if (newNode === false) { // false defines that tag should be removed but contents should remain (unwrap) fragment = oldNode.ownerDocument.createDocumentFragment(); for (i = oldChildsLength; i--;) { - newChild = _convert(oldChilds[i], cleanUp); - if (newChild) { - fragment.insertBefore(newChild, fragment.firstChild); + if (oldChilds[i]) { + newChild = _convert(oldChilds[i], cleanUp, clearInternals); + if (newChild) { + if (oldChilds[i] === newChild) { + i--; + } + fragment.insertBefore(newChild, fragment.firstChild); + } } } // TODO: try to minimize surplus spaces if (wysihtml5.lang.array([ @@ -5891,26 +5905,33 @@ if (fragment.normalize) { fragment.normalize(); } return fragment; } else { - return null; + // Remove + return null; } } + // Converts all childnodes for (i=0; i<oldChildsLength; i++) { - newChild = _convert(oldChilds[i], cleanUp); - if (newChild) { - newNode.appendChild(newChild); + if (oldChilds[i]) { + newChild = _convert(oldChilds[i], cleanUp, clearInternals); + if (newChild) { + if (oldChilds[i] === newChild) { + i--; + } + newNode.appendChild(newChild); + } } } // Cleanup senseless <span> elements if (cleanUp && newNode.nodeName.toLowerCase() === DEFAULT_NODE_NAME && (!newNode.childNodes.length || - ((/^\s*$/gi).test(newNode.innerHTML) && oldNode.className !== "_wysihtml5-temp-placeholder" && oldNode.className !== "rangySelectionBoundary") || + ((/^\s*$/gi).test(newNode.innerHTML) && (clearInternals || (oldNode.className !== "_wysihtml5-temp-placeholder" && oldNode.className !== "rangySelectionBoundary"))) || !newNode.attributes.length) ) { fragment = newNode.ownerDocument.createDocumentFragment(); while (newNode.firstChild) { fragment.appendChild(newNode.firstChild); @@ -5925,11 +5946,11 @@ newNode.normalize(); } return newNode; } - function _handleElement(oldNode) { + function _handleElement(oldNode, clearInternals) { var rule, newNode, tagRules = currentRules.tags, nodeName = oldNode.nodeName.toLowerCase(), scopeName = oldNode.scopeName; @@ -5983,28 +6004,28 @@ // Remove empty unknown elements return null; } newNode = oldNode.ownerDocument.createElement(rule.rename_tag || nodeName); - _handleAttributes(oldNode, newNode, rule); + _handleAttributes(oldNode, newNode, rule, clearInternals); _handleStyles(oldNode, newNode, rule); // tests if type condition is met or node should be removed/unwrapped - if (rule.one_of_type && !_testTypes(oldNode, currentRules, rule.one_of_type)) { + if (rule.one_of_type && !_testTypes(oldNode, currentRules, rule.one_of_type, clearInternals)) { return (rule.remove_action && rule.remove_action == "unwrap") ? false : null; } oldNode = null; if (newNode.normalize) { newNode.normalize(); } return newNode; } - function _testTypes(oldNode, rules, types) { + function _testTypes(oldNode, rules, types, clearInternals) { var definition, type; // do not interfere with placeholder span or pasting caret position is not maintained - if (oldNode.nodeName === "SPAN" && (oldNode.className === "_wysihtml5-temp-placeholder" || oldNode.className === "rangySelectionBoundary")) { + if (oldNode.nodeName === "SPAN" && !clearInternals && (oldNode.className === "_wysihtml5-temp-placeholder" || oldNode.className === "rangySelectionBoundary")) { return true; } for (type in types) { if (types.hasOwnProperty(type) && rules.type_definitions && rules.type_definitions[type]) { @@ -6110,11 +6131,12 @@ } } } } - function _handleAttributes(oldNode, newNode, rule) { + // TODO: refactor. Too long to read + function _handleAttributes(oldNode, newNode, rule, clearInternals) { var attributes = {}, // fresh new set of attributes to set on newNode setClass = rule.set_class, // classes to set addClass = rule.add_class, // add classes based on existing attributes addStyle = rule.add_style, // add styles based on existing attributes setAttributes = rule.set_attributes, // attributes to set on the current node @@ -6187,12 +6209,15 @@ if (typeof(allowedClasses) === "string" && allowedClasses === "any" && oldNode.getAttribute("class")) { attributes["class"] = oldNode.getAttribute("class"); } else { // make sure that wysihtml5 temp class doesn't get stripped out - allowedClasses["_wysihtml5-temp-placeholder"] = 1; - allowedClasses["_rangySelectionBoundary"] = 1; + if (!clearInternals) { + allowedClasses["_wysihtml5-temp-placeholder"] = 1; + allowedClasses["_rangySelectionBoundary"] = 1; + allowedClasses["wysiwyg-tmp-selected-cell"] = 1; + } // add old classes last oldClasses = oldNode.getAttribute("class"); if (oldClasses) { classes = classes.concat(oldClasses.split(WHITE_SPACE_REG_EXP)); @@ -6208,10 +6233,18 @@ if (newClasses.length) { attributes["class"] = wysihtml5.lang.array(newClasses).unique().join(" "); } } + // remove table selection class if present + if (attributes["class"] && clearInternals) { + attributes["class"] = attributes["class"].replace("wysiwyg-tmp-selected-cell", ""); + if ((/^\s*$/g).test(attributes["class"])) { + delete attributes.class; + } + } + if (styles.length) { attributes["style"] = wysihtml5.lang.array(styles).unique().join(" "); } // set attributes on newNode @@ -10825,11 +10858,11 @@ state: function(composer, command) { return wysihtml5.commands.insertList.state(composer, command, "UL"); } }; -;wysihtml5.commands.insertList = (function() { +;wysihtml5.commands.insertList = (function(wysihtml5) { var isNode = function(node, name) { if (node && node.nodeName) { if (typeof name === 'string') { name = [name]; @@ -10983,11 +11016,11 @@ return (list.el && !list.other) ? list.el : false; } }; -})();;wysihtml5.commands.italic = { +})(wysihtml5);;wysihtml5.commands.italic = { exec: function(composer, command) { wysihtml5.commands.formatInline.execWithToggle(composer, command, "i"); }, state: function(composer, command) { @@ -11449,11 +11482,11 @@ }); }, transact: function() { var previousHtml = this.historyStr[this.position - 1], - currentHtml = this.composer.getValue(); + currentHtml = this.composer.getValue(false, false); if (currentHtml === previousHtml) { return; } @@ -11652,15 +11685,14 @@ clear: function() { this.element.innerHTML = browser.displaysCaretInEmptyContentEditableCorrectly() ? "" : this.CARET_HACK; }, - getValue: function(parse) { + getValue: function(parse, clearInternals) { var value = this.isEmpty() ? "" : wysihtml5.quirks.getCorrectInnerHTML(this.element); - - if (parse) { - value = this.parent.parse(value); + if (parse !== false) { + value = this.parent.parse(value, (clearInternals === false) ? false : true); } return value; }, @@ -11793,11 +11825,11 @@ var that = this; this.doc = this.sandbox.getDocument(); this.element = (this.config.contentEditableMode) ? this.sandbox.getContentEditable() : this.doc.body; if (!this.config.noTextarea) { this.textarea = this.parent.textarea; - this.element.innerHTML = this.textarea.getValue(true); + this.element.innerHTML = this.textarea.getValue(true, false); } else { this.cleanUp(); // cleans contenteditable on initiation as it may contain html } // Make sure our selection handler is ready @@ -12372,11 +12404,11 @@ composer.commands.exec("insertHTML", "&emsp;"); }; wysihtml5.views.Composer.prototype.observe = function() { var that = this, - state = this.getValue(), + state = this.getValue(false, false), container = (this.sandbox.getIframe) ? this.sandbox.getIframe() : this.sandbox.getContentEditable(), element = this.element, focusBlurElement = (browser.supportsEventsInIframeCorrectly() || this.sandbox.getContentEditable) ? element : this.sandbox.getWindow(), pasteEvents = ["drop", "paste"], interactionEvents = ["drop", "paste", "mouseup", "focus", "keyup"]; @@ -12420,15 +12452,15 @@ dom.observe(focusBlurElement, "focus", function() { that.parent.fire("focus").fire("focus:composer"); // Delay storing of state until all focus handler are fired // especially the one which resets the placeholder - setTimeout(function() { state = that.getValue(); }, 0); + setTimeout(function() { state = that.getValue(false, false); }, 0); }); dom.observe(focusBlurElement, "blur", function() { - if (state !== that.getValue()) { + if (state !== that.getValue(false, false)) { that.parent.fire("change").fire("change:composer"); } that.parent.fire("blur").fire("blur:composer"); }); @@ -12601,20 +12633,20 @@ * Sync html from composer to textarea * Takes care of placeholders * @param {Boolean} shouldParseHtml Whether the html should be sanitized before inserting it into the textarea */ fromComposerToTextarea: function(shouldParseHtml) { - this.textarea.setValue(wysihtml5.lang.string(this.composer.getValue()).trim(), shouldParseHtml); + this.textarea.setValue(wysihtml5.lang.string(this.composer.getValue(false, false)).trim(), shouldParseHtml); }, /** * Sync value of textarea to composer * Takes care of placeholders * @param {Boolean} shouldParseHtml Whether the html should be sanitized before inserting it into the composer */ fromTextareaToComposer: function(shouldParseHtml) { - var textareaValue = this.textarea.getValue(); + var textareaValue = this.textarea.getValue(false, false); if (textareaValue) { this.composer.setValue(textareaValue, shouldParseHtml); } else { this.composer.clear(); this.editor.fire("set_placeholder"); @@ -12691,11 +12723,11 @@ this.element.value = ""; }, getValue: function(parse) { var value = this.isEmpty() ? "" : this.element.value; - if (parse) { + if (parse !== false) { value = this.parent.parse(value); } return value; }, @@ -12876,12 +12908,12 @@ clear: function() { this.currentView.clear(); return this; }, - getValue: function(parse) { - return this.currentView.getValue(parse); + getValue: function(parse, clearInternals) { + return this.currentView.getValue(parse, clearInternals); }, setValue: function(html, parse) { this.fire("unset_placeholder"); @@ -12924,16 +12956,17 @@ hasPlaceholderSet: function() { return this.currentView.hasPlaceholderSet(); }, - parse: function(htmlOrElement) { - var parseContext = (this.config.contentEditableMode) ? document : this.composer.sandbox.getDocument(); + parse: function(htmlOrElement, clearInternals) { + var parseContext = (this.config.contentEditableMode) ? document : ((this.composer) ? this.composer.sandbox.getDocument() : null); var returnValue = this.config.parser(htmlOrElement, { "rules": this.config.parserRules, "cleanUp": this.config.cleanUp, "context": parseContext, - "uneditableClass": this.config.uneditableContainerClassname + "uneditableClass": this.config.uneditableContainerClassname, + "clearInternals" : clearInternals }); if (typeof(htmlOrElement) === "object") { wysihtml5.quirks.redraw(htmlOrElement); } return returnValue;