Describing DocumentElements internal html structure
[fnpeditor.git] / modules / documentCanvas / canvas / canvas.test3.js
1 define([
2 'libs/chai',
3 'modules/documentCanvas/canvas/canvas',
4 'modules/documentCanvas/canvas/documentElement'
5 ], function(chai, canvas, documentElement) {
6     
7 'use strict';
8
9 var expect = chai.expect;
10
11
12 describe('Canvas', function() {
13
14     describe('Internal HTML representation of a DocumentNodeElement', function() {
15         it('is always a div tag', function() {
16             ['section', 'header', 'span', 'aside', 'figure'].forEach(function(tagName) {
17                 var dom = canvas.fromXML('<' + tagName + '></' + tagName + '>').doc().dom();
18                 expect(dom.prop('tagName')).to.equal('DIV', tagName + ' is represented as div');
19             });
20         });
21         it('has wlxml tag put into wlxml-tag attribute', function() {
22             var dom = canvas.fromXML('<section></section>').doc().dom();
23             expect(dom.attr('wlxml-tag')).to.equal('section');
24         });
25         it('has wlxml class put into wlxml-class, dots replaced with dashes', function() {
26             var dom = canvas.fromXML('<section class="some.class"></section>').doc().dom();
27             expect(dom.attr('wlxml-class')).to.equal('some-class');
28         });
29     });
30
31     describe('Internal HTML representation of a DocumentTextElement', function() {
32         it('is just a TextNode', function() {
33             var dom = canvas.fromXML('<section>Alice</section>').doc().children()[0].dom();
34             expect(dom[0].nodeType === Node.TEXT_NODE);
35         });
36     });
37
38     describe('basic properties', function() {
39         it('renders empty document when canvas created from empty XML', function() {
40             var c = canvas.fromXML('');
41             expect(c.doc()).to.equal(null);
42         });
43
44         it('gives access to its document root node', function() {
45             var c = canvas.fromXML('<section></section>');
46             expect(c.doc().wlxmlTag).to.equal('section');
47         });
48
49         describe('DocumentElement', function() {
50             it('knows index of its child', function() {
51                 var c = canvas.fromXML('<section><div></div><header></header><span></span></section>'),
52                     root = c.doc(),
53                     child = root.children()[1];
54                 expect(root.childIndex(child)).to.equal(1);
55             });
56
57             describe('DocumentTextElement can have its content set', function() {
58                 var c = canvas.fromXML('<section>Alice</section>'),
59                     root = c.doc(),
60                     text = root.children()[0];
61                 
62                 text.setText('a cat');
63                 expect(root.children()[0].getText()).to.equal('a cat');
64             });
65         });
66     });
67
68     describe('document representation api', function() {
69         describe('document root element', function() {
70             var c = canvas.fromXML('<section></section>');
71             it('exists', function() {
72                 expect(c.doc()).to.be.instanceOf(documentElement.DocumentElement);
73             });
74             it('is of type DocumentNodeElement', function() {
75                 expect(c.doc()).to.be.instanceOf(documentElement.DocumentNodeElement);
76             });
77         });
78
79         describe('DocumentElements comparison', function() {
80             it('reports dwo DocumentElements to be the same when they represent the same wlxml document element', function() {
81                 var c = canvas.fromXML('<section><div></div><div></div></section>'),
82                     first_div1 = c.doc().children()[0],
83                     first_div2 = c.doc().children()[0],
84                     second_div = c.doc().children()[1];
85                 expect(first_div1.sameNode(first_div1)).to.be.true;
86                 expect(first_div1.sameNode(first_div2)).to.be.true;
87                 expect(first_div1.sameNode(second_div)).to.be.false;
88             });
89         });
90
91         describe('traversing', function() {
92             it('reports element nodes', function() {
93                 var c = canvas.fromXML('<section><div></div></section>'),
94                     children = c.doc().children();
95                 expect(children.length).to.equal(1);
96                 expect(children[0]).to.be.instanceOf(documentElement.DocumentNodeElement);
97
98                 c = canvas.fromXML('<section><div></div><div></div></section>'),
99                     children = c.doc().children();
100                 expect(children.length).to.equal(2);
101                 expect(children[0]).to.be.instanceOf(documentElement.DocumentNodeElement);
102                 expect(children[1]).to.be.instanceOf(documentElement.DocumentNodeElement);
103             });
104             
105             it('reports text nodes', function() {
106                 var c = canvas.fromXML('<section>Alice</section>'),
107                     children = c.doc().children();
108                 expect(children.length).to.equal(1);
109                 expect(children[0]).to.be.instanceOf(documentElement.DocumentTextElement);
110             });
111
112             describe('accessing parents', function() {
113                 it('returns DocumentNodeElement representing parent in wlxml document as DocumentNodeElement parent', function() {
114                     var c = canvas.fromXML('<section><div></div></section>'),
115                         div = c.doc().children()[0];
116                     expect(div.parent().sameNode(c.doc())).to.be.true;
117                 });
118                 it('returns DocumentNodeElement representing parent in wlxml document as DocumentTextElement parent', function() {
119                     var c = canvas.fromXML('<section>Alice</section>'),
120                         text = c.doc().children()[0];
121                     expect(text.parent().sameNode(c.doc())).to.be.true;
122                 });
123             });
124
125             describe('free text handling', function() {
126                     it('sees free text', function() {
127                         var c = canvas.fromXML('<section>Alice <span>has</span> a cat</section>'),
128                             children = c.doc().children();
129                         expect(children.length).to.equal(3);
130                         expect(children[0]).to.be.instanceOf(documentElement.DocumentTextElement);
131                         expect(children[1]).to.be.instanceOf(documentElement.DocumentNodeElement);
132                         expect(children[2]).to.be.instanceOf(documentElement.DocumentTextElement);
133                     });
134             });
135             
136             describe('white characters handling', function() {
137                 it('says empty element node has no children', function() {
138                     var c = canvas.fromXML('<section></section>');
139                     expect(c.doc().children().length).to.equal(0);
140                 });
141                 it('says element node with one space has one DocumentTextElement', function() {
142                     var c = canvas.fromXML('<section> </section>');
143                     expect(c.doc().children().length).to.equal(1);
144                     expect(c.doc().children()[0]).to.be.instanceOf(documentElement.DocumentTextElement);
145                 });
146                 it('ignores white space surrounding block elements', function() {
147                     var c = canvas.fromXML('<section> <div></div> </section>');
148                     var children = c.doc().children();
149                     expect(children.length).to.equal(1);
150                     expect(children[0]).to.be.instanceOf(documentElement.DocumentNodeElement);
151                 });
152                 it('ignores white space between block elements', function() {
153                     var c = canvas.fromXML('<section><div></div> <div></div></section>');
154                     var children = c.doc().children();
155                     expect(children.length === 2);
156                     [0,1].forEach(function(idx) {
157                         expect(children[idx]).to.be.instanceOf(documentElement.DocumentNodeElement);
158                     });
159                 });
160
161                 it('trims white space from the beginning and the end of the block elements', function() {
162                     var c = canvas.fromXML('<section> Alice <span>has</span> a cat </section>');
163                     expect(c.doc().children()[0].getText()).to.equal('Alice ');
164                     expect(c.doc().children()[2].getText()).to.equal(' a cat');
165                 });
166
167                 it('normalizes string of white characters to one space at the inline element boundries', function() {
168                     var c = canvas.fromXML('<span>   Alice has a cat   </span>');
169                     expect(c.doc().children()[0].getText()).to.equal(' Alice has a cat ');
170                 });
171
172                 it('normalizes string of white characters to one space before inline element', function() {
173                     var c = canvas.fromXML('<div>Alice has  <span>a cat</span></div>');
174                     expect(c.doc().children()[0].getText()).to.equal('Alice has ');
175                 });
176                 
177                 it('normalizes string of white characters to one space after inline element', function() {
178                     var c = canvas.fromXML('<div>Alice has <span>a</span>  cat</div>');
179                     expect(c.doc().children()[2].getText()).to.equal(' cat');
180                 });
181             });
182         });
183
184         describe('manipulation api', function() {
185
186             describe('Basic Element inserting', function() {
187                 it('can put new NodeElement at the end', function() {
188                     var c = canvas.fromXML('<section></section>'),
189                         appended = c.doc().append({tag: 'header', klass: 'some.class'}),
190                         children = c.doc().children();
191
192                     expect(children.length).to.equal(1);
193                     expect(children[0].sameNode(appended));
194                 });
195
196                 it('can put new TextElement at the end', function() {
197                     var c = canvas.fromXML('<section></section>'),
198                         appended = c.doc().append({text: 'Alice'}),
199                         children = c.doc().children();
200
201                     expect(children.length).to.equal(1);
202                     expect(children[0].sameNode(appended));
203                     expect(children[0].getText()).to.equal('Alice');
204                 });
205
206                 it('can put new NodeElement after another NodeElement', function() {
207                     var c = canvas.fromXML('<section><div></div></section>'),
208                         div = c.doc().children()[0],
209                         added = div.after({tag: 'header', klass: 'some.class'}),
210                         children = c.doc().children();
211                     expect(children.length).to.equal(2);
212                     expect(children[1].sameNode(added));
213                 });
214
215                 it('can put new Nodeelement before another element', function() {
216                     var c = canvas.fromXML('<section><div></div></section>'),
217                         div = c.doc().children()[0],
218                         added = div.before({tag: 'header', klass: 'some.class'}),
219                         children = c.doc().children();
220                     expect(children.length).to.equal(2);
221                     expect(children[0].sameNode(added));
222                 });
223
224                 it('can put new DocumentNodeElement after DocumentTextElement', function() {
225                     var c = canvas.fromXML('<section>Alice</section>'),
226                         text = c.doc().children()[0],
227                         added = text.after({tag: 'p'}),
228                         children = c.doc().children();
229
230                     expect(children.length).to.equal(2);
231                     expect(children[0]).to.be.instanceOf(documentElement.DocumentTextElement);
232                     expect(children[0].getText()).to.equal('Alice');
233                     expect(children[1]).to.be.instanceOf(documentElement.DocumentNodeElement);
234                     expect(children[1].sameNode(added)).to.be.true;
235                 });
236                 it('can put new DocumentNodeElement before DocumentTextElement', function() {
237                     var c = canvas.fromXML('<section>Alice</section>'),
238                         text = c.doc().children()[0],
239                         added = text.before({tag: 'p'}),
240                         children = c.doc().children();
241
242                     expect(children.length).to.equal(2);
243                     expect(children[0]).to.be.instanceOf(documentElement.DocumentNodeElement);
244                     expect(children[0].sameNode(added)).to.be.true;
245                     expect(children[1]).to.be.instanceOf(documentElement.DocumentTextElement);
246                     expect(children[1].getText()).to.equal('Alice');
247                 });
248             });
249
250             describe('Splitting text', function() {
251                 
252                 it('splits DocumentTextElement\'s parent into two DocumentNodeElements of the same type', function() {
253                     var c = canvas.fromXML('<section><header>Some header</header></section>'),
254                         section = c.doc(),
255                         text = section.children()[0].children()[0];
256
257                     text.split({offset: 5});
258                     expect(section.children().length).to.equal(2, 'section has two children');
259                     
260                     var header1 = section.children()[0];
261                     var header2 = section.children()[1];
262
263                     expect(header1.wlxmlTag).to.equal('header', 'first section child represents wlxml header');
264                     expect(header1.children().length).to.equal(1, 'first header has one text child');
265                     expect(header1.children()[0].getText()).to.equal('Some ', 'first header has correct content');
266                     expect(header2.wlxmlTag).to.equal('header', 'second section child represents wlxml header');
267                     expect(header2.children().length).to.equal(1, 'second header has one text child');
268                     expect(header2.children()[0].getText()).to.equal('header', 'second header has correct content');
269                 });
270
271                 it('keeps DocumentTextElement\'s parent\'s children elements intact', function() {
272                     var c = canvas.fromXML('\
273                             <section>\
274                                 <header>\
275                                     A <span>fancy</span> and <span>nice</span> header\
276                                 </header>\
277                             </section>'),
278                         section = c.doc(),
279                         header = section.children()[0],
280                         textAnd = header.children()[2];
281
282                     textAnd.split({offset: 2});
283                     
284                     var sectionChildren = section.children();
285                     expect(sectionChildren.length).to.equal(2, 'Section has two children');
286                     expect(sectionChildren[0].wlxmlTag).to.equal('header', 'First section element is a wlxml header');
287                     expect(sectionChildren[1].wlxmlTag).to.equal('header', 'Second section element is a wlxml header');
288
289                     var firstHeaderChildren = sectionChildren[0].children();
290                     expect(firstHeaderChildren.length).to.equal(3, 'First header has three children');
291                     expect(firstHeaderChildren[0].getText()).to.equal('A ', 'First header starts with a text');
292                     expect(firstHeaderChildren[1].wlxmlTag).to.equal('span', 'First header has span in the middle');
293                     expect(firstHeaderChildren[2].getText()).to.equal(' a', 'First header ends with text');
294
295                     var secondHeaderChildren = sectionChildren[1].children();
296                     expect(secondHeaderChildren.length).to.equal(3, 'Second header has three children');
297                     expect(secondHeaderChildren[0].getText()).to.equal('nd ', 'Second header starts with text');
298                     expect(secondHeaderChildren[1].wlxmlTag).to.equal('span', 'Second header has span in the middle');
299                     expect(secondHeaderChildren[2].getText()).to.equal(' header', 'Second header ends with text');
300                 });
301             });
302
303             describe('wrapping', function() {
304                 it('wraps DocumentNodeElement', function() {
305                     var c = canvas.fromXML('<section><div></div></section>'),
306                         div = c.doc().children()[0];
307                     
308                     var returned = div.wrapWithNodeElement({tag: 'header', klass: 'some.class'}),
309                         parent = div.parent(),
310                         parent2 = c.doc().children()[0];
311
312                     expect(returned.sameNode(parent)).to.be.true;
313                     expect(returned.sameNode(parent2)).to.be.true;
314                 });
315                 it('wraps DocumentTextElement', function() {
316                     var c = canvas.fromXML('<section>Alice</section>'),
317                         text = c.doc().children()[0];
318                     
319                     var returned = text.wrapWithNodeElement({tag: 'header', klass: 'some.class'}),
320                         parent = text.parent(),
321                         parent2 = c.doc().children()[0];
322
323                     expect(returned.sameNode(parent)).to.be.true;
324                     expect(returned.sameNode(parent2)).to.be.true;
325                 });
326                 
327                 it('wraps part of DocumentTextElement', function() {
328                     var c = canvas.fromXML('<section>Alice has a cat</section>'),
329                         text = c.doc().children()[0];
330                     
331                     var returned = text.wrapWithNodeElement({tag: 'header', klass: 'some.class', start: 5, end: 12}),
332                         children = c.doc().children();
333
334                     expect(children.length).to.equal(3);
335                     
336                     expect(children[0]).to.be.instanceOf(documentElement.DocumentTextElement);
337                     expect(children[0].getText()).to.equal('Alice');
338
339                     expect(children[1].sameNode(returned)).to.be.true;
340                     expect(children[1].children().length).to.equal(1);
341                     expect(children[1].children()[0].getText()).to.equal(' has a ');
342
343                     expect(children[2]).to.be.instanceOf(documentElement.DocumentTextElement);
344                     expect(children[2].getText()).to.equal('cat');
345                 });
346
347                 it('wraps text spanning multiple sibling DocumentTextNodes', function() {
348                     var c = canvas.fromXML('<section>Alice has a <span>small</span> cat</section>'),
349                         section = c.doc(),
350                         wrapper = c.wrapText({
351                             inside: section, 
352                             _with: {tag: 'span', klass: 'some.class'},
353                             offsetStart: 6,
354                             offsetEnd: 4,
355                             textNodeIdx: [0,2]
356                         });
357
358                     expect(section.children().length).to.equal(2);
359                     expect(section.children()[0]).to.be.instanceOf(documentElement.DocumentTextElement);
360                     expect(section.children()[0].getText()).to.equal('Alice ');
361
362                     var wrapper2 = section.children()[1];
363                     expect(wrapper2.sameNode(wrapper)).to.be.true;
364
365                     var wrapperChildren = wrapper.children();
366                     expect(wrapperChildren.length).to.equal(3);
367                     expect(wrapperChildren[0].getText()).to.equal('has a ');
368
369                     expect(wrapperChildren[1]).to.be.instanceOf(documentElement.DocumentNodeElement);
370                     expect(wrapperChildren[1].children().length).to.equal(1);
371                     expect(wrapperChildren[1].children()[0].getText()).to.equal('small');
372
373                     expect(wrapperChildren[2].getText()).to.equal(' cat');
374                 });
375             });
376         });
377
378         describe('Lists api', function() {
379             it('allows creation of a list from existing sibling DocumentElements', function() {
380                 var c = canvas.fromXML('\
381                     <section>\
382                         Alice\
383                         <div>has</div>\
384                         a\
385                         <div>cat</div>\
386                     </section>'),
387                     section = c.doc(),
388                     textAlice = section.children()[0],
389                     divCat = section.children()[3]
390                 
391                 c.list.create({element1: textAlice, element2: divCat});
392
393                 expect(section.children().length).to.equal(1, 'section has one child element');
394
395                 var list = section.children()[0];
396                 expect(list.is('list')).to.equal(true, 'section\'s only child is a list');
397                 expect(list.children().length).to.equal(4, 'list contains four elements');
398             });
399         });
400
401     });
402 });
403
404
405 });