editor: prevent list action from operating across context root boundries
[fnpeditor.git] / src / wlxml / extensions / list / list.test.js
1 define(function(require) {
2     
3 'use strict';
4
5 /* jshint multistr:true */
6 /* globals describe, it */
7
8 var chai = require('libs/chai'),
9     wlxml = require('wlxml/wlxml'),
10     expect = chai.expect,
11     $ = require('libs/jquery'),
12     listsExtension = require('wlxml/extensions/list/list');
13
14
15 var getDocumentFromXML = function(xml, options) {
16     var doc = wlxml.WLXMLDocumentFromXML(xml, options || {});
17     doc.registerExtension(listsExtension);
18     return doc;
19 };
20
21 var removeEmptyTextNodes = function(xml) {
22     /* globals Node */
23     xml = $($.trim(xml));
24     xml.find(':not(iframe)')
25         .addBack()
26         .contents()
27         .filter(function() {return this.nodeType === Node.TEXT_NODE;})
28         .each(function() {
29             if(!this.data.length) {
30                 $(this).remove();
31             }
32         });
33     return $('<w>').append(xml).html();
34 };
35
36
37 describe('Lists extension', function() {
38
39     describe('creating lists', function() {
40         it('allows creation of a list from existing sibling DocumentElements', function() {
41             var doc = getDocumentFromXML('<section>Alice<div>has</div>a<div>cat</div></section>'),
42                 section = doc.root,
43                 div1 = section.contents()[1],
44                 textA = section.contents()[2];
45             
46             doc.createList({node1: div1, node2: textA});
47
48             expect(section.contents().length).to.equal(3, 'section has three child nodes');
49
50             var child1 = section.contents()[0],
51                 list = section.contents()[1],
52                 child3 = section.contents()[2];
53
54             expect(child1.getText()).to.equal('Alice');
55             expect(list.is('list')).to.equal(true, 'second child is a list');
56             expect(list.contents().length).to.equal(2, 'list contains two elements');
57             list.contents().forEach(function(child) {
58                  expect(child.getClass()).to.equal('item', 'list childs have wlxml class of item');
59             });
60             expect(child3.contents()[0].getText()).to.equal('cat');
61         });
62
63         it('Handles text nodes on the boundries', function() {
64             var doc = getDocumentFromXML('<section>Alice<span>has</span>a cat</section>'),
65                 textNode1 = doc.root.contents()[0],
66                 textNode2 = doc.root.contents()[2];
67             doc.createList({node1: textNode1, node2: textNode2});
68             expect(doc.root.contents().length).to.equal(1);
69             expect(doc.root.contents()[0].is('list')).to.equal(true);
70         });
71
72         it('allows creating nested list from existing sibling list items', function() {
73             var doc = getDocumentFromXML('\
74                 <section>\
75                     <div class="list">\
76                         <div class="item">A</div>\
77                         <div class="item">B</div>\
78                         <div class="item">C</div>\
79                         <div class="item">D</div>\
80                     </div>\
81                 </section>');
82                 
83                 var outerList = doc.root.contents('.list')[0],
84                 itemB = outerList.contents('.item')[1],
85                 itemC = outerList.contents('.item')[2];
86
87             
88             doc.createList({node1: itemB, node2: itemC});
89
90             var outerListItems = outerList.contents('.item'),
91                 innerList = outerListItems[1].contents()[0];
92             
93             var innerListItems = innerList.contents('.item');
94
95             expect(outerListItems.length).to.equal(3, 'outer list has three items');
96             expect(outerListItems[0].contents()[0].getText()).to.equal('A', 'first outer item ok');
97             expect(outerListItems[1].getClass()).to.equal('item', 'inner list is wrapped by item element');
98
99             expect(innerList.is('list')).to.equal(true, 'inner list created');
100             expect(innerListItems.length).to.equal(2, 'inner list has two items');
101             expect(innerListItems[0].contents()[0].getText()).to.equal('B', 'first inner item ok');
102             expect(innerListItems[1].contents()[0].getText()).to.equal('C', 'second inner item ok');
103
104             expect(outerListItems[2].contents()[0].getText()).to.equal('D', 'last outer item ok');
105
106         });
107     });
108
109     describe('extracting list items', function() {
110         it('creates two lists with extracted items in the middle if extracting from the middle of the list', function() {
111             var doc = getDocumentFromXML(removeEmptyTextNodes('\
112                 <section>\
113                     <div class="list">\
114                         <div class="item">0</div>\
115                         <div class="item">1</div>\
116                         <div class="item">2</div>\
117                         <div class="item">3</div>\
118                     </div>\
119                 </section>')),
120                 list = doc.root.contents()[0],
121                 item1 = list.contents()[1],
122                 item2 = list.contents()[2];
123
124             doc.extractItems({item1: item1, item2: item2});
125
126             var section = doc.root,
127                 list1 = section.contents()[0],
128                 oldItem1 = section.contents()[1],
129                 oldItem2 = section.contents()[2],
130                 list2 = section.contents()[3];
131
132             expect(section.contents().length).to.equal(4, 'section contains two old items and two lists');
133             
134             expect(list1.is('list')).to.equal(true, 'first section child is a list');
135             expect(list1.contents().length).to.equal(1, 'first list has one child');
136             expect(list1.contents()[0].contents()[0].getText()).to.equal('0', 'first item of the first list is a first item of the original list');
137
138             expect(oldItem1.contents()[0].getText()).to.equal('1', 'first item got extracted');
139             expect(oldItem1.getClass() === '').to.equal(true, 'first extracted element has no wlxml class');
140
141             expect(oldItem2.contents()[0].getText()).to.equal('2', 'second item got extracted');
142             expect(oldItem2.getClass() === '').to.equal(true, 'second extracted element has no wlxml class');
143
144             expect(list2.is('list')).to.equal(true, 'last section child is a list');
145             expect(list2.contents().length).to.equal(1, 'second list has one child');
146             expect(list2.contents()[0].contents()[0].getText()).to.equal('3', 'first item of the second list is a last item of the original list');
147         });
148
149         it('puts extracted items above the list if starting item is the first one', function() {
150             var doc = getDocumentFromXML(removeEmptyTextNodes('\
151                 <section>\
152                     <div class="list">\
153                         <div class="item">0</div>\
154                         <div class="item">1</div>\
155                         <div class="item">2</div>\
156                     </div>\
157                 </section>')),
158                 list = doc.root.contents()[0],
159                 item1 = list.contents()[0],
160                 item2 = list.contents()[1];
161
162             doc.extractItems({item1: item1, item2: item2});
163
164             var section = doc.root,
165                 oldItem1 = section.contents()[0],
166                 oldItem2 = section.contents()[1],
167                 newList = section.contents()[2];
168
169             expect(section.contents().length).to.equal(3, 'section has three children');
170             expect(oldItem1.contents()[0].getText()).to.equal('0', 'first item extracted');
171             expect(oldItem2.contents()[0].getText()).to.equal('1', 'second item extracted');
172             expect(newList.is('list')).to.equal(true, 'list lies below extracted item');
173             expect(newList.contents().length).to.equal(1, 'list has now one child');
174         });
175
176         it('puts extracted items below the list if ending item is the last one', function() {
177             var doc = getDocumentFromXML(removeEmptyTextNodes('\
178                 <section>\
179                     <div class="list">\
180                         <div class="item">0</div>\
181                         <div class="item">1</div>\
182                         <div class="item">2</div>\
183                     </div>\
184                 </section>')),
185                 list = doc.root.contents()[0],
186                 item2 = list.contents()[1],
187                 item3 = list.contents()[2];
188
189             doc.extractItems({item1: item2, item2: item3});
190
191             var section = doc.root,
192                 oldItem1 = section.contents()[1],
193                 oldItem2 = section.contents()[2],
194                 newList = section.contents()[0];
195
196             expect(section.contents().length).to.equal(3, 'section has three children');
197             expect(oldItem1.contents()[0].getText()).to.equal('1', 'first item extracted');
198             expect(oldItem2.contents()[0].getText()).to.equal('2', 'second item extracted');
199             expect(newList.is('list')).to.equal(true, 'list lies above extracted item');
200             expect(newList.contents().length).to.equal(1, 'list has now one child');
201         });
202
203         it('removes list if all its items are extracted', function() {
204             var doc = getDocumentFromXML(removeEmptyTextNodes('\
205                 <section>\
206                     <div class="list">\
207                         <div class="item">some item</div>\
208                         <div class="item">some item 2</div>\
209                     </div>\
210                 </section>')),
211                 list = doc.root.contents()[0],
212                 item1 = list.contents()[0],
213                 item2 = list.contents()[1];
214
215             doc.extractItems({item1: item1, item2: item2});
216
217             var section = doc.root,
218                 oldItem1 = section.contents()[0],
219                 oldItem2 = section.contents()[1];
220
221             expect(section.contents().length).to.equal(2, 'section contains two children');
222             expect(oldItem1.contents()[0].getText()).to.equal('some item');
223             expect(oldItem2.contents()[0].getText()).to.equal('some item 2');
224         });
225
226         it('creates two lists with extracted items in the middle if extracting from the middle of the list - nested case' , function() {
227             var doc = getDocumentFromXML(removeEmptyTextNodes('\
228                 <section>\
229                     <div class="list">\
230                         <div class="item">0</div>\
231                         <div class="item">\
232                             <div class="list.items">\
233                                 <div class="item">1.1</div>\
234                                 <div class="item">1.2</div>\
235                                 <div class="item">1.3</div>\
236                             </div>\
237                         </div>\
238                         <div class="item">2</div>\
239                     </div>\
240                 </section>')),
241                 list = doc.root.contents()[0],
242                 nestedList = list.contents()[1].contents()[0],
243                 nestedListItem = nestedList.contents()[1];
244
245             doc.extractItems({item1: nestedListItem, item2: nestedListItem}); //@@ name!
246
247             list = doc.root.contents()[0];
248             var item1 = list.contents()[0],
249                 item2 = list.contents()[1], //
250                 item3 = list.contents()[2],
251                 item4 = list.contents()[3], //
252                 item5 = list.contents()[4],
253                 nestedList1 = item2.contents()[0],
254                 nestedList2 = item4.contents()[0];
255
256             expect(list.contents().length).to.equal(5, 'top list has five items');
257             
258             expect(item1.contents()[0].getText()).to.equal('0', 'first item ok');
259
260             expect(item2.getClass()).to.equal('item', 'first nested list is still wrapped in item element');
261             expect(nestedList1.contents().length).to.equal(1, 'first nested list is left with one child');
262             expect(nestedList1.contents()[0].contents()[0].getText()).to.equal('1.1', 'first nested list item left alone');
263             
264             expect(item3.contents()[0].getText()).to.equal('1.2', 'third item ok');
265
266             expect(item4.getClass()).to.equal('item', 'second nested list is still wrapped in item element');
267             expect(nestedList2.contents().length).to.equal(1, 'second nested list is left with one child');
268             expect(nestedList2.contents()[0].contents()[0].getText()).to.equal('1.3', 'second nested list item left alone');
269
270             expect(item5.contents()[0].getText()).to.equal('2', 'last item ok');
271         });
272
273         it('puts extracted items below the list if ending item is the last one - nested case' , function() {
274             var doc = getDocumentFromXML(removeEmptyTextNodes('\
275                 <section>\
276                     <div class="list.items">\
277                         <div class="item">0</div>\
278                         <div class="item">\
279                             <div class="list.items">\
280                                 <div class="item">1.1</div>\
281                                 <div class="item">1.2</div>\
282                                 <div class="item">1.3</div>\
283                             </div>\
284                         </div>\
285                         <div class="item">2</div>\
286                     </div>\
287                 </section>')),
288                 list = doc.root.contents()[0],
289                 nestedList = list.contents()[1].contents()[0],
290                 nestedListItem1 = nestedList.contents()[1],
291                 nestedListItem2 = nestedList.contents()[2];
292
293             doc.extractItems({item1: nestedListItem1, item2: nestedListItem2});
294             list = doc.root.contents()[0];
295             var item1 = list.contents()[0],
296                 item2 = list.contents()[1],
297                 item3 = list.contents()[2],
298                 item4 = list.contents()[3],
299                 item5 = list.contents()[4];
300             nestedList = item2.contents()[0];
301
302             expect(list.contents().length).to.equal(5, 'top list has five items');
303             expect(item1.contents()[0].getText()).to.equal('0', 'first item ok');
304             expect(item2.getClass()).to.equal('item', 'nested list is still wrapped in item element');
305             expect(nestedList.contents().length).to.equal(1, 'nested list is left with one child');
306             expect(nestedList.contents()[0].contents()[0].getText()).to.equal('1.1', 'nested list item left alone');
307             expect(item3.contents()[0].getText()).to.equal('1.2', 'third item ok');
308             expect(item4.contents()[0].getText()).to.equal('1.3', 'fourth item ok');
309             expect(item5.contents()[0].getText()).to.equal('2', 'fifth item ok');
310         });
311
312         it('puts extracted items above the list if starting item is the first one - nested case' , function() {
313             var doc = getDocumentFromXML(removeEmptyTextNodes('\
314                 <section>\
315                     <div class="list.items">\
316                         <div class="item">0</div>\
317                         <div class="item">\
318                             <div class="list.items">\
319                                 <div class="item">1.1</div>\
320                                 <div class="item">1.2</div>\
321                                 <div class="item">1.3</div>\
322                             </div>\
323                         </div>\
324                         <div class="item">2</div>\
325                     </div>\
326                 </section>')),
327                 list = doc.root.contents()[0],
328                 nestedList = list.contents()[1].contents()[0],
329                 nestedListItem1 = nestedList.contents()[0],
330                 nestedListItem2 = nestedList.contents()[1];
331
332             doc.extractItems({item1: nestedListItem1, item2: nestedListItem2});
333
334             list = doc.root.contents()[0];
335             var item1 = list.contents()[0],
336                 item2 = list.contents()[1],
337                 item3 = list.contents()[2],
338                 item4 = list.contents()[3],
339                 item5 = list.contents()[4];
340             nestedList = item4.contents()[0];
341
342             expect(list.contents().length).to.equal(5, 'top list has five items');
343             expect(item1.contents()[0].getText()).to.equal('0', 'first item ok');
344             expect(item2.contents()[0].getText()).to.equal('1.1', 'second item ok');
345             expect(item3.contents()[0].getText()).to.equal('1.2', 'third item ok');
346             
347             expect(item4.getClass()).to.equal('item', 'nested list is still wrapped in item element');
348             expect(nestedList.contents().length).to.equal(1, 'nested list is left with one child');
349             expect(nestedList.contents()[0].contents()[0].getText()).to.equal('1.3', 'nested list item left alone');
350             expect(item5.contents()[0].getText()).to.equal('2', 'fifth item ok');
351         });
352
353         it('removes list if all its items are extracted - nested case', function() {
354             var doc = getDocumentFromXML(removeEmptyTextNodes('\
355                 <section>\
356                     <div class="list.items">\
357                         <div class="item">0</div>\
358                         <div class="item">\
359                             <div class="list.items">\
360                                 <div class="item">1.1</div>\
361                                 <div class="item">1.2</div>\
362                             </div>\
363                         </div>\
364                         <div class="item">2</div>\
365                     </div>\
366                 </section>')),
367                 list = doc.root.contents()[0],
368                 nestedList = list.contents()[1].contents()[0],
369                 nestedListItem1 = nestedList.contents()[0],
370                 nestedListItem2 = nestedList.contents()[1];
371
372             doc.extractItems({item1: nestedListItem1, item2: nestedListItem2});
373
374             list = doc.root.contents()[0];
375             var item1 = list.contents()[0],
376                 item2 = list.contents()[1],
377                 item3 = list.contents()[2],
378                 item4 = list.contents()[3];
379
380             expect(list.contents().length).to.equal(4, 'top list has four items');
381             expect(item1.contents()[0].getText()).to.equal('0', 'first item ok');
382             expect(item2.contents()[0].getText()).to.equal('1.1', 'second item ok');
383             expect(item3.contents()[0].getText()).to.equal('1.2', 'third item ok');
384             expect(item4.contents()[0].getText()).to.equal('2', 'fourth item ok');
385         });
386
387         it('extracts items out of outer most list when merge flag is set to false', function() {
388             var doc = getDocumentFromXML(removeEmptyTextNodes('\
389                 <section>\
390                     <div class="list.items">\
391                         <div class="item">0</div>\
392                         <div class="item">\
393                             <div class="list.items">\
394                                 <div class="item">1.1</div>\
395                                 <div class="item">1.2</div>\
396                             </div>\
397                         </div>\
398                         <div class="item">2</div>\
399                     </div>\
400                 </section>')),
401                 section = doc.root,
402                 list = section.contents()[0],
403                 nestedList = list.contents()[1].contents()[0],
404                 nestedListItem = nestedList.contents()[0];
405
406             var test = doc.extractItems({item1: nestedListItem, item2: nestedListItem, merge: false});
407
408             expect(test.sameNode(nestedListItem)).to.equal(true, 'first item returned');
409
410             var sectionContents = section.contents(),
411                 extractedItem = sectionContents[1];
412
413             expect(sectionContents.length).to.equal(3, 'section has three children');
414             expect(sectionContents[0].is('list')).to.equal(true, 'first child is a list');
415
416             expect(extractedItem.getTagName()).to.equal('div', 'extracted item is a wlxml div');
417             expect(extractedItem.getClass()).to.equal('', 'extracted item has no wlxml class');
418             expect(extractedItem.contents()[0].getText()).to.equal('1.1', 'extracted item ok');
419             expect(sectionContents[2].is('list')).to.equal(true, 'second child is a list');
420         });
421     });
422
423 });
424
425 });