wlxml: moving white space handling from canvas code base
[fnpeditor.git] / src / wlxml / wlxml.js
1 define([
2     'smartxml/smartxml'
3 ], function(smartxml) {
4     
5 'use strict';
6
7 // utils
8
9 var isMetaAttribute = function(attrName) {
10     return attrName.substr(0, 5) === 'meta-';
11 };
12
13 //
14
15 var WLXMLElementNode = function(nativeNode, document) {
16     smartxml.ElementNode.call(this, nativeNode, document);
17 };
18 WLXMLElementNode.prototype = Object.create(smartxml.ElementNode.prototype);
19
20 $.extend(WLXMLElementNode.prototype, smartxml.ElementNode.prototype, {
21     getClass: function() {
22         return this.getAttr('class');
23     },
24     setClass: function(klass) {
25         return this.setAttr('class', klass);
26     },
27     getMetaAttributes: function() {
28         var toret = [];
29         this.getAttrs().forEach(function(attr) {
30             if(isMetaAttribute(attr.name)) {
31                 toret.push({name: attr.name.substr(5), value: attr.value});
32             }
33         });
34         return toret;
35     },
36     getOtherAttributes: function() {
37         var toret = {};
38         this.getAttrs().forEach(function(attr) {
39             if(attr.name !== 'class' && !isMetaAttribute(attr.name)) {
40                 toret[attr.name] = attr.value;
41             }
42         });
43         return toret;
44     }
45 });
46
47
48 var WLXMLDocument = function(xml) {
49     smartxml.Document.call(this, xml);
50
51     $(this.dom).find(':not(iframe)').addBack().contents()
52     .filter(function() {return this.nodeType === Node.TEXT_NODE;})
53     .each(function() {
54         var el = $(this),
55             text = {original: el.text(), trimmed: $.trim(el.text())},
56             elParent = el.parent(),
57             hasSpanParent = elParent.prop('tagName') === 'SPAN',
58             hasSpanBefore = el.prev().length && $(el.prev()).prop('tagName') === 'SPAN',
59             hasSpanAfter = el.next().length && $(el.next()).prop('tagName') === 'SPAN';
60
61
62         text.transformed = text.trimmed;
63
64         if(hasSpanParent || hasSpanBefore || hasSpanAfter) {
65             var startSpace = /\s/g.test(text.original.substr(0,1)),
66                 endSpace = /\s/g.test(text.original.substr(-1)) && text.original.length > 1;
67             text.transformed = (startSpace && (hasSpanParent || hasSpanBefore) ? ' ' : '');
68             text.transformed += text.trimmed;
69             text.transformed += (endSpace && (hasSpanParent || hasSpanAfter) ? ' ' : '');
70         } else {
71             if(text.trimmed.length === 0 && text.original.length > 0 && elParent.contents().length === 1) {
72                 text.transformed = ' ';
73             }
74         }
75
76         if(!text.transformed) {
77             el.remove();
78             return true; // continue
79         }
80         el.replaceWith(document.createTextNode(text.transformed));
81     });
82 };
83 WLXMLDocument.prototype = Object.create(smartxml.Document.prototype);
84 $.extend(WLXMLDocument.prototype, {
85     ElementNodeFactory: WLXMLElementNode
86 });
87
88
89 return {
90     WLXMLDocumentFromXML: function(xml) {
91         return new WLXMLDocument(xml);
92     },
93
94     WLXMLElementNodeFromXML: function(xml) {
95         return this.WLXMLDocumentFromXML(xml).root;
96     }
97 };
98
99 });