Skip to content

Commit

Permalink
Fix #57
Browse files Browse the repository at this point in the history
Default getValue parsing change noted in #25
Makes getValue parsing from public api stronger (internals removed by default)
  • Loading branch information
Oliver Pulges committed Jun 17, 2014
1 parent a45bcf0 commit 094f2ba
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 49 deletions.
51 changes: 36 additions & 15 deletions src/dom/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,15 @@ wysihtml5.dom.parse = (function() {
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;
}
Expand All @@ -96,7 +101,7 @@ wysihtml5.dom.parse = (function() {

while (element.firstChild) {
firstChild = element.firstChild;
newNode = _convert(firstChild, config.cleanUp);
newNode = _convert(firstChild, config.cleanUp, clearInternals);
if (newNode) {
fragment.appendChild(newNode);
}
Expand All @@ -114,7 +119,7 @@ wysihtml5.dom.parse = (function() {
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,
Expand All @@ -124,20 +129,22 @@ wysihtml5.dom.parse = (function() {
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--;) {
if (oldChilds[i]) {
newChild = _convert(oldChilds[i], cleanUp);
newChild = _convert(oldChilds[i], cleanUp, clearInternals);
if (newChild) {
if (oldChilds[i] === newChild) {
i--;
Expand Down Expand Up @@ -167,13 +174,15 @@ wysihtml5.dom.parse = (function() {
}
return fragment;
} else {
return null;
// Remove
return null;
}
}

// Converts all childnodes
for (i=0; i<oldChildsLength; i++) {
if (oldChilds[i]) {
newChild = _convert(oldChilds[i], cleanUp);
newChild = _convert(oldChilds[i], cleanUp, clearInternals);
if (newChild) {
if (oldChilds[i] === newChild) {
i--;
Expand All @@ -187,7 +196,7 @@ wysihtml5.dom.parse = (function() {
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();
Expand All @@ -206,7 +215,7 @@ wysihtml5.dom.parse = (function() {
return newNode;
}

function _handleElement(oldNode) {
function _handleElement(oldNode, clearInternals) {
var rule,
newNode,
tagRules = currentRules.tags,
Expand Down Expand Up @@ -264,10 +273,10 @@ wysihtml5.dom.parse = (function() {
}

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;
}

Expand All @@ -277,11 +286,11 @@ wysihtml5.dom.parse = (function() {
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;
}

Expand Down Expand Up @@ -391,7 +400,8 @@ wysihtml5.dom.parse = (function() {
}
}

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
Expand Down Expand Up @@ -468,8 +478,11 @@ wysihtml5.dom.parse = (function() {
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");
Expand All @@ -489,6 +502,14 @@ wysihtml5.dom.parse = (function() {
}
}

// 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(" ");
}
Expand Down
11 changes: 6 additions & 5 deletions src/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@
return this;
},

getValue: function(parse) {
return this.currentView.getValue(parse);
getValue: function(parse, clearInternals) {
return this.currentView.getValue(parse, clearInternals);
},

setValue: function(html, parse) {
Expand Down Expand Up @@ -176,13 +176,14 @@
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);
Expand Down
2 changes: 1 addition & 1 deletion src/undo_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@

transact: function() {
var previousHtml = this.historyStr[this.position - 1],
currentHtml = this.composer.getValue();
currentHtml = this.composer.getValue(false, false);

if (currentHtml === previousHtml) {
return;
Expand Down
9 changes: 4 additions & 5 deletions src/views/composer.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,10 @@
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;
Expand Down Expand Up @@ -168,7 +167,7 @@
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
}
Expand Down
6 changes: 3 additions & 3 deletions src/views/composer.observe.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@

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(),
Expand Down Expand Up @@ -135,11 +135,11 @@

// 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");
Expand Down
4 changes: 2 additions & 2 deletions src/views/synchronizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* @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);
},

/**
Expand All @@ -30,7 +30,7 @@
* @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 {
Expand Down
2 changes: 1 addition & 1 deletion src/views/textarea.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(

getValue: function(parse) {
var value = this.isEmpty() ? "" : this.element.value;
if (parse) {
if (parse !== false) {
value = this.parent.parse(value);
}
return value;
Expand Down
8 changes: 4 additions & 4 deletions test/editor_contenteditablemode_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ if (wysihtml5.browser.supported()) {
equal(composerElement.innerHTML.toLowerCase(), html, "Editor content correctly set after calling 'setValue'");
ok(!editor.isEmpty(), "'isEmpty' returns correct value when the composer element isn't actually empty");

var value = editor.getValue();
equal(value.toLowerCase(), html, "Editor content correctly returned after calling 'getValue'");
var value = editor.getValue(false, false);
equal(value.toLowerCase(), html, "Editor content correctly returned after calling 'getValue(false, false)'");

editor.clear();
value = editor.getValue();
Expand Down Expand Up @@ -224,7 +224,7 @@ if (wysihtml5.browser.supported()) {
equal(editor.config.parserRules, parserRules, "Parser rules correctly set on config object");
// Invoke parsing via second parameter of setValue()
editor.setValue(input, true);
equal(editor.getValue().toLowerCase(), output, "HTML got correctly parsed within setValue()");
equal(editor.getValue(false, false).toLowerCase(), output, "HTML got correctly parsed within setValue()");
start();
});
});
Expand Down Expand Up @@ -283,7 +283,7 @@ if (wysihtml5.browser.supported()) {

// Invoke parsing via second parameter of setValue()
editor.setValue(input, true);
equal(editor.getValue().toLowerCase(), output, "HTML got correctly parsed within setValue()");
equal(editor.getValue(false, false).toLowerCase(), output, "HTML got correctly parsed within setValue()");
start();
});
});
Expand Down
9 changes: 4 additions & 5 deletions test/editor_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,8 @@ if (wysihtml5.browser.supported()) {
equal(composerElement.innerHTML.toLowerCase(), html, "Editor content correctly set after calling 'setValue'");
ok(!editor.isEmpty(), "'isEmpty' returns correct value when the composer element isn't actually empty");

var value = editor.getValue();
equal(value.toLowerCase(), html, "Editor content correctly returned after calling 'getValue'");
var value = editor.getValue(false, false);
equal(value.toLowerCase(), html, "Editor content correctly returned after calling 'getValue(false, false)'");

editor.clear();
value = editor.getValue();
Expand Down Expand Up @@ -415,7 +415,7 @@ if (wysihtml5.browser.supported()) {
equal(editor.config.parserRules, parserRules, "Parser rules correctly set on config object");
// Invoke parsing via second parameter of setValue()
editor.setValue(input, true);
equal(editor.getValue().toLowerCase(), output, "HTML got correctly parsed within setValue()");
equal(editor.getValue(false, false).toLowerCase(), output, "HTML got correctly parsed within setValue()");
start();
});
});
Expand All @@ -428,7 +428,6 @@ if (wysihtml5.browser.supported()) {
parserRules = { script: undefined },
input = this.textareaElement.value,
output = input;

var editor = new wysihtml5.Editor(this.textareaElement, {
parserRules: parserRules,
parser: function(html, config) {
Expand All @@ -445,7 +444,7 @@ if (wysihtml5.browser.supported()) {

// Invoke parsing via second parameter of setValue()
editor.setValue(input, true);
equal(editor.getValue().toLowerCase(), output, "HTML got correctly parsed within setValue()");
equal(editor.getValue(false, false).toLowerCase(), output, "HTML got correctly parsed within setValue()");

start();
});
Expand Down
16 changes: 8 additions & 8 deletions test/undo_manager_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,19 @@ if (wysihtml5.browser.supportsCommand(document, "insertHTML")) {
editor.setValue("1 2 3 4 5");

that.triggerUndo(editor);
equal(editor.getValue(), "1 2 3 4");
equal(editor.getValue(false, false), "1 2 3 4");
that.triggerRedo(editor);
that.triggerRedo(editor);
equal(editor.getValue(), "1 2 3 4 5");
equal(editor.getValue(false, false), "1 2 3 4 5");
that.triggerUndo(editor);
that.triggerUndo(editor);
equal(editor.getValue(), "1 2 3");
equal(editor.getValue(false, false), "1 2 3");
that.triggerUndo(editor);
that.triggerUndo(editor);
equal(editor.getValue(), "1");
equal(editor.getValue(false, false), "1");
that.triggerUndo(editor);
that.triggerUndo(editor);
equal(editor.getValue(), "1");
equal(editor.getValue(false, false), "1");

start();
});
Expand All @@ -81,12 +81,12 @@ if (wysihtml5.browser.supportsCommand(document, "insertHTML")) {
editor.setValue("<i><b>1</b></i>").fire("beforecommand:composer");

that.triggerUndo(editor);
equal(editor.getValue(), "<b>1</b>");
equal(editor.getValue(false, false), "<b>1</b>");
that.triggerRedo(editor);
equal(editor.getValue(), "<i><b>1</b></i>");
equal(editor.getValue(false, false), "<i><b>1</b></i>");
that.triggerUndo(editor);
that.triggerUndo(editor);
equal(editor.getValue(), "1");
equal(editor.getValue(false, false), "1");

start();
});
Expand Down

0 comments on commit 094f2ba

Please sign in to comment.