Skip to content
This repository has been archived by the owner on Mar 8, 2019. It is now read-only.

Whitelist for classes can be overriden to allow all classes through with * option #341

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion parser_rules/advanced.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var wysihtml5ParserRules = {
/**
* CSS Class white-list
* Following CSS classes won't be removed when parsed by the wysihtml5 HTML parser
"classes": { "*":1 } will allow all classes to be carried over, otheriwse only those whitelisted

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

otherwise

*/
"classes": {
"wysiwyg-clear-both": 1,
Expand Down Expand Up @@ -85,7 +86,7 @@ var wysihtml5ParserRules = {
* - clear_br: converts clear attribute values left/right/all/both to their corresponding css class "wysiwyg-clear-*"
* <br clear="all"> ... becomes ... <br class="wysiwyg-clear-both">
* - align_img: converts align attribute values (right/left) on <img> to their corresponding css class "wysiwyg-float-*"
*
*
* - remove: removes the element and its content
*
* - rename_tag: renames the element to the given tag
Expand Down
96 changes: 48 additions & 48 deletions src/dom/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
* // => '<p class="red">foo</p><p>bar</p>'
*/
wysihtml5.dom.parse = (function() {

/**
* It's not possible to use a XMLParser/DOMParser as HTML5 is not always well-formed XML
* new DOMParser().parseFromString('<img src="foo.gif">') will cause a parseError since the
Expand All @@ -67,27 +67,27 @@ wysihtml5.dom.parse = (function() {
WHITE_SPACE_REG_EXP = /\s+/,
defaultRules = { tags: {}, classes: {} },
currentRules = {};

/**
* Iterates over all childs of the element, recreates them, appends them into a document fragment
* which later replaces the entire body content
*/
function parse(elementOrHtml, rules, context, cleanUp) {
wysihtml5.lang.object(currentRules).merge(defaultRules).merge(rules).get();

context = context || elementOrHtml.ownerDocument || document;
var fragment = context.createDocumentFragment(),
isString = typeof(elementOrHtml) === "string",
element,
newNode,
firstChild;

if (isString) {
element = wysihtml5.dom.getAsDom(elementOrHtml, context);
} else {
element = elementOrHtml;
}

while (element.firstChild) {
firstChild = element.firstChild;
element.removeChild(firstChild);
Expand All @@ -96,16 +96,16 @@ wysihtml5.dom.parse = (function() {
fragment.appendChild(newNode);
}
}

// Clear element contents
element.innerHTML = "";

// Insert new DOM tree
element.appendChild(fragment);

return isString ? wysihtml5.quirks.getCorrectInnerHTML(element) : element;
}

function _convert(oldNode, cleanUp) {
var oldNodeType = oldNode.nodeType,
oldChilds = oldNode.childNodes,
Expand All @@ -114,39 +114,39 @@ wysihtml5.dom.parse = (function() {
i = 0,
newNode,
newChild;

newNode = method && method(oldNode);

if (!newNode) {
return null;
}

for (i=0; i<oldChildsLength; i++) {
newChild = _convert(oldChilds[i], cleanUp);
if (newChild) {
newNode.appendChild(newChild);
}
}

// Cleanup senseless <span> elements
if (cleanUp &&
newNode.childNodes.length <= 1 &&
newNode.nodeName.toLowerCase() === DEFAULT_NODE_NAME &&
!newNode.attributes.length) {
return newNode.firstChild;
}

return newNode;
}

function _handleElement(oldNode) {
var rule,
newNode,
endTag,
tagRules = currentRules.tags,
nodeName = oldNode.nodeName.toLowerCase(),
scopeName = oldNode.scopeName;

/**
* We already parsed that element
* ignore it! (yes, this sometimes happens in IE8 when the html is invalid)
Expand All @@ -155,11 +155,11 @@ wysihtml5.dom.parse = (function() {
return null;
}
oldNode._wysihtml5 = 1;

if (oldNode.className === "wysihtml5-temp") {
return null;
}

/**
* IE is the only browser who doesn't include the namespace in the
* nodeName, that's why we have to prepend it by ourselves
Expand All @@ -169,7 +169,7 @@ wysihtml5.dom.parse = (function() {
if (scopeName && scopeName != "HTML") {
nodeName = scopeName + ":" + nodeName;
}

/**
* Repair node
* IE is a bit bitchy when it comes to invalid nested markup which includes unclosed tags
Expand All @@ -182,28 +182,28 @@ wysihtml5.dom.parse = (function() {
nodeName = "div";
}
}

if (nodeName in tagRules) {
rule = tagRules[nodeName];
if (!rule || rule.remove) {
return null;
}

rule = typeof(rule) === "string" ? { rename_tag: rule } : rule;
} else if (oldNode.firstChild) {
rule = { rename_tag: DEFAULT_NODE_NAME };
} else {
// Remove empty unknown elements
return null;
}

newNode = oldNode.ownerDocument.createElement(rule.rename_tag || nodeName);
_handleAttributes(oldNode, newNode, rule);

oldNode = null;
return newNode;
}

function _handleAttributes(oldNode, newNode, rule) {
var attributes = {}, // fresh new set of attributes to set on newNode
setClass = rule.set_class, // classes to set
Expand All @@ -223,11 +223,11 @@ wysihtml5.dom.parse = (function() {
attributeName,
newAttributeValue,
method;

if (setAttributes) {
attributes = wysihtml5.lang.object(setAttributes).clone();
}

if (checkAttributes) {
for (attributeName in checkAttributes) {
method = attributeCheckMethods[checkAttributes[attributeName]];
Expand All @@ -240,11 +240,11 @@ wysihtml5.dom.parse = (function() {
}
}
}

if (setClass) {
classes.push(setClass);
}

if (addClass) {
for (attributeName in addClass) {
method = addClassMethods[addClass[attributeName]];
Expand All @@ -257,10 +257,10 @@ wysihtml5.dom.parse = (function() {
}
}
}

// make sure that wysihtml5 temp class doesn't get stripped out
allowedClasses["_wysihtml5-temp-placeholder"] = 1;

// add old classes last
oldClasses = oldNode.getAttribute("class");
if (oldClasses) {
Expand All @@ -269,11 +269,11 @@ wysihtml5.dom.parse = (function() {
classesLength = classes.length;
for (; i<classesLength; i++) {
currentClass = classes[i];
if (allowedClasses[currentClass]) {
if (allowedClasses['*'] || allowedClasses[currentClass]) {
newClasses.push(currentClass);
}
}

// remove duplicate entries and preserve class specificity
newClassesLength = newClasses.length;
while (newClassesLength--) {
Expand All @@ -282,11 +282,11 @@ wysihtml5.dom.parse = (function() {
newUniqueClasses.unshift(currentClass);
}
}

if (newUniqueClasses.length) {
attributes["class"] = newUniqueClasses.join(" ");
}

// set attributes on newNode
for (attributeName in attributes) {
// Setting attributes can cause a js error in IE under certain circumstances
Expand All @@ -296,7 +296,7 @@ wysihtml5.dom.parse = (function() {
newNode.setAttribute(attributeName, attributes[attributeName]);
} catch(e) {}
}

// IE8 sometimes loses the width/height attributes when those are set before the "src"
// so we make sure to set them again
if (attributes.src) {
Expand All @@ -308,7 +308,7 @@ wysihtml5.dom.parse = (function() {
}
}
}

/**
* IE gives wrong results for hasAttribute/getAttribute, for example:
* var td = document.createElement("td");
Expand All @@ -331,13 +331,13 @@ wysihtml5.dom.parse = (function() {
var outerHTML = node.outerHTML.toLowerCase(),
// TODO: This might not work for attributes without value: <input disabled>
hasAttribute = outerHTML.indexOf(" " + attributeName + "=") != -1;

return hasAttribute ? node.getAttribute(attributeName) : null;
} else{
return node.getAttribute(attributeName);
}
}

/**
* Check whether the given node is a proper loaded image
* FIXME: Returns undefined when unknown (Chrome, Safari)
Expand All @@ -351,12 +351,12 @@ wysihtml5.dom.parse = (function() {
}
}
}

function _handleText(oldNode) {
return oldNode.ownerDocument.createTextNode(oldNode.data);
}


// ------------ attribute checks ------------ \\
var attributeCheckMethods = {
url: (function() {
Expand Down Expand Up @@ -394,7 +394,7 @@ wysihtml5.dom.parse = (function() {
});
};
})(),

alt: (function() {
var REG_EXP = /[^ a-z0-9_\-]/gi;
return function(attributeValue) {
Expand All @@ -404,7 +404,7 @@ wysihtml5.dom.parse = (function() {
return attributeValue.replace(REG_EXP, "");
};
})(),

numbers: (function() {
var REG_EXP = /\D/g;
return function(attributeValue) {
Expand All @@ -413,7 +413,7 @@ wysihtml5.dom.parse = (function() {
};
})()
};

// ------------ class converter (converts an html attribute to a class name) ------------ \\
var addClassMethods = {
align_img: (function() {
Expand All @@ -425,7 +425,7 @@ wysihtml5.dom.parse = (function() {
return mapping[String(attributeValue).toLowerCase()];
};
})(),

align_text: (function() {
var mapping = {
left: "wysiwyg-text-align-left",
Expand All @@ -437,7 +437,7 @@ wysihtml5.dom.parse = (function() {
return mapping[String(attributeValue).toLowerCase()];
};
})(),

clear_br: (function() {
var mapping = {
left: "wysiwyg-clear-left",
Expand All @@ -449,7 +449,7 @@ wysihtml5.dom.parse = (function() {
return mapping[String(attributeValue).toLowerCase()];
};
})(),

size_font: (function() {
var mapping = {
"1": "wysiwyg-font-size-xx-small",
Expand All @@ -467,6 +467,6 @@ wysihtml5.dom.parse = (function() {
};
})()
};

return parse;
})();