Implement tests for serialization
ensure that complex DOM elements can serialize and deserialize without modifications RTWYSIWYG-54 > implement tests for components of the WYSIWYG editorpull/1/head
parent
6b9d982d40
commit
a07774e81a
@ -0,0 +1,124 @@
|
||||
define([], function () {
|
||||
// this makes recursing a lot simpler
|
||||
var isArray = function (A) {
|
||||
return Object.prototype.toString.call(A)==='[object Array]';
|
||||
};
|
||||
|
||||
var parseStyle = function(el){
|
||||
var style = el.style;
|
||||
var output = {};
|
||||
for (var i = 0; i < style.length; ++i) {
|
||||
var item = style.item(i);
|
||||
output[item] = style[item];
|
||||
}
|
||||
return output;
|
||||
};
|
||||
|
||||
var callOnHyperJSON = function (hj, cb) {
|
||||
var children;
|
||||
|
||||
if (hj && hj[2]) {
|
||||
children = hj[2].map(function (child) {
|
||||
if (isArray(child)) {
|
||||
// if the child is an array, recurse
|
||||
return callOnHyperJSON(child, cb);
|
||||
} else if (typeof (child) === 'string') {
|
||||
// string nodes have leading and trailing quotes
|
||||
return child.replace(/(^"|"$)/g,"");
|
||||
} else {
|
||||
// the above branches should cover all methods
|
||||
// if we hit this, there is a problem
|
||||
throw new Error();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
children = [];
|
||||
}
|
||||
// this should return the top level element of your new DOM
|
||||
return cb(hj[0], hj[1], children);
|
||||
};
|
||||
|
||||
var classify = function (token) {
|
||||
return '.' + token.trim();
|
||||
};
|
||||
|
||||
var isValidClass = function (x) {
|
||||
if (x && /\S/.test(x)) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var isTruthy = function (x) {
|
||||
return x;
|
||||
};
|
||||
|
||||
var DOM2HyperJSON = function(el, predicate, filter){
|
||||
if(!el.tagName && el.nodeType === Node.TEXT_NODE){
|
||||
return el.textContent;
|
||||
}
|
||||
if(!el.attributes){
|
||||
return;
|
||||
}
|
||||
if (predicate) {
|
||||
if (!predicate(el)) {
|
||||
// shortcircuit
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var attributes = {};
|
||||
|
||||
var i = 0;
|
||||
for(;i < el.attributes.length; i++){
|
||||
var attr = el.attributes[i];
|
||||
if(attr.name && attr.value){
|
||||
if(attr.name === "style"){
|
||||
attributes.style = parseStyle(el);
|
||||
}
|
||||
else{
|
||||
attributes[attr.name] = attr.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this should never be longer than three elements
|
||||
var result = [];
|
||||
|
||||
// get the element type, id, and classes of the element
|
||||
// and push them to the result array
|
||||
var sel = el.tagName;
|
||||
|
||||
if(attributes.id){
|
||||
// we don't have to do much to validate IDs because the browser
|
||||
// will only permit one id to exist
|
||||
// unless we come across a strange browser in the wild
|
||||
sel = sel +'#'+ attributes.id;
|
||||
delete attributes.id;
|
||||
}
|
||||
result.push(sel);
|
||||
|
||||
// second element of the array is the element attributes
|
||||
result.push(attributes);
|
||||
|
||||
// third element of the array is an array of child nodes
|
||||
var children = [];
|
||||
|
||||
// js hint complains if we use 'var' here
|
||||
i = 0;
|
||||
for(; i < el.childNodes.length; i++){
|
||||
children.push(DOM2HyperJSON(el.childNodes[i], predicate, filter));
|
||||
}
|
||||
result.push(children.filter(isTruthy));
|
||||
|
||||
if (filter) {
|
||||
return filter(result);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
fromDOM: DOM2HyperJSON,
|
||||
callOn: callOnHyperJSON
|
||||
};
|
||||
});
|
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<script data-main="main" src="/bower_components/requirejs/require.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Serialization tests</h1>
|
||||
|
||||
<h2>Test 1</h2>
|
||||
<h3>class strings</h3>
|
||||
<!-- put in weird HTML that might cause problems -->
|
||||
<div id="target"><p class=" alice bob charlie has.dot" id="bang">pewpewpew</p></div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>Test 2</h2>
|
||||
<h3>XWiki Macros</h3>
|
||||
|
||||
<!-- Can we serialize XWiki Macros? -->
|
||||
<div id="widget"><div data-cke-widget-id="0" tabindex="-1" data-cke-widget-wrapper="1" data-cke-filter="off" class="cke_widget_wrapper cke_widget_block" data-cke-display-name="macro:velocity" contenteditable="false"><div class="macro cke_widget_element" data-macro="startmacro:velocity|-||-|Here is a macro" data-cke-widget-data="%7B%22classes%22%3A%7B%22macro%22%3A1%7D%7D" data-cke-widget-upcasted="1" data-cke-widget-keep-attr="0" data-widget="xwiki-macro"><p>Here is a macro</p></div><span style='background: rgba(220, 220, 220, 0.5) url("/common/cryptofist.png") repeat scroll 0% 0%; top: -15px; left: 0px; display: block;' class="cke_reset cke_widget_drag_handler_container"><img title="Click and drag to move" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" data-cke-widget-drag-handler="1" class="cke_reset cke_widget_drag_handler" height="15" width="15"></span></div></div>
|
||||
|
||||
<hr>
|
@ -0,0 +1,50 @@
|
||||
define([
|
||||
'/bower_components/jquery/dist/jquery.min.js',
|
||||
'/assert/hyperjson.js', // serializing classes as an attribute
|
||||
'/assert/hyperscript.js', // using setAttribute
|
||||
'/common/TextPatcher.js'
|
||||
], function (jQuery, Hyperjson, Hyperscript, TextPatcher) {
|
||||
var $ = window.jQuery;
|
||||
window.Hyperjson = Hyperjson;
|
||||
window.Hyperscript = Hyperscript;
|
||||
window.TextPatcher = TextPatcher;
|
||||
|
||||
var assertions = 0;
|
||||
|
||||
var assert = function (test, msg) {
|
||||
if (test()) {
|
||||
assertions++;
|
||||
} else {
|
||||
throw new Error(msg || '');
|
||||
}
|
||||
};
|
||||
|
||||
var $body = $('body');
|
||||
|
||||
var roundTrip = function (target) {
|
||||
assert(function () {
|
||||
var hjson = Hyperjson.fromDOM(target);
|
||||
var cloned = Hyperjson.callOn(hjson, Hyperscript);
|
||||
|
||||
var success = cloned.outerHTML === target.outerHTML;
|
||||
|
||||
if (!success) {
|
||||
window.DEBUG = {
|
||||
error: "Expected equality between A and B",
|
||||
A: target.outerHTML,
|
||||
B: cloned.outerHTML,
|
||||
target: target,
|
||||
diff: TextPatcher.diff(target.outerHTML, cloned.outerHTML)
|
||||
};
|
||||
console.log(JSON.stringify(window.DEBUG, null, 2));
|
||||
}
|
||||
|
||||
return success;
|
||||
}, "Round trip serialization introduced artifacts.");
|
||||
};
|
||||
|
||||
roundTrip($('#target')[0]);
|
||||
roundTrip($('#widget')[0]);
|
||||
|
||||
console.log("%s test%s passed", assertions, assertions === 1? '':'s');
|
||||
});
|
Loading…
Reference in New Issue