This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @module ob/plugins/wikidom/htmltowikidom, | |
* @requires ob/plugins/wikidom/wikidom | |
*/ | |
var NS = 'ob.plugins.wikidom', | |
Yopw = Y.namespace(NS), | |
SPECIAL_CHARS = [{ | |
LT: { | |
original: '<', | |
replacement: '⫷', | |
entity: '<' | |
}, | |
GT: { | |
original: '>', | |
replacement: '⫸', | |
entity: '>' | |
}, | |
QUOTE: { | |
original: '\'', | |
replacement: '⧘', | |
entity: ''' | |
}, | |
DOUBLE_QUOTE: { | |
original: '"', | |
replacement: '⧚', | |
entity: '"' | |
} | |
}], | |
/** | |
* Utils to convert WikiDOM to HTML and HTML to WikiDOM | |
* @class Converter | |
* @namespace Y.ob.plugins.wikidom | |
* @extends Y.Base | |
* @abstract | |
* @public | |
*/ | |
Converter = Y.Base.create('Converter', Y.Base, [], { | |
initializer: function() | |
{ | |
this._init(); | |
}, | |
_init: function() | |
{ | |
throw new Error('Can\'t instanciate abstract class'); | |
} | |
}, { | |
ATTRS: { | |
/** | |
* HTML string value | |
* @attribute html | |
* @type String | |
* @public | |
*/ | |
html: { | |
value: '', | |
validator: function(v) | |
{ | |
return Y.Lang.isString(v); | |
} | |
}, | |
/** | |
* WikiDOM object value | |
* @attribute wikidom | |
* @type Y.ob.plugins.wikidom.Document | |
* @public | |
*/ | |
wikidom: { | |
valueFn: function() | |
{ | |
return new Yopw.Document(); | |
}, | |
setter: function(v) | |
{ | |
if (v.name && 'Document' === v.name) | |
{ | |
return v; | |
} | |
try | |
{ | |
return new Yopw.Document(v); | |
} | |
catch (e){} | |
} | |
} | |
} | |
}), | |
/** | |
* Convert HTML to WikiDOM object | |
* @class HTML2WikiDOM | |
* @namespace Y.ob.plugins.wikidom | |
* @extends Y.ob.plugins.wikidom.Converter | |
* @public | |
*/ | |
HTML2WikiDOM = Y.Base.create('HTML2WikiDOM', Converter, [], { | |
_init: function() {}, | |
/** | |
* Convert HTML value to WikiDOM object | |
* @method render | |
* @param {String} html HTML to convert | |
* @return Y.ob.plugins.wikidom.Document | |
* @public | |
*/ | |
render: function(html) | |
{ | |
var wikidom = new Yopw.Document(); | |
if (html) | |
{ | |
this.set('html', html); | |
} | |
html = this.get('html'); | |
if (html.match(/^[^<>]+$/)) | |
{ | |
html = '<p>'+html+'</p>'; | |
} | |
var node = document.createElement('div'); | |
node.innerHTML = html; | |
this._parseChildren(node, wikidom); | |
this.set('wikidom', wikidom); | |
return wikidom; | |
}, | |
/** | |
* Parse children node elements to WikiDOM Child objects. | |
* Recursive function. | |
* @method _parseChildren | |
* @param {Element} node Element to transform to WikiDOM object | |
* @param {Y.ob.plugins.wikidom.Child} parent Child where to append the new | |
* objects | |
* @private | |
*/ | |
_parseChildren: function(node, parent) | |
{ | |
var children = node.childNodes; | |
Y.each( | |
children, | |
function(c) | |
{ | |
var type = c.nodeName.toLowerCase(); | |
if ('#text' === type) | |
{ | |
// Content | |
return this._addContent(c.textContent, parent); | |
} | |
else | |
if ('br' === type) | |
{ | |
return this._addContent('\\n', parent); | |
} | |
else | |
{ | |
c.innerHTML = c.innerHTML.replace(/( )|\s+/g, ' '); | |
// Annotation | |
if (type.match(new RegExp( | |
'^('+Yopw.Annotation.getTagsRegExp()+')$' | |
))) | |
{ | |
if (!c.textContent) | |
{ | |
return; | |
} | |
return this._parseChildren( | |
this._addAnnotation(c, parent), | |
parent | |
); | |
} | |
else | |
// Child | |
if (type.match(new RegExp( | |
'^('+Yopw.Child.getTagsRegExp()+')$' | |
)) && | |
parent.canHaveChild(type)) | |
{ | |
c.innerHTML = Y.Lang.trim(c.innerHTML); | |
return this._parseChildren( | |
c, | |
this._addChild(c, parent) | |
); | |
} | |
// Trash | |
else | |
{ | |
return this._parseChildren(c, parent); | |
} | |
} | |
}, | |
this | |
); | |
}, | |
/** | |
* Set content of a Child object | |
* @method _addContent | |
* @param {String} text Text to append to Content object | |
* @param {Y.ob.plugins.wikidom.Child} Parent to appends content text | |
* @private | |
*/ | |
_addContent: function(text, parent) | |
{ | |
var content = parent.get('content'), | |
text; | |
if (!content) | |
{ | |
return; | |
} | |
content.set('text', content.get('text') + text); | |
}, | |
/** | |
* Add a new child | |
* @method _addChild | |
* @param {Element} node Element to convert to Child | |
* @param {Y.ob.plugins.wikidom.Child} Parent where to append the new child | |
* @private | |
* @return Y.ob.plugins.wikidom.Child | |
*/ | |
_addChild: function(node, parent) | |
{ | |
var type = node.nodeName.toLowerCase(), | |
child = Yopw.Child.createChildFromTag(type); | |
return parent.addChild(child); | |
}, | |
/** | |
* Add a new Annotation object | |
* @method _addAnnotation | |
* @param {Element} node Element to convert to annotation | |
* @param {Y.ob.plugins.wikidom.Child} Parent where to append the new | |
* annotation | |
* @private | |
* return node | |
*/ | |
_addAnnotation: function(node, parent) | |
{ | |
var type = node.nodeName.toLowerCase(), | |
annotation = Yopw.Annotation.createAnnotationFromTag(type), | |
content = parent.get('content'), | |
annotations = content.get('annotations'), | |
range_s = content.get('text').length, | |
range_e = range_s + node.textContent.length, | |
preva = (annotations && annotations.length) ? | |
annotations[annotations.length - 1] : null; | |
annotation.set('range_start', range_s); | |
// Check if this annotation is same as another one | |
if (preva && | |
annotation.get('type') === preva.get('type') && | |
preva.get('range_end') === range_s) | |
{ | |
annotation = preva; | |
} | |
else | |
{ | |
annotations.push(annotation); | |
} | |
annotation.set('range_end', range_e); | |
if (Yopw.ANNOTATION_LINK === annotation.get('type')) | |
{ | |
annotation.set( | |
'data', | |
{'title': node.getAttribute('href')} | |
); | |
} | |
return node; | |
} | |
}), | |
/** | |
* Convert WikiDOM to HTML object | |
* @class WikiDOM2HTML | |
* @namespace Y.ob.plugins.wikidom | |
* @extends Y.ob.plugins.wikidom.Converter | |
* @public | |
*/ | |
WikiDOM2HTML = Y.Base.create('WikiDOM2HTML', Converter, [], | |
{ | |
_init: function() {}, | |
/** | |
* Convert wikiDOM value to html | |
* @method render | |
* @param {Y.ob.plugins.wikidom.Document} wikidom WikiDOM object | |
* @return string | |
* @public | |
*/ | |
render: function(wikidom) | |
{ | |
var node = document.createElement('div'); | |
if (wikidom) | |
{ | |
this.set('wikidom', wikidom); | |
} | |
wikidom = this.get('wikidom'); | |
this._parseChild(wikidom, node); | |
return node.innerHTML; | |
}, | |
/** | |
* Parse a Child object. Recursive function. | |
* @method _parseChild | |
* @param {Y.ob.plugins.wikidom.Child} child Child to convert to Element | |
* @param {Element} parent Parent node where to append the new one | |
* @private | |
*/ | |
_parseChild: function(child, parent) | |
{ | |
var tag, node, content; | |
if ('document' === child.get('type')) | |
{ | |
Y.each( | |
child.get('children'), | |
function(c) | |
{ | |
this._parseChild(c, parent) | |
}, | |
this | |
); | |
return; | |
} | |
else | |
{ | |
tag = child.getTag(); | |
node = document.createElement(tag); | |
parent.appendChild(node); | |
content = child.get('content'); | |
if (content) | |
{ | |
node.innerHTML = this._renderContent(content); | |
} | |
return this._parseChildren(child.get('children'), node); | |
} | |
}, | |
/** | |
* Parse array of children | |
* @method _parseChildren | |
* @param {Array} children Array of children to send to _parseChild method | |
* @param {Element} parent Parent node where to append the new children | |
* @private | |
*/ | |
_parseChildren: function(children, parent) | |
{ | |
if (!Y.Lang.isArray(children)) return; | |
Y.each( | |
children, | |
function(c) | |
{ | |
this._parseChild(c, parent); | |
}, | |
this | |
); | |
}, | |
/** | |
* Render a child content | |
* @method _renderContent | |
* @param {Y.ob.plugins.wikidom.Content} c Content to render | |
* @private | |
* @return String | |
*/ | |
_renderContent: function(c) | |
{ | |
var list = [], | |
annotations = c.get('annotations'), | |
html = this._encodeText(c.get('text')), | |
length = 0; | |
/** | |
* Sort annotations | |
*/ | |
Y.each( | |
annotations, | |
function(a, i) | |
{ | |
var pos = a.get('range_end'); | |
if (!list[pos]) | |
{ | |
list[pos] = []; | |
} | |
list[pos].push({ | |
annotation: a, | |
begin: false | |
}); | |
pos = a.get('range_start'); | |
if (!list[pos]) | |
{ | |
list[pos] = []; | |
} | |
list[pos].push({ | |
annotation: a, | |
begin: true | |
}); | |
} | |
); | |
/** | |
* Generate html | |
*/ | |
if (list.length) | |
{ | |
Y.each( | |
list, | |
function(annotations, i) | |
{ | |
var replace = '', | |
pos = i + length; | |
Y.each( | |
annotations, | |
function(a) | |
{ | |
var tag = a.annotation.getTag(a.begin); | |
if (a.begin) | |
{ | |
replace += tag; | |
} | |
else | |
{ | |
replace = tag+replace; | |
} | |
} | |
); | |
html = html.substring(0, pos) | |
+ replace | |
+ html.substring(pos); | |
length += replace.length; | |
} | |
); | |
} | |
return this._entitiesText(html) | |
.replace(/\\n/g, '<br />'); | |
}, | |
/** | |
* Encode some special caracters to make convertion easier | |
* @method _encodeText | |
* @param {String} text Text to encode | |
* @private | |
* @return String | |
*/ | |
_encodeText: function(text) | |
{ | |
Y.each( | |
SPECIAL_CHARS, | |
function(s) | |
{ | |
text = text.replace(s.original, s.replacement); | |
} | |
); | |
return text; | |
}, | |
/** | |
* Get back the encoded caracters as html entities | |
* @method _entitiesText | |
* @param {String} text Text to encode | |
* @private | |
* @return String | |
*/ | |
_entitiesText: function(text) | |
{ | |
Y.each( | |
SPECIAL_CHARS, | |
function(s) | |
{ | |
text = text.replace(s.replacement, s.entity); | |
} | |
); | |
return text; | |
} | |
}); | |
/** | |
* Convert HTML string to Y.ob.plugins.wikidom.Document object | |
* @method html2wikidom | |
* @param {String} html HTML to convert to WikiDOM object | |
* @static | |
* @return Y.ob.plugins.wikidom.Document | |
*/ | |
Converter.html2wikidom = function(html) | |
{ | |
var converter = new HTML2WikiDOM({ | |
html: html | |
}); | |
return converter.render().asJson(); | |
}; | |
/** | |
* Convert Y.ob.plugins.wikidom.Document object to HTML string | |
* @method wikidom2html | |
* @param {Y;ob.plugins.wikidom.Document} wikidom WikiDOM object to render as | |
* HTML | |
* @static | |
* @return String | |
*/ | |
Converter.wikidom2html = function(wikidom) | |
{ | |
if (!wikidom || | |
!wikidom.name || | |
wikidom.name !== 'Document') | |
{ | |
try | |
{ | |
wikidom = new Y.ob.plugins.wikidom.Document(wikidom); | |
} | |
catch (e) | |
{ | |
throw new Error( | |
'wikidom must be a Y.ob.plugins.wikidom.Document object' | |
); | |
} | |
} | |
var converter = new WikiDOM2HTML({ | |
wikidom: wikidom | |
}); | |
return converter.render(); | |
}; | |
Yopw.Converter = Converter; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment