Index: trunk/parsers/wikidom/tests/hype/es.ModelNode.test.js |
— | — | @@ -1,107 +0,0 @@ |
2 | | -module( 'Bases' ); |
3 | | - |
4 | | -test( 'es.ModelNode',20, function() { |
5 | | - // Example data (integers) is used for simplicity of testing |
6 | | - var modelNode1 = new es.ModelNode(), |
7 | | - modelNode2 = new es.ModelNode(), |
8 | | - modelNode3 = new es.ModelNode( [new es.ModelNode()] ), |
9 | | - modelNode4 = new es.ModelNode( [new es.ModelNode(), new es.ModelNode()] ); |
10 | | - |
11 | | - // Event triggering is detected using a callback that increments a counter |
12 | | - var updates = 0; |
13 | | - modelNode1.on( 'update', function() { |
14 | | - updates++; |
15 | | - } ); |
16 | | - var attaches = 0; |
17 | | - modelNode2.on( 'afterAttach', function() { |
18 | | - attaches++; |
19 | | - } ); |
20 | | - modelNode3.on( 'afterAttach', function() { |
21 | | - attaches++; |
22 | | - } ); |
23 | | - modelNode4.on( 'afterAttach', function() { |
24 | | - attaches++; |
25 | | - } ); |
26 | | - var detaches = 0; |
27 | | - modelNode2.on( 'afterDetach', function() { |
28 | | - detaches++; |
29 | | - } ); |
30 | | - modelNode3.on( 'afterDetach', function() { |
31 | | - detaches++; |
32 | | - } ); |
33 | | - modelNode4.on( 'afterDetach', function() { |
34 | | - detaches++; |
35 | | - } ); |
36 | | - |
37 | | - /** @covers es.ModelNode.push */ |
38 | | - modelNode1.push( modelNode2 ); |
39 | | - equal( updates, 1, 'push emits update events' ); |
40 | | - equal( modelNode1[0], modelNode2, 'push appends a node' ); |
41 | | - |
42 | | - /** @covers es.ModelNode.attach */ |
43 | | - equal( attaches, 1, 'push attaches added node' ); |
44 | | - |
45 | | - /** @covers es.ModelNode.unshift */ |
46 | | - modelNode1.unshift( modelNode3 ); |
47 | | - equal( updates, 2, 'unshift emits update events' ); |
48 | | - equal( modelNode1[0], modelNode3, 'unshift prepends a node' ); |
49 | | - |
50 | | - /** @covers es.ModelNode.attach */ |
51 | | - equal( attaches, 2, 'unshift attaches added node' ); |
52 | | - |
53 | | - /** @covers es.ModelNode.splice */ |
54 | | - modelNode1.splice( 1, 0, modelNode4 ); |
55 | | - equal( updates, 3, 'splice emits update events' ); |
56 | | - equal( modelNode1[1], modelNode4, 'splice inserts nodes' ); |
57 | | - |
58 | | - /** @covers es.ModelNode.attach */ |
59 | | - equal( attaches, 3, 'splice attaches added nodes' ); |
60 | | - |
61 | | - /** @covers es.ModelNode.reverse */ |
62 | | - modelNode1.reverse(); |
63 | | - equal( updates, 4, 'reverse emits update events' ); |
64 | | - |
65 | | - /** @covers es.ModelNode.sort */ |
66 | | - modelNode1.sort( function( a, b ) { |
67 | | - return a.length < b.length ? -1 : 1; |
68 | | - } ); |
69 | | - equal( updates, 5, 'sort emits update events' ); |
70 | | - deepEqual( |
71 | | - modelNode1.slice( 0 ), |
72 | | - [modelNode2, modelNode3, modelNode4], |
73 | | - 'sort reorderes nodes correctly' |
74 | | - ); |
75 | | - |
76 | | - /** @covers es.ModelNode.pop */ |
77 | | - modelNode1.pop(); |
78 | | - equal( updates, 6, 'pop emits update events' ); |
79 | | - deepEqual( |
80 | | - modelNode1.slice( 0 ), |
81 | | - [modelNode2, modelNode3], |
82 | | - 'pop removes the last child node' |
83 | | - ); |
84 | | - |
85 | | - /** @covers es.ModelNode.detach */ |
86 | | - equal( detaches, 1, 'pop detaches a node' ); |
87 | | - |
88 | | - /** @covers es.ModelNode.shift */ |
89 | | - modelNode1.shift(); |
90 | | - equal( updates, 7, 'es.ModelNode emits update events on shift' ); |
91 | | - deepEqual( |
92 | | - modelNode1.slice( 0 ), |
93 | | - [modelNode3], |
94 | | - 'es.ModelNode removes first Node on shift' |
95 | | - ); |
96 | | - |
97 | | - /** @covers es.ModelNode.detach */ |
98 | | - equal( detaches, 2, 'shift detaches a node' ); |
99 | | - |
100 | | - /** @covers es.ModelNode.getParent */ |
101 | | - strictEqual( modelNode3.getParent(), modelNode1, 'getParent returns the correct reference' ); |
102 | | - |
103 | | - try { |
104 | | - var view = modelNode3.createView(); |
105 | | - } catch ( err ){ |
106 | | - ok( true, 'createView throws an exception when not overridden' ); |
107 | | - } |
108 | | -} ); |
Index: trunk/parsers/wikidom/tests/hype/es.DocumentNode.test.js |
— | — | @@ -1,4 +1,4 @@ |
2 | | -module( 'Bases' ); |
| 2 | +module( 'es/bases' ); |
3 | 3 | |
4 | 4 | function DocumentNodeStub( items, name, size ) { |
5 | 5 | this.name = name; |
— | — | @@ -275,7 +275,7 @@ |
276 | 276 | { 'node': g, 'range': new es.Range( 0, 5 ) } |
277 | 277 | ], |
278 | 278 | 'desc': 'Range starting at the end of a node and ending in the middle of the next node' |
279 | | - }, |
| 279 | + } |
280 | 280 | ]; |
281 | 281 | |
282 | 282 | for ( var i = 0; i < selectNodesTests.length; i++ ) { |
Index: trunk/parsers/wikidom/tests/hype/index.html |
— | — | @@ -16,8 +16,6 @@ |
17 | 17 | <script src="../../lib/hype/es.Range.js"></script> |
18 | 18 | <script src="../../lib/hype/es.Transaction.js"></script> |
19 | 19 | <script src="../../lib/hype/bases/es.EventEmitter.js"></script> |
20 | | - <script src="../../lib/hype/bases/es.ModelNode.js"></script> |
21 | | - <script src="../../lib/hype/bases/es.ViewNode.js"></script> |
22 | 20 | <script src="../../lib/hype/bases/es.DocumentNode.js"></script> |
23 | 21 | <script src="../../lib/hype/bases/es.DocumentModelNode.js"></script> |
24 | 22 | <script src="../../lib/hype/models/es.DocumentModel.js"></script> |
— | — | @@ -28,7 +26,6 @@ |
29 | 27 | <script src="../../lib/hype/models/es.TableModel.js"></script> |
30 | 28 | <script src="../../lib/hype/models/es.TableRowModel.js"></script> |
31 | 29 | <script src="es.test.js"></script> |
32 | | - <script src="es.ModelNode.test.js"></script> |
33 | 30 | <script src="es.DocumentNode.test.js"></script> |
34 | 31 | <script src="es.DocumentModel.test.js"></script> |
35 | 32 | </body> |
Index: trunk/parsers/wikidom/tests/hype/es.DocumentModel.test.js |
— | — | @@ -1,4 +1,4 @@ |
2 | | -module( 'Models' ); |
| 2 | +module( 'es/models' ); |
3 | 3 | |
4 | 4 | /* |
5 | 5 | * Sample plain object (WikiDom). |
— | — | @@ -208,11 +208,30 @@ |
209 | 209 | deepEqual( documentModel.getData(), data, 'Flattening plain objects results in correct data' ); |
210 | 210 | } ); |
211 | 211 | |
212 | | -test( 'es.DocumentModel.slice', 1, function() { |
| 212 | +test( 'es.DocumentModel.getChildren', 1, function() { |
213 | 213 | var documentModel = es.DocumentModel.newFromPlainObject( obj ); |
| 214 | + |
| 215 | + function equalLengths( a, b ) { |
| 216 | + if ( a.length !== b.length ) { |
| 217 | + return false; |
| 218 | + } |
| 219 | + for ( var i = 0; i < a.length; i++ ) { |
| 220 | + if ( a[i].getContentLength() !== b[i].getContentLength() ) { |
| 221 | + console.log( 'mismatched content lengths', a[i], b[i] ); |
| 222 | + return false; |
| 223 | + } |
| 224 | + if ( !equalLengths( a[i].getChildren(), b[i].getChildren() ) ) { |
| 225 | + return false; |
| 226 | + } |
| 227 | + } |
| 228 | + return true; |
| 229 | + } |
214 | 230 | |
215 | 231 | // Test 1 |
216 | | - deepEqual( documentModel.slice( 0 ), tree, 'Nodes in the model tree contain correct lengths' ); |
| 232 | + ok( |
| 233 | + equalLengths( documentModel.getChildren(), tree ), |
| 234 | + 'Nodes in the model tree contain correct lengths' |
| 235 | + ); |
217 | 236 | } ); |
218 | 237 | |
219 | 238 | test( 'es.DocumentModel.getRelativeContentOffset', 7, function() { |
— | — | @@ -263,11 +282,12 @@ |
264 | 283 | } ); |
265 | 284 | |
266 | 285 | test( 'es.DocumentModel.getContent', 6, function() { |
267 | | - var documentModel = es.DocumentModel.newFromPlainObject( obj ); |
| 286 | + var documentModel = es.DocumentModel.newFromPlainObject( obj ), |
| 287 | + childNodes = documentModel.getChildren(); |
268 | 288 | |
269 | 289 | // Test 1 |
270 | 290 | deepEqual( |
271 | | - documentModel[0].getContent( new es.Range( 1, 3 ) ), |
| 291 | + childNodes[0].getContent( new es.Range( 1, 3 ) ), |
272 | 292 | [ |
273 | 293 | ['b', { 'type': 'bold', 'hash': '#bold' }], |
274 | 294 | ['c', { 'type': 'italic', 'hash': '#italic' }] |
— | — | @@ -277,34 +297,34 @@ |
278 | 298 | |
279 | 299 | // Test 2 |
280 | 300 | deepEqual( |
281 | | - documentModel[0].getContent( new es.Range( 0, 2 ) ), |
| 301 | + childNodes[0].getContent( new es.Range( 0, 2 ) ), |
282 | 302 | ['a', ['b', { 'type': 'bold', 'hash': '#bold' }]], |
283 | 303 | 'getContent can return a beginning portion of the content' |
284 | 304 | ); |
285 | 305 | |
286 | 306 | // Test 3 |
287 | 307 | deepEqual( |
288 | | - documentModel[0].getContent( new es.Range( 1, 2 ) ), |
| 308 | + childNodes[0].getContent( new es.Range( 1, 2 ) ), |
289 | 309 | [['b', { 'type': 'bold', 'hash': '#bold' }]], |
290 | 310 | 'getContent can return a middle portion of the content' |
291 | 311 | ); |
292 | 312 | |
293 | 313 | // Test 4 |
294 | 314 | try { |
295 | | - documentModel[0].getContent( new es.Range( -1, 3 ) ); |
| 315 | + childNodes[0].getContent( new es.Range( -1, 3 ) ); |
296 | 316 | } catch ( negativeIndexError ) { |
297 | 317 | ok( true, 'getContent throws exceptions when given a range with start < 0' ); |
298 | 318 | } |
299 | 319 | |
300 | 320 | // Test 5 |
301 | 321 | try { |
302 | | - documentModel[0].getContent( new es.Range( 0, 4 ) ); |
| 322 | + childNodes[0].getContent( new es.Range( 0, 4 ) ); |
303 | 323 | } catch ( outOfRangeError ) { |
304 | 324 | ok( true, 'getContent throws exceptions when given a range with end > length' ); |
305 | 325 | } |
306 | 326 | |
307 | 327 | // Test 6 |
308 | | - deepEqual( documentModel[2].getContent(), ['h'], 'Content can be extracted from nodes' ); |
| 328 | + deepEqual( childNodes[2].getContent(), ['h'], 'Content can be extracted from nodes' ); |
309 | 329 | } ); |
310 | 330 | |
311 | 331 | test( 'es.DocumentModel.getIndexOfAnnotation', 3, function() { |
— | — | @@ -395,21 +415,21 @@ |
396 | 416 | // Test 1 |
397 | 417 | deepEqual( |
398 | 418 | documentModel.prepareElementAttributeChange( 0, 'set', 'test', 1234 ), |
399 | | - [ |
| 419 | + new es.Transaction( [ |
400 | 420 | { 'type': 'attribute', 'method': 'set', 'key': 'test', 'value': 1234 }, |
401 | 421 | { 'type': 'retain', 'length': 28 } |
402 | | - ], |
| 422 | + ] ), |
403 | 423 | 'prepareElementAttributeChange retains data after attribute change for first element' |
404 | 424 | ); |
405 | 425 | |
406 | 426 | // Test 2 |
407 | 427 | deepEqual( |
408 | 428 | documentModel.prepareElementAttributeChange( 5, 'set', 'test', 1234 ), |
409 | | - [ |
| 429 | + new es.Transaction( [ |
410 | 430 | { 'type': 'retain', 'length': 5 }, |
411 | 431 | { 'type': 'attribute', 'method': 'set', 'key': 'test', 'value': 1234 }, |
412 | 432 | { 'type': 'retain', 'length': 23 } |
413 | | - ], |
| 433 | + ] ), |
414 | 434 | 'prepareElementAttributeChange retains data before and after attribute change' |
415 | 435 | ); |
416 | 436 | |
— | — | @@ -440,7 +460,7 @@ |
441 | 461 | // Test 1 |
442 | 462 | deepEqual( |
443 | 463 | documentModel.prepareContentAnnotation( new es.Range( 1, 4 ), 'set', { 'type': 'bold' } ), |
444 | | - [ |
| 464 | + new es.Transaction( [ |
445 | 465 | { 'type': 'retain', 'length': 1 }, |
446 | 466 | { |
447 | 467 | 'type': 'annotate', |
— | — | @@ -470,7 +490,7 @@ |
471 | 491 | 'annotation': { 'type': 'bold', 'hash': '#bold' } |
472 | 492 | }, |
473 | 493 | { 'type': 'retain', 'length': 24 } |
474 | | - ], |
| 494 | + ] ), |
475 | 495 | 'prepareContentAnnotation skips over content that is already set or cleared' |
476 | 496 | ); |
477 | 497 | } ); |
— | — | @@ -481,7 +501,7 @@ |
482 | 502 | // Test 1 |
483 | 503 | deepEqual( |
484 | 504 | documentModel.prepareRemoval( new es.Range( 1, 4 ) ), |
485 | | - [ |
| 505 | + new es.Transaction( [ |
486 | 506 | { 'type': 'retain', 'length': 1 }, |
487 | 507 | { |
488 | 508 | 'type': 'remove', |
— | — | @@ -492,14 +512,14 @@ |
493 | 513 | ] |
494 | 514 | }, |
495 | 515 | { 'type': 'retain', 'length': 24 } |
496 | | - ], |
| 516 | + ] ), |
497 | 517 | 'prepareRemoval includes the content being removed' |
498 | 518 | ); |
499 | 519 | |
500 | 520 | // Test 2 |
501 | 521 | deepEqual( |
502 | 522 | documentModel.prepareRemoval( new es.Range( 15, 18 ) ), |
503 | | - [ |
| 523 | + new es.Transaction( [ |
504 | 524 | { 'type': 'retain', 'length': 15 }, |
505 | 525 | { |
506 | 526 | 'type': 'remove', |
— | — | @@ -510,14 +530,14 @@ |
511 | 531 | ] |
512 | 532 | }, |
513 | 533 | { 'type': 'retain', 'length': 10 } |
514 | | - ], |
| 534 | + ] ), |
515 | 535 | 'prepareRemoval removes entire elements' |
516 | 536 | ); |
517 | 537 | |
518 | 538 | // Test 3 |
519 | 539 | deepEqual( |
520 | 540 | documentModel.prepareRemoval( new es.Range( 17, 19 ) ), |
521 | | - [ |
| 541 | + new es.Transaction( [ |
522 | 542 | { 'type': 'retain', 'length': 17 }, |
523 | 543 | { |
524 | 544 | 'type': 'remove', |
— | — | @@ -527,7 +547,7 @@ |
528 | 548 | ] |
529 | 549 | }, |
530 | 550 | { 'type': 'retain', 'length': 9 } |
531 | | - ], |
| 551 | + ] ), |
532 | 552 | 'prepareRemoval merges two list items' |
533 | 553 | ); |
534 | 554 | } ); |
— | — | @@ -538,11 +558,11 @@ |
539 | 559 | // Test 1 |
540 | 560 | deepEqual( |
541 | 561 | documentModel.prepareInsertion( 1, ['d', 'e', 'f'] ), |
542 | | - [ |
| 562 | + new es.Transaction( [ |
543 | 563 | { 'type': 'retain', 'length': 1 }, |
544 | 564 | { 'type': 'insert', 'data': ['d', 'e', 'f'] }, |
545 | 565 | { 'type': 'retain', 'length': 27 } |
546 | | - ], |
| 566 | + ] ), |
547 | 567 | 'prepareInsertion retains data up to the offset and includes the content being inserted' |
548 | 568 | ); |
549 | 569 | |
— | — | @@ -552,14 +572,14 @@ |
553 | 573 | 5, |
554 | 574 | [{ 'type': 'paragraph' }, 'd', 'e', 'f', { 'type': '/paragraph' }] |
555 | 575 | ), |
556 | | - [ |
| 576 | + new es.Transaction( [ |
557 | 577 | { 'type': 'retain', 'length': 5 }, |
558 | 578 | { |
559 | 579 | 'type': 'insert', |
560 | 580 | 'data': [{ 'type': 'paragraph' }, 'd', 'e', 'f', { 'type': '/paragraph' }] |
561 | 581 | }, |
562 | 582 | { 'type': 'retain', 'length': 23 } |
563 | | - ], |
| 583 | + ] ), |
564 | 584 | 'prepareInsertion inserts a paragraph between two structural elements' |
565 | 585 | ); |
566 | 586 | |
— | — | @@ -569,14 +589,14 @@ |
570 | 590 | 5, |
571 | 591 | ['d', 'e', 'f'] |
572 | 592 | ), |
573 | | - [ |
| 593 | + new es.Transaction( [ |
574 | 594 | { 'type': 'retain', 'length': 5 }, |
575 | 595 | { |
576 | 596 | 'type': 'insert', |
577 | 597 | 'data': [{ 'type': 'paragraph' }, 'd', 'e', 'f', { 'type': '/paragraph' }] |
578 | 598 | }, |
579 | 599 | { 'type': 'retain', 'length': 23 } |
580 | | - ], |
| 600 | + ] ), |
581 | 601 | 'prepareInsertion wraps unstructured content inserted between elements in a paragraph' |
582 | 602 | ); |
583 | 603 | |
— | — | @@ -586,14 +606,14 @@ |
587 | 607 | 5, |
588 | 608 | [{ 'type': 'paragraph' }, 'd', 'e', 'f'] |
589 | 609 | ), |
590 | | - [ |
| 610 | + new es.Transaction( [ |
591 | 611 | { 'type': 'retain', 'length': 5 }, |
592 | 612 | { |
593 | 613 | 'type': 'insert', |
594 | 614 | 'data': [{ 'type': 'paragraph' }, 'd', 'e', 'f', { 'type': '/paragraph' }] |
595 | 615 | }, |
596 | 616 | { 'type': 'retain', 'length': 23 } |
597 | | - ], |
| 617 | + ] ), |
598 | 618 | 'prepareInsertion completes opening elements in inserted content' |
599 | 619 | ); |
600 | 620 | |
— | — | @@ -603,14 +623,14 @@ |
604 | 624 | 2, |
605 | 625 | [ { 'type': 'table' }, { 'type': '/table' } ] |
606 | 626 | ), |
607 | | - [ |
| 627 | + new es.Transaction( [ |
608 | 628 | { 'type': 'retain', 'length': 2 }, |
609 | 629 | { |
610 | 630 | 'type': 'insert', |
611 | 631 | 'data': [ { 'type': '/paragraph' }, { 'type': 'table' }, { 'type': '/table' }, { 'type': 'paragraph' } ] |
612 | 632 | }, |
613 | 633 | { 'type': 'retain', 'length': 26 } |
614 | | - ], |
| 634 | + ] ), |
615 | 635 | 'prepareInsertion splits up paragraph when inserting a table in the middle' |
616 | 636 | ); |
617 | 637 | |
— | — | @@ -620,14 +640,14 @@ |
621 | 641 | 2, |
622 | 642 | [ 'f', 'o', 'o', { 'type': '/paragraph' }, { 'type': 'paragraph' }, 'b', 'a', 'r' ] |
623 | 643 | ), |
624 | | - [ |
| 644 | + new es.Transaction( [ |
625 | 645 | { 'type': 'retain', 'length': 2 }, |
626 | 646 | { |
627 | 647 | 'type': 'insert', |
628 | 648 | 'data': [ 'f', 'o', 'o', { 'type': '/paragraph' }, { 'type': 'paragraph' }, 'b', 'a', 'r' ] |
629 | 649 | }, |
630 | 650 | { 'type': 'retain', 'length': 26 } |
631 | | - ], |
| 651 | + ] ), |
632 | 652 | 'prepareInsertion splits up paragraph when inserting a paragraph closing and opening into a paragraph' |
633 | 653 | ); |
634 | 654 | |
— | — | @@ -637,13 +657,13 @@ |
638 | 658 | 0, |
639 | 659 | [ { 'type': 'paragraph' }, 'f', 'o', 'o', { 'type': '/paragraph' } ] |
640 | 660 | ), |
641 | | - [ |
| 661 | + new es.Transaction( [ |
642 | 662 | { |
643 | 663 | 'type': 'insert', |
644 | 664 | 'data': [ { 'type': 'paragraph' }, 'f', 'o', 'o', { 'type': '/paragraph' } ] |
645 | 665 | }, |
646 | 666 | { 'type': 'retain', 'length': 28 } |
647 | | - ], |
| 667 | + ] ), |
648 | 668 | 'prepareInsertion inserts at the beginning, then retains up to the end' |
649 | 669 | ); |
650 | 670 | |
— | — | @@ -653,13 +673,13 @@ |
654 | 674 | 28, |
655 | 675 | [ { 'type': 'paragraph' }, 'f', 'o', 'o', { 'type': '/paragraph' } ] |
656 | 676 | ), |
657 | | - [ |
| 677 | + new es.Transaction( [ |
658 | 678 | { 'type': 'retain', 'length': 28 }, |
659 | 679 | { |
660 | 680 | 'type': 'insert', |
661 | 681 | 'data': [ { 'type': 'paragraph' }, 'f', 'o', 'o', { 'type': '/paragraph' } ] |
662 | 682 | } |
663 | | - ], |
| 683 | + ] ), |
664 | 684 | 'prepareInsertion inserts at the end' |
665 | 685 | ); |
666 | 686 | |
— | — | @@ -786,7 +806,7 @@ |
787 | 807 | |
788 | 808 | // Test 6 |
789 | 809 | deepEqual( |
790 | | - documentModel[0].getContent(), |
| 810 | + documentModel.getChildren()[0].getContent(), |
791 | 811 | [ |
792 | 812 | 'a', |
793 | 813 | ['b', { 'type': 'bold', 'hash': '#bold' }], |
— | — | @@ -812,7 +832,7 @@ |
813 | 833 | |
814 | 834 | // Test 8 |
815 | 835 | deepEqual( |
816 | | - documentModel[0].getContent(), |
| 836 | + documentModel.getChildren()[0].getContent(), |
817 | 837 | [ |
818 | 838 | 'a', |
819 | 839 | ['b', { 'type': 'bold', 'hash': '#bold' }], |
— | — | @@ -850,3 +870,126 @@ |
851 | 871 | ); |
852 | 872 | |
853 | 873 | } ); |
| 874 | + |
| 875 | +test( 'es.DocumentDocumentModelNode child operations', 20, function() { |
| 876 | + // Example data (integers) is used for simplicity of testing |
| 877 | + var node1 = new es.DocumentModelNode( null ), |
| 878 | + node2 = new es.DocumentModelNode( null ), |
| 879 | + node3 = new es.DocumentModelNode( null, [new es.DocumentModelNode()] ), |
| 880 | + node4 = new es.DocumentModelNode( |
| 881 | + null, |
| 882 | + [new es.DocumentModelNode(), new es.DocumentModelNode()] |
| 883 | + ); |
| 884 | + |
| 885 | + // Event triggering is detected using a callback that increments a counter |
| 886 | + var updates = 0; |
| 887 | + node1.on( 'update', function() { |
| 888 | + updates++; |
| 889 | + } ); |
| 890 | + var attaches = 0; |
| 891 | + node2.on( 'afterAttach', function() { |
| 892 | + attaches++; |
| 893 | + } ); |
| 894 | + node3.on( 'afterAttach', function() { |
| 895 | + attaches++; |
| 896 | + } ); |
| 897 | + node4.on( 'afterAttach', function() { |
| 898 | + attaches++; |
| 899 | + } ); |
| 900 | + var detaches = 0; |
| 901 | + node2.on( 'afterDetach', function() { |
| 902 | + detaches++; |
| 903 | + } ); |
| 904 | + node3.on( 'afterDetach', function() { |
| 905 | + detaches++; |
| 906 | + } ); |
| 907 | + node4.on( 'afterDetach', function() { |
| 908 | + detaches++; |
| 909 | + } ); |
| 910 | + function strictArrayValueEqual( a, b, msg ) { |
| 911 | + if ( a.length !== b.length ) { |
| 912 | + ok( false, msg ); |
| 913 | + return; |
| 914 | + } |
| 915 | + for ( var i = 0; i < a.length; i++ ) { |
| 916 | + if ( a[i] !== b[i] ) { |
| 917 | + ok( false, msg ); |
| 918 | + return; |
| 919 | + } |
| 920 | + } |
| 921 | + ok( true, msg ); |
| 922 | + } |
| 923 | + |
| 924 | + // Test 1 |
| 925 | + node1.push( node2 ); |
| 926 | + equal( updates, 1, 'push emits update events' ); |
| 927 | + strictArrayValueEqual( node1.getChildren(), [node2], 'push appends a node' ); |
| 928 | + |
| 929 | + // Test 2 |
| 930 | + equal( attaches, 1, 'push attaches added node' ); |
| 931 | + |
| 932 | + // Test 3, 4 |
| 933 | + node1.unshift( node3 ); |
| 934 | + equal( updates, 2, 'unshift emits update events' ); |
| 935 | + strictArrayValueEqual( node1.getChildren(), [node3, node2], 'unshift prepends a node' ); |
| 936 | + |
| 937 | + // Test 5 |
| 938 | + equal( attaches, 2, 'unshift attaches added node' ); |
| 939 | + |
| 940 | + // Test 6, 7 |
| 941 | + node1.splice( 1, 0, node4 ); |
| 942 | + equal( updates, 3, 'splice emits update events' ); |
| 943 | + strictArrayValueEqual( node1.getChildren(), [node3, node4, node2], 'splice inserts nodes' ); |
| 944 | + |
| 945 | + // Test 8 |
| 946 | + equal( attaches, 3, 'splice attaches added nodes' ); |
| 947 | + |
| 948 | + // Test 9 |
| 949 | + node1.reverse(); |
| 950 | + equal( updates, 4, 'reverse emits update events' ); |
| 951 | + |
| 952 | + // Test 10, 11 |
| 953 | + node1.sort( function( a, b ) { |
| 954 | + return a.getChildren().length < b.getChildren().length ? -1 : 1; |
| 955 | + } ); |
| 956 | + equal( updates, 5, 'sort emits update events' ); |
| 957 | + strictArrayValueEqual( |
| 958 | + node1.getChildren(), |
| 959 | + [node2, node3, node4], |
| 960 | + 'sort reorderes nodes correctly' |
| 961 | + ); |
| 962 | + |
| 963 | + // Test 12, 13 |
| 964 | + node1.pop(); |
| 965 | + equal( updates, 6, 'pop emits update events' ); |
| 966 | + strictArrayValueEqual( |
| 967 | + node1.getChildren(), |
| 968 | + [node2, node3], |
| 969 | + 'pop removes the last child node' |
| 970 | + ); |
| 971 | + |
| 972 | + // Test 14 |
| 973 | + equal( detaches, 1, 'pop detaches a node' ); |
| 974 | + |
| 975 | + // Test 15, 16 |
| 976 | + node1.shift(); |
| 977 | + equal( updates, 7, 'es.ModelNode emits update events on shift' ); |
| 978 | + strictArrayValueEqual( |
| 979 | + node1.getChildren(), |
| 980 | + [node3], |
| 981 | + 'es.ModelNode removes first Node on shift' |
| 982 | + ); |
| 983 | + |
| 984 | + // Test 17 |
| 985 | + equal( detaches, 2, 'shift detaches a node' ); |
| 986 | + |
| 987 | + // Test 18 |
| 988 | + strictEqual( node3.getParent(), node1, 'getParent returns the correct reference' ); |
| 989 | + |
| 990 | + // Test 19 |
| 991 | + try { |
| 992 | + var view = node3.createView(); |
| 993 | + } catch ( err ){ |
| 994 | + ok( true, 'createView throws an exception when not overridden' ); |
| 995 | + } |
| 996 | +} ); |
Index: trunk/parsers/wikidom/lib/hype/models/es.DocumentModel.js |
— | — | @@ -6,24 +6,23 @@ |
7 | 7 | * |
8 | 8 | * @class |
9 | 9 | * @constructor |
| 10 | + * @extends {es.DocumentModelNode} |
10 | 11 | * @param {Array} data Model data to initialize with, such as data from es.DocumentModel.getData() |
11 | 12 | * @param {Object} attributes Document attributes |
12 | 13 | */ |
13 | 14 | es.DocumentModel = function( data, attributes ) { |
14 | | - // Extension |
15 | | - var node = es.extendObject( new es.DocumentModelNode( null, length ), this ); |
| 15 | + // Inheritance |
| 16 | + es.DocumentModelNode.call( this, null, data ? data.length : 0 ); |
16 | 17 | |
17 | 18 | // Properties |
18 | | - node.data = es.isArray( data ) ? data : []; |
19 | | - node.attributes = es.isPlainObject( attributes ) ? attributes : {}; |
| 19 | + this.data = es.isArray( data ) ? data : []; |
| 20 | + this.attributes = es.isPlainObject( attributes ) ? attributes : {}; |
20 | 21 | |
21 | 22 | // Auto-generate model tree |
22 | | - var nodes = es.DocumentModel.createNodesFromData( node.data ); |
| 23 | + var nodes = es.DocumentModel.createNodesFromData( this.data ); |
23 | 24 | for ( var i = 0; i < nodes.length; i++ ) { |
24 | | - node.push( nodes[i] ); |
| 25 | + this.push( nodes[i] ); |
25 | 26 | } |
26 | | - |
27 | | - return node; |
28 | 27 | }; |
29 | 28 | |
30 | 29 | /* Static Members */ |
— | — | @@ -313,7 +312,7 @@ |
314 | 313 | i--; |
315 | 314 | } |
316 | 315 | } |
317 | | - return currentNode.slice(); |
| 316 | + return currentNode.getChildren().slice( 0 ); |
318 | 317 | }; |
319 | 318 | |
320 | 319 | /** |
— | — | @@ -1107,15 +1106,16 @@ |
1108 | 1107 | */ |
1109 | 1108 | es.DocumentModel.prototype.commit = function( transaction ) { |
1110 | 1109 | var state = { |
1111 | | - 'data': this.data, |
1112 | | - 'tree': this, |
1113 | | - 'cursor': 0, |
1114 | | - 'set': [], |
1115 | | - 'clear': [], |
1116 | | - 'rebuild': [] |
1117 | | - }; |
1118 | | - for ( var i = 0, length = transaction.length; i < length; i++ ) { |
1119 | | - var operation = transaction[i]; |
| 1110 | + 'data': this.data, |
| 1111 | + 'tree': this, |
| 1112 | + 'cursor': 0, |
| 1113 | + 'set': [], |
| 1114 | + 'clear': [], |
| 1115 | + 'rebuild': [] |
| 1116 | + }, |
| 1117 | + operations = transaction.getOperations(); |
| 1118 | + for ( var i = 0, length = operations.length; i < length; i++ ) { |
| 1119 | + var operation = operations[i]; |
1120 | 1120 | if ( operation.type in es.DocumentModel.operations ) { |
1121 | 1121 | es.DocumentModel.operations[operation.type].commit.call( state, operation ); |
1122 | 1122 | } else { |
— | — | @@ -1133,15 +1133,16 @@ |
1134 | 1134 | */ |
1135 | 1135 | es.DocumentModel.prototype.rollback = function( transaction ) { |
1136 | 1136 | var state = { |
1137 | | - 'data': this.data, |
1138 | | - 'tree': this, |
1139 | | - 'cursor': 0, |
1140 | | - 'set': [], |
1141 | | - 'clear': [], |
1142 | | - 'rebuild': [] |
1143 | | - }; |
1144 | | - for ( var i = 0, length = transaction.length; i < length; i++ ) { |
1145 | | - var operation = transaction[i]; |
| 1137 | + 'data': this.data, |
| 1138 | + 'tree': this, |
| 1139 | + 'cursor': 0, |
| 1140 | + 'set': [], |
| 1141 | + 'clear': [], |
| 1142 | + 'rebuild': [] |
| 1143 | + }, |
| 1144 | + operations = transaction.getOperations(); |
| 1145 | + for ( var i = 0, length = operations.length; i < length; i++ ) { |
| 1146 | + var operation = operations[i]; |
1146 | 1147 | if ( operation.type in es.DocumentModel.operations ) { |
1147 | 1148 | es.DocumentModel.operations[operation.type].rollback.call( state, operation ); |
1148 | 1149 | } else { |
Index: trunk/parsers/wikidom/lib/hype/models/es.HeadingModel.js |
— | — | @@ -3,10 +3,13 @@ |
4 | 4 | * |
5 | 5 | * @class |
6 | 6 | * @constructor |
| 7 | + * @extends {es.DocumentModelNode} |
| 8 | + * @param {Object} element Document data element of this node |
| 9 | + * @param {Integer} length Length of document data element |
7 | 10 | */ |
8 | 11 | es.HeadingModel = function( element, length ) { |
9 | | - // Extension |
10 | | - return es.extendObject( new es.DocumentModelNode( element, length ), this ); |
| 12 | + // Inheritance |
| 13 | + es.DocumentModelNode.call( this, element, length ); |
11 | 14 | }; |
12 | 15 | |
13 | 16 | /* Methods */ |
— | — | @@ -29,3 +32,7 @@ |
30 | 33 | 'parents': null, |
31 | 34 | 'children': [] |
32 | 35 | }; |
| 36 | + |
| 37 | +/* Inheritance */ |
| 38 | + |
| 39 | +es.extendClass( es.HeadingModel, es.DocumentModelNode ); |
Index: trunk/parsers/wikidom/lib/hype/models/es.TableRowModel.js |
— | — | @@ -3,10 +3,13 @@ |
4 | 4 | * |
5 | 5 | * @class |
6 | 6 | * @constructor |
| 7 | + * @extends {es.DocumentModelNode} |
| 8 | + * @param {Object} element Document data element of this node |
| 9 | + * @param {es.DocumentModelNode[]} contents List of child nodes to initially add |
7 | 10 | */ |
8 | | -es.TableRowModel = function( element, length ) { |
9 | | - // Extension |
10 | | - return es.extendObject( new es.DocumentModelNode( element, length ), this ); |
| 11 | +es.TableRowModel = function( element, contents ) { |
| 12 | + // Inheritance |
| 13 | + es.DocumentModelNode.call( this, element, contents ); |
11 | 14 | }; |
12 | 15 | |
13 | 16 | /* Methods */ |
— | — | @@ -29,3 +32,7 @@ |
30 | 33 | 'parents': ['table'], |
31 | 34 | 'children': ['tableCell'] |
32 | 35 | }; |
| 36 | + |
| 37 | +/* Inheritance */ |
| 38 | + |
| 39 | +es.extendClass( es.TableRowModel, es.DocumentModelNode ); |
Index: trunk/parsers/wikidom/lib/hype/models/es.ParagraphModel.js |
— | — | @@ -3,10 +3,13 @@ |
4 | 4 | * |
5 | 5 | * @class |
6 | 6 | * @constructor |
| 7 | + * @extends {es.DocumentModelNode} |
| 8 | + * @param {Object} element Document data element of this node |
| 9 | + * @param {Integer} length Length of document data element |
7 | 10 | */ |
8 | 11 | es.ParagraphModel = function( element, length ) { |
9 | | - // Extension |
10 | | - return es.extendObject( new es.DocumentModelNode( element, length ), this ); |
| 12 | + // Inheritance |
| 13 | + es.DocumentModelNode.call( this, element, length ); |
11 | 14 | }; |
12 | 15 | |
13 | 16 | /* Methods */ |
— | — | @@ -29,3 +32,7 @@ |
30 | 33 | 'parents': null, |
31 | 34 | 'children': [] |
32 | 35 | }; |
| 36 | + |
| 37 | +/* Inheritance */ |
| 38 | + |
| 39 | +es.extendClass( es.ParagraphModel, es.DocumentModelNode ); |
Index: trunk/parsers/wikidom/lib/hype/models/es.TableCellModel.js |
— | — | @@ -3,10 +3,13 @@ |
4 | 4 | * |
5 | 5 | * @class |
6 | 6 | * @constructor |
| 7 | + * @extends {es.DocumentModelNode} |
| 8 | + * @param {Object} element Document data element of this node |
| 9 | + * @param {es.DocumentModelNode[]} contents List of child nodes to initially add |
7 | 10 | */ |
8 | | -es.TableCellModel = function( element, length ) { |
9 | | - // Extension |
10 | | - return es.extendObject( new es.DocumentModelNode( element, length ), this ); |
| 11 | +es.TableCellModel = function( element, contents ) { |
| 12 | + // Inheritance |
| 13 | + es.DocumentModelNode.call( this, element, contents ); |
11 | 14 | }; |
12 | 15 | |
13 | 16 | /* Methods */ |
— | — | @@ -29,3 +32,7 @@ |
30 | 33 | 'parents': ['tableRow'], |
31 | 34 | 'children': null |
32 | 35 | }; |
| 36 | + |
| 37 | +/* Inheritance */ |
| 38 | + |
| 39 | +es.extendClass( es.TableCellModel, es.DocumentModelNode ); |
Index: trunk/parsers/wikidom/lib/hype/models/es.TableModel.js |
— | — | @@ -3,10 +3,13 @@ |
4 | 4 | * |
5 | 5 | * @class |
6 | 6 | * @constructor |
| 7 | + * @extends {es.DocumentModelNode} |
| 8 | + * @param {Object} element Document data element of this node |
| 9 | + * @param {es.DocumentModelNode[]} contents List of child nodes to initially add |
7 | 10 | */ |
8 | | -es.TableModel = function( element, length ) { |
9 | | - // Extension |
10 | | - return es.extendObject( new es.DocumentModelNode( element, length ), this ); |
| 11 | +es.TableModel = function( element, contents ) { |
| 12 | + // Inheritance |
| 13 | + es.DocumentModelNode.call( this, element, contents ); |
11 | 14 | }; |
12 | 15 | |
13 | 16 | /* Methods */ |
— | — | @@ -29,3 +32,7 @@ |
30 | 33 | 'parents': null, |
31 | 34 | 'children': ['tableRow'] |
32 | 35 | }; |
| 36 | + |
| 37 | +/* Inheritance */ |
| 38 | + |
| 39 | +es.extendClass( es.TableModel, es.DocumentModelNode ); |
Index: trunk/parsers/wikidom/lib/hype/models/es.SurfaceModel.js |
— | — | @@ -1,7 +1,16 @@ |
2 | | -es.SurfaceModel = function( doc) { |
| 2 | +/** |
| 3 | + * Creates an es.SurfaceModel object. |
| 4 | + * |
| 5 | + * @class |
| 6 | + * @constructor |
| 7 | + * @param {es.DocumentModel} doc Document model to create surface for |
| 8 | + */ |
| 9 | +es.SurfaceModel = function( doc ) { |
3 | 10 | this.doc = doc; |
4 | 11 | }; |
5 | 12 | |
| 13 | +/* Methods */ |
| 14 | + |
6 | 15 | es.SurfaceModel.prototype.getDocument = function() { |
7 | 16 | return this.doc; |
8 | | -}; |
\ No newline at end of file |
| 17 | +}; |
Index: trunk/parsers/wikidom/lib/hype/models/es.ListItemModel.js |
— | — | @@ -3,10 +3,13 @@ |
4 | 4 | * |
5 | 5 | * @class |
6 | 6 | * @constructor |
| 7 | + * @extends {es.DocumentModelNode} |
| 8 | + * @param {Object} element Document data element of this node |
| 9 | + * @param {Integer} length Length of document data element |
7 | 10 | */ |
8 | 11 | es.ListItemModel = function( element, length ) { |
9 | | - // Extension |
10 | | - return es.extendObject( new es.DocumentModelNode( element, length ), this ); |
| 12 | + // Inheritance |
| 13 | + es.DocumentModelNode.call( this, element, length ); |
11 | 14 | }; |
12 | 15 | |
13 | 16 | /* Methods */ |
— | — | @@ -29,3 +32,7 @@ |
30 | 33 | 'parents': ['list'], |
31 | 34 | 'children': [] |
32 | 35 | }; |
| 36 | + |
| 37 | +/* Inheritance */ |
| 38 | + |
| 39 | +es.extendClass( es.ListItemModel, es.DocumentModelNode ); |
Index: trunk/parsers/wikidom/lib/hype/models/es.ListModel.js |
— | — | @@ -3,10 +3,13 @@ |
4 | 4 | * |
5 | 5 | * @class |
6 | 6 | * @constructor |
| 7 | + * @extends {es.DocumentModelNode} |
| 8 | + * @param {Object} element Document data element of this node |
| 9 | + * @param {es.DocumentModelNode[]} contents List of child nodes to initially add |
7 | 10 | */ |
8 | | -es.ListModel = function( element, length ) { |
9 | | - // Extension |
10 | | - return es.extendObject( new es.DocumentModelNode( element, length ), this ); |
| 11 | +es.ListModel = function( element, contents ) { |
| 12 | + // Inheritance |
| 13 | + es.DocumentModelNode.call( this, element, contents ); |
11 | 14 | }; |
12 | 15 | |
13 | 16 | /* Methods */ |
— | — | @@ -29,3 +32,7 @@ |
30 | 33 | 'parents': null, |
31 | 34 | 'children': ['listItem'] |
32 | 35 | }; |
| 36 | + |
| 37 | +/* Inheritance */ |
| 38 | + |
| 39 | +es.extendClass( es.ListModel, es.DocumentModelNode ); |
Index: trunk/parsers/wikidom/lib/hype/es.Transaction.js |
— | — | @@ -2,38 +2,42 @@ |
3 | 3 | * Creates an es.Transaction object. |
4 | 4 | * |
5 | 5 | * @class |
6 | | - * @extends {Array} |
7 | 6 | * @constructor |
| 7 | + * @param {Object[]} operations List of operations |
8 | 8 | */ |
9 | | -es.Transaction = function() { |
10 | | - return es.extendObject( [], this ); |
| 9 | +es.Transaction = function( operations ) { |
| 10 | + this.operations = es.isArray( operations ) ? operations : []; |
11 | 11 | }; |
12 | 12 | |
13 | 13 | /* Methods */ |
14 | 14 | |
| 15 | +es.Transaction.prototype.getOperations = function() { |
| 16 | + return this.operations; |
| 17 | +}; |
| 18 | + |
15 | 19 | es.Transaction.prototype.pushRetain = function( length ) { |
16 | | - this.push( { |
| 20 | + this.operations.push( { |
17 | 21 | 'type': 'retain', |
18 | 22 | 'length': length |
19 | 23 | } ); |
20 | 24 | }; |
21 | 25 | |
22 | 26 | es.Transaction.prototype.pushInsert = function( content ) { |
23 | | - this.push( { |
| 27 | + this.operations.push( { |
24 | 28 | 'type': 'insert', |
25 | 29 | 'data': content |
26 | 30 | } ); |
27 | 31 | }; |
28 | 32 | |
29 | 33 | es.Transaction.prototype.pushRemove = function( data ) { |
30 | | - this.push( { |
| 34 | + this.operations.push( { |
31 | 35 | 'type': 'remove', |
32 | 36 | 'data': data |
33 | 37 | } ); |
34 | 38 | }; |
35 | 39 | |
36 | 40 | es.Transaction.prototype.pushChangeElementAttribute = function( method, key, value ) { |
37 | | - this.push( { |
| 41 | + this.operations.push( { |
38 | 42 | 'type': 'attribute', |
39 | 43 | 'method': method, |
40 | 44 | 'key': key, |
— | — | @@ -42,7 +46,7 @@ |
43 | 47 | }; |
44 | 48 | |
45 | 49 | es.Transaction.prototype.pushStartAnnotating = function( method, annotation ) { |
46 | | - this.push( { |
| 50 | + this.operations.push( { |
47 | 51 | 'type': 'annotate', |
48 | 52 | 'method': method, |
49 | 53 | 'bias': 'start', |
— | — | @@ -51,7 +55,7 @@ |
52 | 56 | }; |
53 | 57 | |
54 | 58 | es.Transaction.prototype.pushStopAnnotating = function( method, annotation ) { |
55 | | - this.push( { |
| 59 | + this.operations.push( { |
56 | 60 | 'type': 'annotate', |
57 | 61 | 'method': method, |
58 | 62 | 'bias': 'stop', |
Index: trunk/parsers/wikidom/lib/hype/bases/es.ViewNode.js |
— | — | @@ -1,188 +0,0 @@ |
2 | | -/** |
3 | | - * Creates an es.ViewNode object. |
4 | | - * |
5 | | - * es.ViewNode extends native JavaScript Array objects, without changing Array.prototype by |
6 | | - * dynamically extending an array literal with the methods of es.ViewNode. |
7 | | - * |
8 | | - * View nodes follow the operations performed on model nodes and keep elements in the DOM in sync. |
9 | | - * |
10 | | - * Child objects must extend es.ViewNode. |
11 | | - * |
12 | | - * @class |
13 | | - * @constructor |
14 | | - * @extends {es.EventEmitter} |
15 | | - * @param model {es.ModelNode} Model to observe |
16 | | - * @param {jQuery} [$element=New DIV element] Element to use as a container |
17 | | - * @property {es.ModelItem} model Model being observed |
18 | | - * @property {jQuery} $ Container element |
19 | | - */ |
20 | | -es.ViewNode = function( model, $element ) { |
21 | | - // Inheritance |
22 | | - es.EventEmitter.call( this ); |
23 | | - |
24 | | - // Extending this class will initialize it without any arguments, exiting early if no model |
25 | | - // was given will prevent clogging up subclass prototypes with array methods |
26 | | - if ( !model ) { |
27 | | - return this; |
28 | | - } |
29 | | - |
30 | | - // Extension |
31 | | - var node = es.extendObject( [], this ); |
32 | | - |
33 | | - // Properties |
34 | | - node.model = model; |
35 | | - node.$ = $element || $( '<div/>' ); |
36 | | - |
37 | | - // Reusable function for passing update events upstream |
38 | | - node.emitUpdate = function() { |
39 | | - node.emit( 'update' ); |
40 | | - }; |
41 | | - |
42 | | - // Append existing model children |
43 | | - for ( var i = 0; i < model.length; i++ ) { |
44 | | - node.onAfterPush( model[i] ); |
45 | | - } |
46 | | - |
47 | | - // Observe and mimic changes on model |
48 | | - node.addListenerMethods( node, { |
49 | | - 'afterPush': 'onAfterPush', |
50 | | - 'afterUnshift': 'onAfterUnshift', |
51 | | - 'afterPop': 'onAfterPop', |
52 | | - 'afterShift': 'onAfterShift', |
53 | | - 'afterSplice': 'onAfterSplice', |
54 | | - 'afterSort': 'onAfterSort', |
55 | | - 'afterReverse': 'onAfterReverse' |
56 | | - } ); |
57 | | - |
58 | | - return node; |
59 | | -}; |
60 | | - |
61 | | -es.ViewNode.prototype.onAfterPush = function( childModel ) { |
62 | | - var childView = childModel.createView(); |
63 | | - this.emit( 'beforePush', childView ); |
64 | | - childView.attach( this ); |
65 | | - childView.on( 'update', this.emitUpdate ); |
66 | | - this.push( childView ); |
67 | | - this.$.append( childView.$ ); |
68 | | - this.emit( 'afterPush', childView ); |
69 | | - this.emit( 'update' ); |
70 | | -}; |
71 | | - |
72 | | -es.ViewNode.prototype.onAfterUnshift = function( childModel ) { |
73 | | - var childView = childModel.createView(); |
74 | | - this.emit( 'beforeUnshift', childView ); |
75 | | - childView.attach( this ); |
76 | | - childView.on( 'update', this.emitUpdate ); |
77 | | - this.unshift( childView ); |
78 | | - this.$.prepend( childView.$ ); |
79 | | - this.emit( 'afterUnshift', childView ); |
80 | | - this.emit( 'update' ); |
81 | | -}; |
82 | | - |
83 | | -es.ViewNode.prototype.onAfterPop = function() { |
84 | | - this.emit( 'beforePop' ); |
85 | | - var childView = this.pop(); |
86 | | - childView.detach(); |
87 | | - childView.removeEventListener( 'update', this.emitUpdate ); |
88 | | - childView.$.detach(); |
89 | | - this.emit( 'afterPop' ); |
90 | | - this.emit( 'update' ); |
91 | | -}; |
92 | | - |
93 | | -es.ViewNode.prototype.onAfterShift = function() { |
94 | | - this.emit( 'beforeShift' ); |
95 | | - var childView = this.shift(); |
96 | | - childView.detach(); |
97 | | - childView.removeEventListener( 'update', this.emitUpdate ); |
98 | | - childView.$.detach(); |
99 | | - this.emit( 'afterShift' ); |
100 | | - this.emit( 'update' ); |
101 | | -}; |
102 | | - |
103 | | -es.ViewNode.prototype.onAfterSplice = function( index, howmany ) { |
104 | | - var args = Array.prototype.slice( arguments, 0 ); |
105 | | - this.emit.apply( ['beforeSplice'].concat( args ) ); |
106 | | - this.$.children() |
107 | | - // Removals |
108 | | - .slice( index, index + howmany ).detach() |
109 | | - // Insertions |
110 | | - .get( index ).after( $.map( args.slice( 2 ), function( childView ) { |
111 | | - return childView.$; |
112 | | - } ) ); |
113 | | - this.emit.apply( ['afterSplice'].concat( args ) ); |
114 | | - this.emit( 'update' ); |
115 | | -}; |
116 | | - |
117 | | -es.ViewNode.prototype.onAfterSort = function() { |
118 | | - this.emit( 'beforeSort' ); |
119 | | - for ( var i = 0; i < this.model.length; i++ ) { |
120 | | - for ( var j = 0; j < this.length; j++ ) { |
121 | | - if ( this[j].getModel() === this.model[i] ) { |
122 | | - var childView = this[j]; |
123 | | - this.splice( j, 1 ); |
124 | | - this.push( childView ); |
125 | | - this.$.append( childView.$ ); |
126 | | - } |
127 | | - } |
128 | | - } |
129 | | - this.emit( 'afterSort' ); |
130 | | - this.emit( 'update' ); |
131 | | -}; |
132 | | - |
133 | | -es.ViewNode.prototype.onAfterReverse = function() { |
134 | | - this.emit( 'beforeReverse' ); |
135 | | - this.reverse(); |
136 | | - this.$.children().each( function() { |
137 | | - $(this).prependTo( $(this).parent() ); |
138 | | - } ); |
139 | | - this.emit( 'afterReverse' ); |
140 | | - this.emit( 'update' ); |
141 | | -}; |
142 | | - |
143 | | -/** |
144 | | - * Gets a reference to the model this node observes. |
145 | | - * |
146 | | - * @method |
147 | | - * @returns {es.ModelNode} Reference to the model this node observes |
148 | | - */ |
149 | | -es.ViewNode.prototype.getModel = function() { |
150 | | - return this.model; |
151 | | -}; |
152 | | - |
153 | | -/** |
154 | | - * Gets a reference to this node's parent. |
155 | | - * |
156 | | - * @method |
157 | | - * @returns {es.ViewNode} Reference to this node's parent |
158 | | - */ |
159 | | -es.ViewNode.prototype.getParent = function() { |
160 | | - return this.parent; |
161 | | -}; |
162 | | - |
163 | | -/** |
164 | | - * Attaches node as a child to another node. |
165 | | - * |
166 | | - * @method |
167 | | - * @param {es.ViewNode} parent Node to attach to |
168 | | - * @emits attach (parent) |
169 | | - */ |
170 | | -es.ViewNode.prototype.attach = function( parent ) { |
171 | | - this.parent = parent; |
172 | | - this.emit( 'attach', parent ); |
173 | | -}; |
174 | | - |
175 | | -/** |
176 | | - * Detaches node from it's parent. |
177 | | - * |
178 | | - * @method |
179 | | - * @emits detach (parent) |
180 | | - */ |
181 | | -es.ViewNode.prototype.detach = function() { |
182 | | - var parent = this.parent; |
183 | | - this.parent = null; |
184 | | - this.emit( 'detach', parent ); |
185 | | -}; |
186 | | - |
187 | | -/* Inheritance */ |
188 | | - |
189 | | -es.extendClass( es.ViewNode, es.EventEmitter ); |
Index: trunk/parsers/wikidom/lib/hype/bases/es.ModelNode.js |
— | — | @@ -1,274 +0,0 @@ |
2 | | -/** |
3 | | - * Creates an es.ModelNode object. |
4 | | - * |
5 | | - * es.ModelNode extends native JavaScript Array objects, without changing Array.prototype by |
6 | | - * dynamically extending an array literal with the methods of es.ModelNode. |
7 | | - * |
8 | | - * Child objects must extend es.ModelNode. |
9 | | - * |
10 | | - * @class |
11 | | - * @constructor |
12 | | - * @extends {Array} |
13 | | - * @extends {es.EventEmitter} |
14 | | - */ |
15 | | -es.ModelNode = function( children ) { |
16 | | - // Inheritance |
17 | | - es.EventEmitter.call( this ); |
18 | | - |
19 | | - // Extension |
20 | | - var node = es.extendObject( [], this ); |
21 | | - |
22 | | - // Reusable function for passing update events upstream |
23 | | - node.emitUpdate = function() { |
24 | | - node.emit( 'update' ); |
25 | | - }; |
26 | | - |
27 | | - // Properties |
28 | | - node.parent = null; |
29 | | - node.root = node; |
30 | | - |
31 | | - // Children |
32 | | - if ( es.isArray( children ) ) { |
33 | | - for ( var i = 0; i < children.length; i++ ) { |
34 | | - node.push( children[i] ); |
35 | | - children[i].parent = node; |
36 | | - } |
37 | | - } |
38 | | - |
39 | | - return node; |
40 | | -}; |
41 | | - |
42 | | -/* Methods */ |
43 | | - |
44 | | -/** |
45 | | - * Adds a node to the end of this node's children. |
46 | | - * |
47 | | - * @method |
48 | | - * @param {es.ModelItem} childModel Item to add |
49 | | - * @returns {Integer} New number of children |
50 | | - * @emits beforePush (childModel) |
51 | | - * @emits afterPush (childModel) |
52 | | - * @emits update |
53 | | - */ |
54 | | -es.ModelNode.prototype.push = function( childModel ) { |
55 | | - this.emit( 'beforePush', childModel ); |
56 | | - childModel.attach( this ); |
57 | | - childModel.on( 'update', this.emitUpdate ); |
58 | | - Array.prototype.push.call( this, childModel ); |
59 | | - this.emit( 'afterPush', childModel ); |
60 | | - this.emit( 'update' ); |
61 | | - return this.length; |
62 | | -}; |
63 | | - |
64 | | -/** |
65 | | - * Adds a node to the beginning of this node's children. |
66 | | - * |
67 | | - * @method |
68 | | - * @param {es.ModelItem} childModel Item to add |
69 | | - * @returns {Integer} New number of children |
70 | | - * @emits beforeUnshift (childModel) |
71 | | - * @emits afterUnshift (childModel) |
72 | | - * @emits update |
73 | | - */ |
74 | | -es.ModelNode.prototype.unshift = function( childModel ) { |
75 | | - this.emit( 'beforeUnshift', childModel ); |
76 | | - childModel.attach( this ); |
77 | | - childModel.on( 'update', this.emitUpdate ); |
78 | | - Array.prototype.unshift.call( this, childModel ); |
79 | | - this.emit( 'afterUnshift', childModel ); |
80 | | - this.emit( 'update' ); |
81 | | - return this.length; |
82 | | -}; |
83 | | - |
84 | | -/** |
85 | | - * Removes a node from the end of this node's children |
86 | | - * |
87 | | - * @method |
88 | | - * @returns {Integer} Removed childModel |
89 | | - * @emits beforePop |
90 | | - * @emits afterPop |
91 | | - * @emits update |
92 | | - */ |
93 | | -es.ModelNode.prototype.pop = function() { |
94 | | - if ( this.length ) { |
95 | | - this.emit( 'beforePop' ); |
96 | | - var childModel = this[this.length - 1]; |
97 | | - childModel.detach(); |
98 | | - childModel.removeListener( 'update', this.emitUpdate ); |
99 | | - Array.prototype.pop.call( this ); |
100 | | - this.emit( 'afterPop' ); |
101 | | - this.emit( 'update' ); |
102 | | - return childModel; |
103 | | - } |
104 | | -}; |
105 | | - |
106 | | -/** |
107 | | - * Removes a node from the beginning of this node's children |
108 | | - * |
109 | | - * @method |
110 | | - * @returns {Integer} Removed childModel |
111 | | - * @emits beforeShift |
112 | | - * @emits afterShift |
113 | | - * @emits update |
114 | | - */ |
115 | | -es.ModelNode.prototype.shift = function() { |
116 | | - if ( this.length ) { |
117 | | - this.emit( 'beforeShift' ); |
118 | | - var childModel = this[0]; |
119 | | - childModel.detach(); |
120 | | - childModel.removeListener( 'update', this.emitUpdate ); |
121 | | - Array.prototype.shift.call( this ); |
122 | | - this.emit( 'afterShift' ); |
123 | | - this.emit( 'update' ); |
124 | | - return childModel; |
125 | | - } |
126 | | -}; |
127 | | - |
128 | | -/** |
129 | | - * Adds and removes nodes from this node's children. |
130 | | - * |
131 | | - * @method |
132 | | - * @param {Integer} index Index to remove and or insert nodes at |
133 | | - * @param {Integer} howmany Number of nodes to remove |
134 | | - * @param {es.ModelItem} [...] Variadic list of nodes to insert |
135 | | - * @returns {es.ModelItem[]} Removed nodes |
136 | | - * @emits beforeSplice (index, howmany, [...]) |
137 | | - * @emits afterSplice (index, howmany, [...]) |
138 | | - * @emits update |
139 | | - */ |
140 | | -es.ModelNode.prototype.splice = function( index, howmany ) { |
141 | | - var i, |
142 | | - length, |
143 | | - args = Array.prototype.slice.call( arguments, 0 ); |
144 | | - this.emit.apply( this, ['beforeSplice'].concat( args ) ); |
145 | | - if ( args.length >= 3 ) { |
146 | | - for ( i = 2, length = args.length; i < length; i++ ) { |
147 | | - args[i].attach( this ); |
148 | | - } |
149 | | - } |
150 | | - var removed = Array.prototype.splice.apply( this, args ); |
151 | | - for ( i = 0, length = removed.length; i < length; i++ ) { |
152 | | - removed[i].detach(); |
153 | | - removed[i].removeListener( 'update', this.emitUpdate ); |
154 | | - } |
155 | | - this.emit.apply( this, ['afterSplice'].concat( args ) ); |
156 | | - this.emit( 'update' ); |
157 | | - return removed; |
158 | | -}; |
159 | | - |
160 | | -/** |
161 | | - * Sorts this node's children. |
162 | | - * |
163 | | - * @method |
164 | | - * @param {Function} sortfunc Function to use when sorting |
165 | | - * @emits beforeSort (sortfunc) |
166 | | - * @emits afterSort (sortfunc) |
167 | | - * @emits update |
168 | | - */ |
169 | | -es.ModelNode.prototype.sort = function( sortfunc ) { |
170 | | - this.emit( 'beforeSort', sortfunc ); |
171 | | - Array.prototype.sort.call( this ); |
172 | | - this.emit( 'afterSort', sortfunc ); |
173 | | - this.emit( 'update' ); |
174 | | -}; |
175 | | - |
176 | | -/** |
177 | | - * Reverses the order of this node's children. |
178 | | - * |
179 | | - * @method |
180 | | - * @emits beforeReverse |
181 | | - * @emits afterReverse |
182 | | - * @emits update |
183 | | - */ |
184 | | -es.ModelNode.prototype.reverse = function() { |
185 | | - this.emit( 'beforeReverse' ); |
186 | | - Array.prototype.reverse.call( this ); |
187 | | - this.emit( 'afterReverse' ); |
188 | | - this.emit( 'update' ); |
189 | | -}; |
190 | | - |
191 | | -/** |
192 | | - * Gets a reference to this node's parent. |
193 | | - * |
194 | | - * @method |
195 | | - * @returns {es.ModelNode} Reference to this node's parent |
196 | | - */ |
197 | | -es.ModelNode.prototype.getParent = function() { |
198 | | - return this.parent; |
199 | | -}; |
200 | | - |
201 | | -/** |
202 | | - * Gets the root node in the tree this node is currently attached to. |
203 | | - * |
204 | | - * @method |
205 | | - * @returns {es.ModelNode} Root node |
206 | | - */ |
207 | | -es.ModelNode.prototype.getRoot = function() { |
208 | | - return this.root; |
209 | | -}; |
210 | | - |
211 | | -/** |
212 | | - * Sets the root node to this and all of it's children. |
213 | | - * |
214 | | - * @method |
215 | | - * @param {es.ModelNode} root Node to use as root |
216 | | - */ |
217 | | -es.ModelNode.prototype.setRoot = function( root ) { |
218 | | - this.root = root; |
219 | | - for ( var i = 0; i < this.length; i++ ) { |
220 | | - this[i].setRoot( root ); |
221 | | - } |
222 | | -}; |
223 | | - |
224 | | -/** |
225 | | - * Clears the root node from this and all of it's children. |
226 | | - * |
227 | | - * @method |
228 | | - */ |
229 | | -es.ModelNode.prototype.clearRoot = function() { |
230 | | - this.root = null; |
231 | | - for ( var i = 0; i < this.length; i++ ) { |
232 | | - this[i].clearRoot(); |
233 | | - } |
234 | | -}; |
235 | | - |
236 | | -/** |
237 | | - * Attaches this node to another as a child. |
238 | | - * |
239 | | - * @method |
240 | | - * @param {es.ModelNode} parent Node to attach to |
241 | | - * @emits attach (parent) |
242 | | - */ |
243 | | -es.ModelNode.prototype.attach = function( parent ) { |
244 | | - this.emit( 'beforeAttach', parent ); |
245 | | - this.parent = parent; |
246 | | - this.setRoot( parent.getRoot() ); |
247 | | - this.emit( 'afterAttach', parent ); |
248 | | -}; |
249 | | - |
250 | | -/** |
251 | | - * Detaches this node from it's parent. |
252 | | - * |
253 | | - * @method |
254 | | - * @emits detach |
255 | | - */ |
256 | | -es.ModelNode.prototype.detach = function() { |
257 | | - this.emit( 'beforeDetach' ); |
258 | | - this.parent = null; |
259 | | - this.clearRoot(); |
260 | | - this.emit( 'afterDetach' ); |
261 | | -}; |
262 | | - |
263 | | -/** |
264 | | - * Creates a view for this node. |
265 | | - * |
266 | | - * @method |
267 | | - * @returns {es.ViewNode} New item view associated with this model |
268 | | - */ |
269 | | -es.ModelNode.prototype.createView = function() { |
270 | | - throw 'ModelItem.createView not implemented in this subclass:' + this.constructor; |
271 | | -}; |
272 | | - |
273 | | -/* Inheritance */ |
274 | | - |
275 | | -es.extendClass( es.ModelNode, es.EventEmitter ); |
Index: trunk/parsers/wikidom/lib/hype/bases/es.DocumentViewNode.js |
— | — | @@ -0,0 +1,204 @@ |
| 2 | +/** |
| 3 | + * Creates an es.DocumentViewNode object. |
| 4 | + * |
| 5 | + * es.DocumentViewNode extends native JavaScript Array objects, without changing Array.prototype by |
| 6 | + * dynamically extending an array literal with the methods of es.DocumentViewNode. |
| 7 | + * |
| 8 | + * View nodes follow the operations performed on model nodes and keep elements in the DOM in sync. |
| 9 | + * |
| 10 | + * Child objects must extend es.DocumentViewNode. |
| 11 | + * |
| 12 | + * @class |
| 13 | + * @constructor |
| 14 | + * @extends {es.DocumentNode} |
| 15 | + * @extends {es.EventEmitter} |
| 16 | + * @param model {es.ModelNode} Model to observe |
| 17 | + * @param {jQuery} [$element=New DIV element] Element to use as a container |
| 18 | + * @property {es.ModelItem} model Model being observed |
| 19 | + * @property {jQuery} $ Container element |
| 20 | + */ |
| 21 | +es.DocumentViewNode = function( model, $element ) { |
| 22 | + // Inheritance |
| 23 | + es.DocumentNode.call( this ); |
| 24 | + es.EventEmitter.call( this ); |
| 25 | + |
| 26 | + // Properties |
| 27 | + this.model = model; |
| 28 | + this.children = []; |
| 29 | + this.$ = $element || $( '<div/>' ); |
| 30 | + |
| 31 | + // Reusable function for passing update events upstream |
| 32 | + var _this = this; |
| 33 | + this.emitUpdate = function() { |
| 34 | + _this.emit( 'update' ); |
| 35 | + }; |
| 36 | + |
| 37 | + if ( model ) { |
| 38 | + // Append existing model children |
| 39 | + var childModels = model.getChildren(); |
| 40 | + for ( var i = 0; i < childModels.length; i++ ) { |
| 41 | + this.onAfterPush( childModels[i] ); |
| 42 | + } |
| 43 | + |
| 44 | + // Observe and mimic changes on model |
| 45 | + this.addListenerMethods( this, { |
| 46 | + 'afterPush': 'onAfterPush', |
| 47 | + 'afterUnshift': 'onAfterUnshift', |
| 48 | + 'afterPop': 'onAfterPop', |
| 49 | + 'afterShift': 'onAfterShift', |
| 50 | + 'afterSplice': 'onAfterSplice', |
| 51 | + 'afterSort': 'onAfterSort', |
| 52 | + 'afterReverse': 'onAfterReverse' |
| 53 | + } ); |
| 54 | + } |
| 55 | +}; |
| 56 | + |
| 57 | +es.DocumentViewNode.prototype.onAfterPush = function( childModel ) { |
| 58 | + var childView = childModel.createView(); |
| 59 | + this.emit( 'beforePush', childView ); |
| 60 | + childView.attach( this ); |
| 61 | + childView.on( 'update', this.emitUpdate ); |
| 62 | + // Update children |
| 63 | + this.children.push( childView ); |
| 64 | + // Update DOM |
| 65 | + this.$.append( childView.$ ); |
| 66 | + this.emit( 'afterPush', childView ); |
| 67 | + this.emit( 'update' ); |
| 68 | +}; |
| 69 | + |
| 70 | +es.DocumentViewNode.prototype.onAfterUnshift = function( childModel ) { |
| 71 | + var childView = childModel.createView(); |
| 72 | + this.emit( 'beforeUnshift', childView ); |
| 73 | + childView.attach( this ); |
| 74 | + childView.on( 'update', this.emitUpdate ); |
| 75 | + // Update children |
| 76 | + this.children.unshift( childView ); |
| 77 | + // Update DOM |
| 78 | + this.$.prepend( childView.$ ); |
| 79 | + this.emit( 'afterUnshift', childView ); |
| 80 | + this.emit( 'update' ); |
| 81 | +}; |
| 82 | + |
| 83 | +es.DocumentViewNode.prototype.onAfterPop = function() { |
| 84 | + this.emit( 'beforePop' ); |
| 85 | + // Update children |
| 86 | + var childView = this.children.pop(); |
| 87 | + childView.detach(); |
| 88 | + childView.removeEventListener( 'update', this.emitUpdate ); |
| 89 | + // Update DOM |
| 90 | + childView.$.detach(); |
| 91 | + this.emit( 'afterPop' ); |
| 92 | + this.emit( 'update' ); |
| 93 | +}; |
| 94 | + |
| 95 | +es.DocumentViewNode.prototype.onAfterShift = function() { |
| 96 | + this.emit( 'beforeShift' ); |
| 97 | + // Update children |
| 98 | + var childView = this.children.shift(); |
| 99 | + childView.detach(); |
| 100 | + childView.removeEventListener( 'update', this.emitUpdate ); |
| 101 | + // Update DOM |
| 102 | + childView.$.detach(); |
| 103 | + this.emit( 'afterShift' ); |
| 104 | + this.emit( 'update' ); |
| 105 | +}; |
| 106 | + |
| 107 | +es.DocumentViewNode.prototype.onAfterSplice = function( index, howmany ) { |
| 108 | + var args = Array.prototype.slice( arguments, 0 ); |
| 109 | + this.emit.apply( ['beforeSplice'].concat( args ) ); |
| 110 | + // Update children |
| 111 | + this.splice.apply( this, args ); |
| 112 | + // Update DOM |
| 113 | + this.$.children() |
| 114 | + // Removals |
| 115 | + .slice( index, index + howmany ) |
| 116 | + .detach() |
| 117 | + .end() |
| 118 | + // Insertions |
| 119 | + .get( index ) |
| 120 | + .after( $.map( args.slice( 2 ), function( childView ) { |
| 121 | + return childView.$; |
| 122 | + } ) ); |
| 123 | + this.emit.apply( ['afterSplice'].concat( args ) ); |
| 124 | + this.emit( 'update' ); |
| 125 | +}; |
| 126 | + |
| 127 | +es.DocumentViewNode.prototype.onAfterSort = function() { |
| 128 | + this.emit( 'beforeSort' ); |
| 129 | + var childModels = this.model.getChildren(); |
| 130 | + for ( var i = 0; i < childModels.length; i++ ) { |
| 131 | + for ( var j = 0; j < this.children.length; j++ ) { |
| 132 | + if ( this.children[j].getModel() === childModels[i] ) { |
| 133 | + var childView = this.children[j]; |
| 134 | + // Update children |
| 135 | + this.children.splice( j, 1 ); |
| 136 | + this.children.push( childView ); |
| 137 | + // Update DOM |
| 138 | + this.$.append( childView.$ ); |
| 139 | + } |
| 140 | + } |
| 141 | + } |
| 142 | + this.emit( 'afterSort' ); |
| 143 | + this.emit( 'update' ); |
| 144 | +}; |
| 145 | + |
| 146 | +es.DocumentViewNode.prototype.onAfterReverse = function() { |
| 147 | + this.emit( 'beforeReverse' ); |
| 148 | + // Update children |
| 149 | + this.reverse(); |
| 150 | + // Update DOM |
| 151 | + this.$.children().each( function() { |
| 152 | + $(this).prependTo( $(this).parent() ); |
| 153 | + } ); |
| 154 | + this.emit( 'afterReverse' ); |
| 155 | + this.emit( 'update' ); |
| 156 | +}; |
| 157 | + |
| 158 | +/** |
| 159 | + * Gets a reference to the model this node observes. |
| 160 | + * |
| 161 | + * @method |
| 162 | + * @returns {es.ModelNode} Reference to the model this node observes |
| 163 | + */ |
| 164 | +es.DocumentViewNode.prototype.getModel = function() { |
| 165 | + return this.model; |
| 166 | +}; |
| 167 | + |
| 168 | +/** |
| 169 | + * Gets a reference to this node's parent. |
| 170 | + * |
| 171 | + * @method |
| 172 | + * @returns {es.DocumentViewNode} Reference to this node's parent |
| 173 | + */ |
| 174 | +es.DocumentViewNode.prototype.getParent = function() { |
| 175 | + return this.parent; |
| 176 | +}; |
| 177 | + |
| 178 | +/** |
| 179 | + * Attaches node as a child to another node. |
| 180 | + * |
| 181 | + * @method |
| 182 | + * @param {es.DocumentViewNode} parent Node to attach to |
| 183 | + * @emits attach (parent) |
| 184 | + */ |
| 185 | +es.DocumentViewNode.prototype.attach = function( parent ) { |
| 186 | + this.parent = parent; |
| 187 | + this.emit( 'attach', parent ); |
| 188 | +}; |
| 189 | + |
| 190 | +/** |
| 191 | + * Detaches node from it's parent. |
| 192 | + * |
| 193 | + * @method |
| 194 | + * @emits detach (parent) |
| 195 | + */ |
| 196 | +es.DocumentViewNode.prototype.detach = function() { |
| 197 | + var parent = this.parent; |
| 198 | + this.parent = null; |
| 199 | + this.emit( 'detach', parent ); |
| 200 | +}; |
| 201 | + |
| 202 | +/* Inheritance */ |
| 203 | + |
| 204 | +es.extendClass( es.DocumentViewNode, es.DocumentNode ); |
| 205 | +es.extendClass( es.DocumentViewNode, es.EventEmitter ); |
Index: trunk/parsers/wikidom/lib/hype/bases/es.DocumentNode.js |
— | — | @@ -1,11 +1,42 @@ |
2 | 2 | /** |
3 | 3 | * Creates an es.DocumentNode object. |
| 4 | + * |
| 5 | + * @class |
| 6 | + * @abstract |
| 7 | + * @constructor |
| 8 | + * @param {es.DocumentNode[]} nodes List of document nodes to initially add |
4 | 9 | */ |
5 | 10 | es.DocumentNode = function( nodes ) { |
6 | | - return es.extendObject( nodes === undefined ? [] : nodes, this ); |
| 11 | + this.children = es.isArray( nodes ) ? nodes : []; |
7 | 12 | }; |
8 | 13 | |
| 14 | +/* Abstract Methods */ |
| 15 | + |
9 | 16 | /** |
| 17 | + * Gets the element length. |
| 18 | + * |
| 19 | + * @abstract |
| 20 | + * @method |
| 21 | + * @returns {Integer} Length of element and it's content |
| 22 | + */ |
| 23 | +es.DocumentNode.prototype.getElementLength = function() { |
| 24 | + throw 'DocumentNode.getElementLength not implemented in this subclass: ' + this.constructor; |
| 25 | +}; |
| 26 | + |
| 27 | +/* Methods */ |
| 28 | + |
| 29 | +/** |
| 30 | + * Gets a list of child nodes. |
| 31 | + * |
| 32 | + * @abstract |
| 33 | + * @method |
| 34 | + * @returns {es.DocumentNode[]} List of document nodes |
| 35 | + */ |
| 36 | +es.DocumentNode.prototype.getChildren = function() { |
| 37 | + return this.children; |
| 38 | +}; |
| 39 | + |
| 40 | +/** |
10 | 41 | * Gets the range within this node that a given child node covers. |
11 | 42 | * |
12 | 43 | * @method |
— | — | @@ -14,20 +45,20 @@ |
15 | 46 | * @returns {es.Range|null} Range of node or null if node was not found |
16 | 47 | */ |
17 | 48 | es.DocumentNode.prototype.getRangeFromNode = function( node, shallow ) { |
18 | | - if ( this.length ) { |
19 | | - for ( var i = 0, length = this.length, left = 0; i < length; i++ ) { |
20 | | - if ( this[i] === node ) { |
21 | | - return new es.Range( left, left + this[i].getElementLength() ); |
| 49 | + if ( this.children.length ) { |
| 50 | + for ( var i = 0, length = this.children.length, left = 0; i < length; i++ ) { |
| 51 | + if ( this.children[i] === node ) { |
| 52 | + return new es.Range( left, left + this.children[i].getElementLength() ); |
22 | 53 | } |
23 | | - if ( !shallow && this[i].length ) { |
24 | | - var range = this[i].getRangeFromNode( node ); |
| 54 | + if ( !shallow && this.children[i].getChildren().length ) { |
| 55 | + var range = this.children[i].getRangeFromNode( node ); |
25 | 56 | if ( range !== null ) { |
26 | 57 | // Include opening of parent |
27 | 58 | left++; |
28 | 59 | return es.Range.newFromTranslatedRange( range, left ); |
29 | 60 | } |
30 | 61 | } |
31 | | - left += this[i].getElementLength(); |
| 62 | + left += this.children[i].getElementLength(); |
32 | 63 | } |
33 | 64 | } |
34 | 65 | return null; |
— | — | @@ -47,19 +78,19 @@ |
48 | 79 | * @returns {Integer} Offset of node or -1 of node was not found |
49 | 80 | */ |
50 | 81 | es.DocumentNode.prototype.getOffsetFromNode = function( node, shallow ) { |
51 | | - if ( this.length ) { |
| 82 | + if ( this.children.length ) { |
52 | 83 | var offset = 0; |
53 | | - for ( var i = 0, length = this.length; i < length; i++ ) { |
54 | | - if ( this[i] === node ) { |
| 84 | + for ( var i = 0, length = this.children.length; i < length; i++ ) { |
| 85 | + if ( this.children[i] === node ) { |
55 | 86 | return offset; |
56 | 87 | } |
57 | | - if ( !shallow && this[i].length ) { |
58 | | - var childOffset = this.getOffsetFromNode.call( this[i], node ); |
| 88 | + if ( !shallow && this.children[i].getChildren().length ) { |
| 89 | + var childOffset = this.getOffsetFromNode.call( this.children[i], node ); |
59 | 90 | if ( childOffset !== -1 ) { |
60 | 91 | return offset + 1 + childOffset; |
61 | 92 | } |
62 | 93 | } |
63 | | - offset += this[i].getElementLength(); |
| 94 | + offset += this.children[i].getElementLength(); |
64 | 95 | } |
65 | 96 | } |
66 | 97 | return -1; |
— | — | @@ -79,16 +110,16 @@ |
80 | 111 | * @returns {es.DocumentModelNode|null} Node at offset, or null if non was found |
81 | 112 | */ |
82 | 113 | es.DocumentNode.prototype.getNodeFromOffset = function( offset, shallow ) { |
83 | | - if ( this.length ) { |
| 114 | + if ( this.children.length ) { |
84 | 115 | var nodeOffset = 0, |
85 | 116 | nodeLength; |
86 | | - for ( var i = 0, length = this.length; i < length; i++ ) { |
87 | | - nodeLength = this[i].getElementLength(); |
| 117 | + for ( var i = 0, length = this.children.length; i < length; i++ ) { |
| 118 | + nodeLength = this.children[i].getElementLength(); |
88 | 119 | if ( offset >= nodeOffset && offset < nodeOffset + nodeLength ) { |
89 | | - if ( !shallow && this[i].length ) { |
90 | | - return this.getNodeFromOffset.call( this[i], offset - nodeOffset ); |
| 120 | + if ( !shallow && this.children[i].getChildren().length ) { |
| 121 | + return this.getNodeFromOffset.call( this.children[i], offset - nodeOffset ); |
91 | 122 | } else { |
92 | | - return this[i]; |
| 123 | + return this.children[i]; |
93 | 124 | } |
94 | 125 | } |
95 | 126 | nodeOffset += nodeLength; |
— | — | @@ -121,7 +152,7 @@ |
122 | 153 | throw 'The start offset of the range is negative'; |
123 | 154 | } |
124 | 155 | |
125 | | - if ( this.length === 0 ) { |
| 156 | + if ( this.children.length === 0 ) { |
126 | 157 | // Special case: this node doesn't have any children |
127 | 158 | // The return value is simply the range itself, if it is not out of bounds |
128 | 159 | if ( end > this.getContentLength() ) { |
— | — | @@ -132,9 +163,9 @@ |
133 | 164 | |
134 | 165 | // This node has children, loop over them |
135 | 166 | left = 1; // First offset inside the first child. Offset 0 is before the first child |
136 | | - for ( i = 0; i < this.length; i++ ) { |
137 | | - // left <= any offset inside this[i] <= right |
138 | | - right = left + this[i].getContentLength(); |
| 167 | + for ( i = 0; i < this.children.length; i++ ) { |
| 168 | + // left <= any offset inside this.children[i] <= right |
| 169 | + right = left + this.children[i].getContentLength(); |
139 | 170 | |
140 | 171 | if ( start == end && ( start == left - 1 || start == right + 1 ) ) { |
141 | 172 | // Empty range outside of any node |
— | — | @@ -142,54 +173,54 @@ |
143 | 174 | } |
144 | 175 | if ( start == left - 1 && end == right + 1 ) { |
145 | 176 | // The range covers the entire node, including its opening and closing elements |
146 | | - return [ { 'node': this[i] } ]; |
| 177 | + return [ { 'node': this.children[i] } ]; |
147 | 178 | } |
148 | 179 | if ( start == left - 1 ) { |
149 | | - // start is between this[i-1] and this[i], move it to left for convenience |
| 180 | + // start is between this.children[i-1] and this.children[i], move it to left for convenience |
150 | 181 | // We don't need to check for start < end here because we already have start != end and |
151 | 182 | // start <= end |
152 | 183 | start = left; |
153 | 184 | } |
154 | 185 | if ( end == right + 1 ) { |
155 | | - // end is between this[i] and this[i+1], move it to right for convenience |
| 186 | + // end is between this.children[i] and this.children[i+1], move it to right for convenience |
156 | 187 | // We don't need to check for start < end here because we already have start != end and |
157 | 188 | // start <= end |
158 | 189 | end = right; |
159 | 190 | } |
160 | 191 | |
161 | | - startInside = start >= left && start <= right; // is the start inside this[i]? |
162 | | - endInside = end >= left && end <= right; // is the end inside this[i]? |
| 192 | + startInside = start >= left && start <= right; // is the start inside this.children[i]? |
| 193 | + endInside = end >= left && end <= right; // is the end inside this.children[i]? |
163 | 194 | |
164 | 195 | if ( startInside && endInside ) { |
165 | | - // The range is entirely inside this[i] |
| 196 | + // The range is entirely inside this.children[i] |
166 | 197 | if ( shallow ) { |
167 | | - nodes = [ { 'node': this[i], 'range': new es.Range( start - left, end - left ) } ]; |
| 198 | + nodes = [{ 'node': this.children[i], 'range': new es.Range( start - left, end - left ) }]; |
168 | 199 | } else { |
169 | | - // Recurse into this[i] |
170 | | - nodes = this[i].selectNodes( new es.Range( start - left, end - left ) ); |
| 200 | + // Recurse into this.children[i] |
| 201 | + nodes = this.children[i].selectNodes( new es.Range( start - left, end - left ) ); |
171 | 202 | } |
172 | | - // Since the start and end are both inside this[i], we know for sure that we're done, so |
| 203 | + // Since the start and end are both inside this.children[i], we know for sure that we're done, so |
173 | 204 | // return |
174 | 205 | return nodes; |
175 | 206 | } else if ( startInside ) { |
176 | | - // The start is inside this[i] but the end isn't |
177 | | - // Add a range from the start of the range to the end of this[i] |
178 | | - nodes.push( { 'node': this[i], 'range': new es.Range( start - left, right - left ) } ); |
| 207 | + // The start is inside this.children[i] but the end isn't |
| 208 | + // Add a range from the start of the range to the end of this.children[i] |
| 209 | + nodes.push( { 'node': this.children[i], 'range': new es.Range( start - left, right - left ) } ); |
179 | 210 | } else if ( endInside ) { |
180 | | - // The end is inside this[i] but the start isn't |
181 | | - // Add a range from the start of this[i] to the end of the range |
182 | | - nodes.push( { 'node': this[i], 'range': new es.Range( 0, end - left ) } ); |
| 211 | + // The end is inside this.children[i] but the start isn't |
| 212 | + // Add a range from the start of this.children[i] to the end of the range |
| 213 | + nodes.push( { 'node': this.children[i], 'range': new es.Range( 0, end - left ) } ); |
183 | 214 | // We've found the end, so we're done |
184 | 215 | return nodes; |
185 | 216 | } else if ( nodes.length > 0 ) { |
186 | | - // Neither the start nor the end is inside this[i], but nodes is non-empty, |
187 | | - // so this[i] must be between the start and the end |
| 217 | + // Neither the start nor the end is inside this.children[i], but nodes is non-empty, |
| 218 | + // so this.children[i] must be between the start and the end |
188 | 219 | // Add the entire node, so no range property |
189 | | - nodes.push( { 'node': this[i] } ); |
| 220 | + nodes.push( { 'node': this.children[i] } ); |
190 | 221 | } |
191 | 222 | |
192 | | - // Move left to the start of this[i+1] for the next iteration |
193 | | - // +2 because we need to jump over the offset between this[i] and this[i+1] |
| 223 | + // Move left to the start of this.children[i+1] for the next iteration |
| 224 | + // +2 because we need to jump over the offset between this.children[i] and this.children[i+1] |
194 | 225 | left = right + 2; |
195 | 226 | } |
196 | 227 | |
Index: trunk/parsers/wikidom/lib/hype/bases/es.DocumentModelNode.js |
— | — | @@ -6,74 +6,282 @@ |
7 | 7 | * |
8 | 8 | * @class |
9 | 9 | * @constructor |
10 | | - * @extends {es.ModelNode} |
| 10 | + * @extends {es.DocumentNode} |
| 11 | + * @extends {es.EventEmitter} |
11 | 12 | * @param {Integer|Array} contents Either Length of content or array of child nodes to append |
12 | 13 | * @property {Integer} contentLength Length of content |
13 | 14 | */ |
14 | 15 | es.DocumentModelNode = function( element, contents ) { |
15 | | - // Extension |
16 | | - var node = es.extendObject( new es.DocumentNode( new es.ModelNode() ), this ); |
| 16 | + // Inheritance |
| 17 | + es.DocumentNode.call( this ); |
| 18 | + es.EventEmitter.call( this ); |
| 19 | + |
| 20 | + // Reusable function for passing update events upstream |
| 21 | + var _this = this; |
| 22 | + this.emitUpdate = function() { |
| 23 | + _this.emit( 'update' ); |
| 24 | + }; |
17 | 25 | |
18 | | - // Observe add and remove operations to keep lengths up to date |
19 | | - node.addListenerMethods( node, { |
20 | | - 'beforePush': 'onBeforePush', |
21 | | - 'beforeUnshift': 'onBeforeUnshift', |
22 | | - 'beforePop': 'onBeforePop', |
23 | | - 'beforeShift': 'onBeforeShift', |
24 | | - 'beforeSplice': 'onBeforeSplice' |
25 | | - } ); |
26 | | - |
27 | 26 | // Properties |
28 | | - node.element = element || null; |
29 | | - node.contentLength = 0; |
| 27 | + this.parent = null; |
| 28 | + this.root = this; |
| 29 | + this.element = element || null; |
| 30 | + this.contentLength = 0; |
30 | 31 | if ( typeof contents === 'number' ) { |
31 | 32 | if ( contents < 0 ) { |
32 | 33 | throw 'Invalid content length error. Content length can not be less than 0.'; |
33 | 34 | } |
34 | | - node.contentLength = contents; |
| 35 | + this.contentLength = contents; |
35 | 36 | } else if ( es.isArray( contents ) ) { |
36 | 37 | for ( var i = 0; i < contents.length; i++ ) { |
37 | | - node.push( contents[i] ); |
| 38 | + this.push( contents[i] ); |
38 | 39 | } |
39 | 40 | } |
40 | | - |
41 | | - return node; |
42 | 41 | }; |
43 | 42 | |
| 43 | +/* Abstract Methods */ |
| 44 | + |
| 45 | +/** |
| 46 | + * Creates a view for this node. |
| 47 | + * |
| 48 | + * @abstract |
| 49 | + * @method |
| 50 | + * @returns {es.DocumentViewNode} New item view associated with this model |
| 51 | + */ |
| 52 | +es.DocumentModelNode.prototype.createView = function() { |
| 53 | + throw 'DocumentModelNode.createView not implemented in this subclass:' + this.constructor; |
| 54 | +}; |
| 55 | + |
44 | 56 | /* Methods */ |
45 | 57 | |
46 | | -es.DocumentModelNode.prototype.onBeforePush = function( childModel ) { |
47 | | - this.adjustContentLength( childModel.getElementLength() ); |
| 58 | +/** |
| 59 | + * Adds a node to the end of this node's children. |
| 60 | + * |
| 61 | + * @method |
| 62 | + * @param {es.DocumentModelNode} childModel Item to add |
| 63 | + * @returns {Integer} New number of children |
| 64 | + * @emits beforePush (childModel) |
| 65 | + * @emits afterPush (childModel) |
| 66 | + * @emits update |
| 67 | + */ |
| 68 | +es.DocumentModelNode.prototype.push = function( childModel ) { |
| 69 | + this.emit( 'beforePush', childModel ); |
| 70 | + childModel.attach( this ); |
| 71 | + childModel.on( 'update', this.emitUpdate ); |
| 72 | + this.children.push( childModel ); |
| 73 | + this.adjustContentLength( childModel.getElementLength(), true ); |
| 74 | + this.emit( 'afterPush', childModel ); |
| 75 | + this.emit( 'update' ); |
| 76 | + return this.children.length; |
48 | 77 | }; |
49 | 78 | |
50 | | -es.DocumentModelNode.prototype.onBeforeUnshift = function( childModel ) { |
51 | | - this.adjustContentLength( childModel.getElementLength() ); |
| 79 | +/** |
| 80 | + * Adds a node to the beginning of this node's children. |
| 81 | + * |
| 82 | + * @method |
| 83 | + * @param {es.DocumentModelNode} childModel Item to add |
| 84 | + * @returns {Integer} New number of children |
| 85 | + * @emits beforeUnshift (childModel) |
| 86 | + * @emits afterUnshift (childModel) |
| 87 | + * @emits update |
| 88 | + */ |
| 89 | +es.DocumentModelNode.prototype.unshift = function( childModel ) { |
| 90 | + this.emit( 'beforeUnshift', childModel ); |
| 91 | + childModel.attach( this ); |
| 92 | + childModel.on( 'update', this.emitUpdate ); |
| 93 | + this.children.unshift( childModel ); |
| 94 | + this.adjustContentLength( childModel.getElementLength(), true ); |
| 95 | + this.emit( 'afterUnshift', childModel ); |
| 96 | + this.emit( 'update' ); |
| 97 | + return this.children.length; |
52 | 98 | }; |
53 | 99 | |
54 | | -es.DocumentModelNode.prototype.onBeforePop = function() { |
55 | | - this.adjustContentLength( -this[this.length - 1].getElementLength() ); |
| 100 | +/** |
| 101 | + * Removes a node from the end of this node's children |
| 102 | + * |
| 103 | + * @method |
| 104 | + * @returns {es.DocumentModelNode} Removed childModel |
| 105 | + * @emits beforePop |
| 106 | + * @emits afterPop |
| 107 | + * @emits update |
| 108 | + */ |
| 109 | +es.DocumentModelNode.prototype.pop = function() { |
| 110 | + if ( this.children.length ) { |
| 111 | + this.emit( 'beforePop' ); |
| 112 | + var childModel = this.children[this.children.length - 1]; |
| 113 | + childModel.detach(); |
| 114 | + childModel.removeListener( 'update', this.emitUpdate ); |
| 115 | + this.children.pop(); |
| 116 | + this.adjustContentLength( -childModel.getElementLength(), true ); |
| 117 | + this.emit( 'afterPop' ); |
| 118 | + this.emit( 'update' ); |
| 119 | + return childModel; |
| 120 | + } |
56 | 121 | }; |
57 | 122 | |
58 | | -es.DocumentModelNode.prototype.onBeforeShift = function() { |
59 | | - this.adjustContentLength( -this[0].getElementLength() ); |
| 123 | +/** |
| 124 | + * Removes a node from the beginning of this node's children |
| 125 | + * |
| 126 | + * @method |
| 127 | + * @returns {es.DocumentModelNode} Removed childModel |
| 128 | + * @emits beforeShift |
| 129 | + * @emits afterShift |
| 130 | + * @emits update |
| 131 | + */ |
| 132 | +es.DocumentModelNode.prototype.shift = function() { |
| 133 | + if ( this.children.length ) { |
| 134 | + this.emit( 'beforeShift' ); |
| 135 | + var childModel = this.children[0]; |
| 136 | + childModel.detach(); |
| 137 | + childModel.removeListener( 'update', this.emitUpdate ); |
| 138 | + this.children.shift(); |
| 139 | + this.adjustContentLength( -childModel.getElementLength(), true ); |
| 140 | + this.emit( 'afterShift' ); |
| 141 | + this.emit( 'update' ); |
| 142 | + return childModel; |
| 143 | + } |
60 | 144 | }; |
61 | 145 | |
62 | | -es.DocumentModelNode.prototype.onBeforeSplice = function( index, howmany ) { |
| 146 | +/** |
| 147 | + * Adds and removes nodes from this node's children. |
| 148 | + * |
| 149 | + * @method |
| 150 | + * @param {Integer} index Index to remove and or insert nodes at |
| 151 | + * @param {Integer} howmany Number of nodes to remove |
| 152 | + * @param {es.DocumentModelNode} [...] Variadic list of nodes to insert |
| 153 | + * @returns {es.DocumentModelNode[]} Removed nodes |
| 154 | + * @emits beforeSplice (index, howmany, [...]) |
| 155 | + * @emits afterSplice (index, howmany, [...]) |
| 156 | + * @emits update |
| 157 | + */ |
| 158 | +es.DocumentModelNode.prototype.splice = function( index, howmany ) { |
63 | 159 | var i, |
64 | 160 | length, |
65 | | - diff = 0, |
66 | | - removed = this.slice( index, index + howmany ), |
67 | | - added = Array.prototype.slice.call( arguments, 2 ); |
| 161 | + args = Array.prototype.slice.call( arguments, 0 ), |
| 162 | + diff = 0; |
| 163 | + this.emit.apply( this, ['beforeSplice'].concat( args ) ); |
| 164 | + if ( args.length >= 3 ) { |
| 165 | + for ( i = 2, length = args.length; i < length; i++ ) { |
| 166 | + diff += args[i].getElementLength(); |
| 167 | + args[i].attach( this ); |
| 168 | + } |
| 169 | + } |
| 170 | + var removed = this.children.splice.apply( this.children, args ); |
68 | 171 | for ( i = 0, length = removed.length; i < length; i++ ) { |
69 | 172 | diff -= removed[i].getElementLength(); |
| 173 | + removed[i].detach(); |
| 174 | + removed[i].removeListener( 'update', this.emitUpdate ); |
70 | 175 | } |
71 | | - for ( i = 0, length = added.length; i < length; i++ ) { |
72 | | - diff += added[i].getElementLength(); |
| 176 | + this.adjustContentLength( diff, true ); |
| 177 | + this.emit.apply( this, ['afterSplice'].concat( args ) ); |
| 178 | + this.emit( 'update' ); |
| 179 | + return removed; |
| 180 | +}; |
| 181 | + |
| 182 | +/** |
| 183 | + * Sorts this node's children. |
| 184 | + * |
| 185 | + * @method |
| 186 | + * @param {Function} sortfunc Function to use when sorting |
| 187 | + * @emits beforeSort (sortfunc) |
| 188 | + * @emits afterSort (sortfunc) |
| 189 | + * @emits update |
| 190 | + */ |
| 191 | +es.DocumentModelNode.prototype.sort = function( sortfunc ) { |
| 192 | + this.emit( 'beforeSort', sortfunc ); |
| 193 | + this.children.sort( sortfunc ); |
| 194 | + this.emit( 'afterSort', sortfunc ); |
| 195 | + this.emit( 'update' ); |
| 196 | +}; |
| 197 | + |
| 198 | +/** |
| 199 | + * Reverses the order of this node's children. |
| 200 | + * |
| 201 | + * @method |
| 202 | + * @emits beforeReverse |
| 203 | + * @emits afterReverse |
| 204 | + * @emits update |
| 205 | + */ |
| 206 | +es.DocumentModelNode.prototype.reverse = function() { |
| 207 | + this.emit( 'beforeReverse' ); |
| 208 | + this.children.reverse(); |
| 209 | + this.emit( 'afterReverse' ); |
| 210 | + this.emit( 'update' ); |
| 211 | +}; |
| 212 | + |
| 213 | +/** |
| 214 | + * Gets a reference to this node's parent. |
| 215 | + * |
| 216 | + * @method |
| 217 | + * @returns {es.DocumentModelNode} Reference to this node's parent |
| 218 | + */ |
| 219 | +es.DocumentModelNode.prototype.getParent = function() { |
| 220 | + return this.parent; |
| 221 | +}; |
| 222 | + |
| 223 | +/** |
| 224 | + * Gets the root node in the tree this node is currently attached to. |
| 225 | + * |
| 226 | + * @method |
| 227 | + * @returns {es.DocumentModelNode} Root node |
| 228 | + */ |
| 229 | +es.DocumentModelNode.prototype.getRoot = function() { |
| 230 | + return this.root; |
| 231 | +}; |
| 232 | + |
| 233 | +/** |
| 234 | + * Sets the root node to this and all of it's children. |
| 235 | + * |
| 236 | + * @method |
| 237 | + * @param {es.DocumentModelNode} root Node to use as root |
| 238 | + */ |
| 239 | +es.DocumentModelNode.prototype.setRoot = function( root ) { |
| 240 | + this.root = root; |
| 241 | + for ( var i = 0; i < this.children.length; i++ ) { |
| 242 | + this.children[i].setRoot( root ); |
73 | 243 | } |
74 | | - this.adjustContentLength( diff ); |
75 | 244 | }; |
76 | 245 | |
77 | 246 | /** |
| 247 | + * Clears the root node from this and all of it's children. |
| 248 | + * |
| 249 | + * @method |
| 250 | + */ |
| 251 | +es.DocumentModelNode.prototype.clearRoot = function() { |
| 252 | + this.root = null; |
| 253 | + for ( var i = 0; i < this.children.length; i++ ) { |
| 254 | + this.children[i].clearRoot(); |
| 255 | + } |
| 256 | +}; |
| 257 | + |
| 258 | +/** |
| 259 | + * Attaches this node to another as a child. |
| 260 | + * |
| 261 | + * @method |
| 262 | + * @param {es.DocumentModelNode} parent Node to attach to |
| 263 | + * @emits attach (parent) |
| 264 | + */ |
| 265 | +es.DocumentModelNode.prototype.attach = function( parent ) { |
| 266 | + this.emit( 'beforeAttach', parent ); |
| 267 | + this.parent = parent; |
| 268 | + this.setRoot( parent.getRoot() ); |
| 269 | + this.emit( 'afterAttach', parent ); |
| 270 | +}; |
| 271 | + |
| 272 | +/** |
| 273 | + * Detaches this node from it's parent. |
| 274 | + * |
| 275 | + * @method |
| 276 | + * @emits detach |
| 277 | + */ |
| 278 | +es.DocumentModelNode.prototype.detach = function() { |
| 279 | + this.emit( 'beforeDetach' ); |
| 280 | + this.parent = null; |
| 281 | + this.clearRoot(); |
| 282 | + this.emit( 'afterDetach' ); |
| 283 | +}; |
| 284 | + |
| 285 | +/** |
78 | 286 | * Sets the content length. |
79 | 287 | * |
80 | 288 | * @method |
— | — | @@ -208,3 +416,8 @@ |
209 | 417 | } |
210 | 418 | return text; |
211 | 419 | }; |
| 420 | + |
| 421 | +/* Inheritance */ |
| 422 | + |
| 423 | +es.extendClass( es.DocumentModelNode, es.DocumentNode ); |
| 424 | +es.extendClass( es.DocumentModelNode, es.EventEmitter ); |
Index: trunk/parsers/wikidom/lib/hype/bases/es.DocumentViewLeafNode.js |
— | — | @@ -3,19 +3,17 @@ |
4 | 4 | * |
5 | 5 | * @class |
6 | 6 | * @constructor |
7 | | - * @extends {es.ViewNode} |
| 7 | + * @extends {es.DocumentViewNode} |
8 | 8 | * @param model {es.ModelNode} Model to observe |
9 | 9 | * @param {jQuery} [$element] Element to use as a container |
10 | 10 | */ |
11 | 11 | es.DocumentViewLeafNode = function( model, $element ) { |
12 | | - // Extension |
13 | | - var node = es.extendObject( new es.DocumentNode( new es.ViewNode( model, $element ) ), this ); |
14 | | - |
15 | | - // Content |
16 | | - node.$content = $( '<div class="editSurface-content"></div>' ).appendTo( node.$ ); |
17 | | - node.contentView = new es.ContentView( node.$content, model ); |
18 | | - |
19 | | - return node; |
| 12 | + // Inheritance |
| 13 | + es.DocumentViewNode.call( this, model, $element ); |
| 14 | + |
| 15 | + // Properties |
| 16 | + this.$content = $( '<div class="editSurface-content"></div>' ).appendTo( this.$ ); |
| 17 | + this.contentView = new es.ContentView( this.$content, model ); |
20 | 18 | }; |
21 | 19 | |
22 | 20 | /* Methods */ |
— | — | @@ -87,4 +85,8 @@ |
88 | 86 | |
89 | 87 | es.DocumentViewLeafNode.prototype.getRenderedLineRange = function( offset ) { |
90 | 88 | return this.contentView.getRenderedLineRange( offset ); |
91 | | -}; |
\ No newline at end of file |
| 89 | +}; |
| 90 | + |
| 91 | +/* Inheritance */ |
| 92 | + |
| 93 | +es.extendClass( es.DocumentViewLeafNode, es.DocumentViewNode ); |
Index: trunk/parsers/wikidom/lib/hype/bases/es.DocumentViewBranchNode.js |
— | — | @@ -3,14 +3,16 @@ |
4 | 4 | * |
5 | 5 | * @class |
6 | 6 | * @constructor |
7 | | - * @extends {es.ViewNode} |
| 7 | + * @extends {es.DocumentViewNode} |
8 | 8 | * @param model {es.ModelNode} Model to observe |
9 | 9 | * @param {jQuery} [$element] Element to use as a container |
10 | 10 | */ |
11 | 11 | es.DocumentViewBranchNode = function( model, $element, horizontal ) { |
| 12 | + // Inheritance |
| 13 | + es.DocumentViewNode.call( this, model, $element ); |
| 14 | + |
| 15 | + // Properties |
12 | 16 | this.horizontal = horizontal || false; |
13 | | - // Extension |
14 | | - return es.extendObject( new es.DocumentNode( new es.ViewNode( model, $element ) ), this ); |
15 | 17 | }; |
16 | 18 | |
17 | 19 | /* Methods */ |
— | — | @@ -21,8 +23,8 @@ |
22 | 24 | * @method |
23 | 25 | */ |
24 | 26 | es.DocumentViewBranchNode.prototype.renderContent = function() { |
25 | | - for ( var i = 0; i < this.length; i++ ) { |
26 | | - this[i].renderContent(); |
| 27 | + for ( var i = 0; i < this.children.length; i++ ) { |
| 28 | + this.children[i].renderContent(); |
27 | 29 | } |
28 | 30 | }; |
29 | 31 | |
— | — | @@ -34,14 +36,14 @@ |
35 | 37 | */ |
36 | 38 | es.DocumentViewBranchNode.prototype.drawSelection = function( range ) { |
37 | 39 | var nodes = this.selectNodes( range, true ); |
38 | | - for ( var i = 0; i < this.length; i++ ) { |
39 | | - if ( nodes.length && this[i] === nodes[0].node ) { |
| 40 | + for ( var i = 0; i < this.children.length; i++ ) { |
| 41 | + if ( nodes.length && this.children[i] === nodes[0].node ) { |
40 | 42 | for ( var j = 0; j < nodes.length; j++ ) { |
41 | 43 | nodes[j].node.drawSelection( nodes[j].range ); |
42 | 44 | i++; |
43 | 45 | } |
44 | 46 | } else { |
45 | | - this[i].clearSelection(); |
| 47 | + this.children[i].clearSelection(); |
46 | 48 | } |
47 | 49 | } |
48 | 50 | }; |
— | — | @@ -52,8 +54,8 @@ |
53 | 55 | * @method |
54 | 56 | */ |
55 | 57 | es.DocumentViewBranchNode.prototype.clearSelection = function() { |
56 | | - for ( var i = 0; i < this.length; i++ ) { |
57 | | - this[i].clearSelection(); |
| 58 | + for ( var i = 0; i < this.children.length; i++ ) { |
| 59 | + this.children[i].clearSelection(); |
58 | 60 | } |
59 | 61 | }; |
60 | 62 | |
— | — | @@ -65,17 +67,17 @@ |
66 | 68 | * @returns {Integer} Offset of position |
67 | 69 | */ |
68 | 70 | es.DocumentViewBranchNode.prototype.getOffsetFromRenderedPosition = function( position ) { |
69 | | - if ( this.length === 0 ) { |
| 71 | + if ( this.children.length === 0 ) { |
70 | 72 | return 0; |
71 | 73 | } |
72 | | - var node = this[0]; |
73 | | - for ( var i = 1; i < this.length; i++ ) { |
74 | | - if ( this.horizontal && this[i].$.offset().left > position.left ) { |
| 74 | + var node = this.children[0]; |
| 75 | + for ( var i = 1; i < this.children.length; i++ ) { |
| 76 | + if ( this.horizontal && this.children[i].$.offset().left > position.left ) { |
75 | 77 | break; |
76 | | - } else if ( this[i].$.offset().top > position.top ) { |
| 78 | + } else if ( this.children[i].$.offset().top > position.top ) { |
77 | 79 | break; |
78 | 80 | } |
79 | | - node = this[i]; |
| 81 | + node = this.children[i]; |
80 | 82 | } |
81 | 83 | return node.getParent().getOffsetFromNode( node, true ) + |
82 | 84 | node.getOffsetFromRenderedPosition( position ) + 1; |
— | — | @@ -118,4 +120,8 @@ |
119 | 121 | ); |
120 | 122 | } |
121 | 123 | return null; |
122 | | -}; |
\ No newline at end of file |
| 124 | +}; |
| 125 | + |
| 126 | +/* Inheritance */ |
| 127 | + |
| 128 | +es.extendClass( es.DocumentViewBranchNode, es.DocumentViewNode ); |
Index: trunk/parsers/wikidom/lib/hype/views/es.ParagraphView.js |
— | — | @@ -4,10 +4,16 @@ |
5 | 5 | * @class |
6 | 6 | * @constructor |
7 | 7 | * @extends {es.DocumentViewLeafNode} |
| 8 | + * @param {es.ParagraphModel} model Paragraph model to view |
8 | 9 | */ |
9 | 10 | es.ParagraphView = function( model ) { |
10 | | - // Extension |
11 | | - var view = es.extendObject( new es.DocumentViewLeafNode( model ), this ); |
12 | | - view.$.addClass( 'editSurface-paragraphBlock' ); |
13 | | - return view; |
14 | | -}; |
\ No newline at end of file |
| 11 | + // Inheritance |
| 12 | + es.DocumentViewLeafNode.call( this, model ); |
| 13 | + |
| 14 | + // DOM Changes |
| 15 | + this.$.addClass( 'editSurface-paragraphBlock' ); |
| 16 | +}; |
| 17 | + |
| 18 | +/* Inheritance */ |
| 19 | + |
| 20 | +es.extendClass( es.ParagraphView, es.DocumentViewLeafNode ); |
Index: trunk/parsers/wikidom/lib/hype/views/es.TableCellView.js |
— | — | @@ -4,10 +4,16 @@ |
5 | 5 | * @class |
6 | 6 | * @constructor |
7 | 7 | * @extends {es.DocumentViewBranchNode} |
| 8 | + * @param {es.TableCellModel} model Table cell model to view |
8 | 9 | */ |
9 | 10 | es.TableCellView = function( model ) { |
10 | | - // Extension |
11 | | - var view = es.extendObject( new es.DocumentViewBranchNode( model, $( '<td>' ) ), this ); |
12 | | - view.$.attr( 'style', model.getElementAttribute( 'html/style' ) ); |
13 | | - return view; |
| 11 | + // Inheritance |
| 12 | + es.DocumentViewBranchNode.call( this, model, $( '<td>' ) ); |
| 13 | + |
| 14 | + // DOM Changes |
| 15 | + this.$.attr( 'style', model.getElementAttribute( 'html/style' ) ); |
14 | 16 | }; |
| 17 | + |
| 18 | +/* Inheritance */ |
| 19 | + |
| 20 | +es.extendClass( es.TableCellView, es.DocumentViewBranchNode ); |
Index: trunk/parsers/wikidom/lib/hype/views/es.TableView.js |
— | — | @@ -4,11 +4,18 @@ |
5 | 5 | * @class |
6 | 6 | * @constructor |
7 | 7 | * @extends {es.DocumentViewBranchNode} |
| 8 | + * @param {es.TableModel} model Table model to view |
8 | 9 | */ |
9 | 10 | es.TableView = function( model ) { |
10 | | - // Extension |
11 | | - var view = es.extendObject( new es.DocumentViewBranchNode( model, $( '<table>' ) ), this ); |
12 | | - view.$.attr( 'style', model.getElementAttribute( 'html/style' ) ); |
13 | | - view.$.addClass( 'editSurface-tableBlock' ); |
14 | | - return view; |
| 11 | + // Inheritance |
| 12 | + es.DocumentViewBranchNode.call( this, model, $( '<table>' ) ); |
| 13 | + |
| 14 | + // DOM Changes |
| 15 | + this.$ |
| 16 | + .attr( 'style', model.getElementAttribute( 'html/style' ) ) |
| 17 | + .addClass( 'editSurface-tableBlock' ); |
15 | 18 | }; |
| 19 | + |
| 20 | +/* Inheritance */ |
| 21 | + |
| 22 | +es.extendClass( es.TableView, es.DocumentViewBranchNode ); |
Index: trunk/parsers/wikidom/lib/hype/views/es.SurfaceView.js |
— | — | @@ -1,3 +1,11 @@ |
| 2 | +/** |
| 3 | + * Creates an es.SurfaceView object. |
| 4 | + * |
| 5 | + * @class |
| 6 | + * @constructor |
| 7 | + * @param {jQuery} $container DOM Container to render surface into |
| 8 | + * @param {es.SurfaceModel} model Surface model to view |
| 9 | + */ |
2 | 10 | es.SurfaceView = function( $container, model ) { |
3 | 11 | this.$ = $container.addClass( 'editSurface' ); |
4 | 12 | this.$window = $( window ); |
— | — | @@ -30,7 +38,7 @@ |
31 | 39 | .prependTo( this.$ ) |
32 | 40 | .bind( { |
33 | 41 | 'focus' : function() { |
34 | | - console.log("focus"); |
| 42 | + //console.log("focus"); |
35 | 43 | $document.unbind( '.editSurface' ); |
36 | 44 | $document.bind({ |
37 | 45 | 'mousemove.editSurface' : function(e) { |
— | — | @@ -43,12 +51,12 @@ |
44 | 52 | return surfaceView.onKeyDown( e ); |
45 | 53 | }, |
46 | 54 | 'keyup.editSurface' : function( e ) { |
47 | | - return surfaceView.onKeyUp( e ); |
| 55 | + return surfaceView.onKeyUp( e ); |
48 | 56 | } |
49 | 57 | }); |
50 | 58 | }, |
51 | 59 | 'blur': function( e ) { |
52 | | - console.log("blur"); |
| 60 | + //console.log("blur"); |
53 | 61 | $document.unbind( '.editSurface' ); |
54 | 62 | surfaceView.hideCursor(); |
55 | 63 | } |
— | — | @@ -107,6 +115,10 @@ |
108 | 116 | return false; |
109 | 117 | }; |
110 | 118 | |
| 119 | +es.SurfaceView.prototype.onKeyUp = function( e ) { |
| 120 | + // |
| 121 | +}; |
| 122 | + |
111 | 123 | es.SurfaceView.prototype.moveCursor = function( direction ) { |
112 | 124 | if ( direction === 'left') { |
113 | 125 | this.showCursor( this.documentView.getModel().getRelativeContentOffset( this.cursor.offset, -1 ) ); |
Index: trunk/parsers/wikidom/lib/hype/views/es.ContentView.js |
— | — | @@ -23,7 +23,10 @@ |
24 | 24 | * @property {Object} renderState |
25 | 25 | */ |
26 | 26 | es.ContentView = function( $container, model ) { |
| 27 | + // Inheritance |
27 | 28 | es.EventEmitter.call( this ); |
| 29 | + |
| 30 | + // Properties |
28 | 31 | this.$ = $container; |
29 | 32 | this.model = model; |
30 | 33 | this.boundaries = []; |
— | — | @@ -32,19 +35,24 @@ |
33 | 36 | this.boundaryTest = /([ \-\t\r\n\f])/g; |
34 | 37 | this.widthCache = {}; |
35 | 38 | this.renderState = {}; |
36 | | - // Respond to model changes |
37 | | - var contentView = this; |
38 | | - this.model.on( 'update', function( args ) { |
39 | | - contentView.scanBoundaries(); |
40 | | - contentView.render( args ? args.offset : 0 ); |
41 | | - } ); |
42 | | - // Perform initial boundary scan |
43 | | - this.scanBoundaries(); |
44 | | - // Create range divs for drawing selection |
45 | | - this.$ranges = $( '<div class="editSurface-ranges"></div>' ).prependTo( this.$ ); |
46 | | - this.$rangeStart = $( '<div class="editSurface-range"></div>' ).appendTo( this.$ranges ); |
47 | | - this.$rangeFill = $( '<div class="editSurface-range"></div>' ).appendTo( this.$ranges ); |
48 | | - this.$rangeEnd = $( '<div class="editSurface-range"></div>' ).appendTo( this.$ranges ); |
| 39 | + |
| 40 | + if ( model ) { |
| 41 | + // Events |
| 42 | + var _this = this; |
| 43 | + this.model.on( 'update', function( args ) { |
| 44 | + _this.scanBoundaries(); |
| 45 | + _this.render( args ? args.offset : 0 ); |
| 46 | + } ); |
| 47 | + |
| 48 | + // DOM Changes |
| 49 | + this.$ranges = $( '<div class="editSurface-ranges"></div>' ).prependTo( this.$ ); |
| 50 | + this.$rangeStart = $( '<div class="editSurface-range"></div>' ).appendTo( this.$ranges ); |
| 51 | + this.$rangeFill = $( '<div class="editSurface-range"></div>' ).appendTo( this.$ranges ); |
| 52 | + this.$rangeEnd = $( '<div class="editSurface-range"></div>' ).appendTo( this.$ranges ); |
| 53 | + |
| 54 | + // Initialization |
| 55 | + this.scanBoundaries(); |
| 56 | + } |
49 | 57 | }; |
50 | 58 | |
51 | 59 | /* Static Members */ |
Index: trunk/parsers/wikidom/lib/hype/views/es.ListItemView.js |
— | — | @@ -4,15 +4,23 @@ |
5 | 5 | * @class |
6 | 6 | * @constructor |
7 | 7 | * @extends {es.DocumentViewLeafNode} |
| 8 | + * @param {es.ListItemModel} model List item model to view |
8 | 9 | */ |
9 | 10 | es.ListItemView = function( model ) { |
10 | | - // Extension |
11 | | - var view = es.extendObject( new es.DocumentViewLeafNode( model ), this ); |
12 | | - view.$icon = $( '<div class="editSurface-listItem-icon"></div>' ).prependTo( view.$ ); |
13 | | - view.$.addClass( 'editSurface-listItem' ); |
14 | | - view.on( 'update', view.setClasses ); |
15 | | - view.setClasses(); |
16 | | - return view; |
| 11 | + // Inheritance |
| 12 | + es.DocumentViewLeafNode.call( this, model ); |
| 13 | + |
| 14 | + // Properties |
| 15 | + this.$icon = $( '<div class="editSurface-listItem-icon"></div>' ).prependTo( this.$ ); |
| 16 | + |
| 17 | + // DOM Changes |
| 18 | + this.$.addClass( 'editSurface-listItem' ); |
| 19 | + |
| 20 | + // Events |
| 21 | + this.on( 'update', this.setClasses ); |
| 22 | + |
| 23 | + // Initialization |
| 24 | + this.setClasses(); |
17 | 25 | }; |
18 | 26 | |
19 | 27 | es.ListItemView.prototype.setClasses = function() { |
— | — | @@ -25,4 +33,8 @@ |
26 | 34 | |
27 | 35 | es.ListItemView.prototype.setNumber = function( number ) { |
28 | 36 | this.$icon.text( number + '.' ); |
29 | | -}; |
\ No newline at end of file |
| 37 | +}; |
| 38 | + |
| 39 | +/* Inheritance */ |
| 40 | + |
| 41 | +es.extendClass( es.ListItemView, es.DocumentViewLeafNode ); |
Index: trunk/parsers/wikidom/lib/hype/views/es.ListView.js |
— | — | @@ -4,18 +4,22 @@ |
5 | 5 | * @class |
6 | 6 | * @constructor |
7 | 7 | * @extends {es.DocumentViewBranchNode} |
| 8 | + * @param {es.ListModel} model List model to view |
8 | 9 | */ |
9 | 10 | es.ListView = function( model ) { |
10 | | - // Extension |
11 | | - var view = es.extendObject( new es.DocumentViewBranchNode( model ), this ); |
12 | | - view.$.addClass( 'editSurface-listBlock' ); |
13 | | - view.on( 'update', view.enumerate ); |
14 | | - view.enumerate(); |
15 | | - return view; |
16 | | -}; |
| 11 | + // Inheritance |
| 12 | + es.DocumentViewBranchNode.call( this, model ); |
17 | 13 | |
| 14 | + // DOM Changes |
| 15 | + this.$.addClass( 'editSurface-listBlock' ); |
18 | 16 | |
| 17 | + // Events |
| 18 | + this.on( 'update', this.enumerate ); |
19 | 19 | |
| 20 | + // Initialization |
| 21 | + this.enumerate(); |
| 22 | +}; |
| 23 | + |
20 | 24 | /** |
21 | 25 | * Set the number labels of all ordered list items. |
22 | 26 | * |
— | — | @@ -24,15 +28,18 @@ |
25 | 29 | es.ListView.prototype.enumerate = function() { |
26 | 30 | var styles, |
27 | 31 | levels = []; |
28 | | - |
29 | 32 | for ( var i = 0; i < this.length; i++ ) { |
30 | 33 | styles = this[i].model.getElementAttribute( 'styles' ); |
31 | 34 | levels = levels.slice( 0, styles.length ); |
32 | | - if ( styles[ styles.length - 1 ] === 'number' ) { |
33 | | - if ( !levels[ styles.length - 1 ] ) { |
34 | | - levels[ styles.length - 1 ] = 0; |
| 35 | + if ( styles[styles.length - 1] === 'number' ) { |
| 36 | + if ( !levels[styles.length - 1] ) { |
| 37 | + levels[styles.length - 1] = 0; |
35 | 38 | } |
36 | | - this[i].setNumber( ++levels[ styles.length - 1 ] ); |
| 39 | + this[i].setNumber( ++levels[styles.length - 1] ); |
37 | 40 | } |
38 | 41 | } |
39 | | -}; |
\ No newline at end of file |
| 42 | +}; |
| 43 | + |
| 44 | +/* Inheritance */ |
| 45 | + |
| 46 | +es.extendClass( es.ListView, es.DocumentViewBranchNode ); |
Index: trunk/parsers/wikidom/lib/hype/views/es.DocumentView.js |
— | — | @@ -1,8 +1,21 @@ |
2 | | -es.DocumentView = function( documentModel, surfaceView ) { |
3 | | - var node = es.extendObject( new es.DocumentViewBranchNode( documentModel ), this ); |
4 | | - node.$.addClass( 'editSurface-document' ); |
5 | | - node.surfaceView = surfaceView; |
6 | | - return node; |
| 2 | +/** |
| 3 | + * Creates an es.DocumentView object. |
| 4 | + * |
| 5 | + * @class |
| 6 | + * @constructor |
| 7 | + * @extends {es.DocumentViewBranchNode} |
| 8 | + * @param {es.DocumentModel} documentModel Document model to view |
| 9 | + * @param {es.SurfaceView} surfaceView Surface view this view is a child of |
| 10 | + */ |
| 11 | +es.DocumentView = function( model, surfaceView ) { |
| 12 | + // Inheritance |
| 13 | + es.DocumentViewBranchNode.call( this, model ); |
| 14 | + |
| 15 | + // Properties |
| 16 | + this.surfaceView = surfaceView; |
| 17 | + |
| 18 | + // DOM Changes |
| 19 | + this.$.addClass( 'editSurface-document' ); |
7 | 20 | }; |
8 | 21 | |
9 | 22 | /** |
— | — | @@ -15,4 +28,8 @@ |
16 | 29 | es.DocumentView.prototype.getOffsetFromEvent = function( e ) { |
17 | 30 | var position = es.Position.newFromEventPagePosition( e ); |
18 | 31 | return this.getOffsetFromRenderedPosition( position ); |
19 | | -}; |
\ No newline at end of file |
| 32 | +}; |
| 33 | + |
| 34 | +/* Inheritance */ |
| 35 | + |
| 36 | +es.extendClass( es.DocumentView, es.DocumentViewBranchNode ); |
Index: trunk/parsers/wikidom/lib/hype/views/es.HeadingView.js |
— | — | @@ -4,10 +4,16 @@ |
5 | 5 | * @class |
6 | 6 | * @constructor |
7 | 7 | * @extends {es.DocumentViewLeafNode} |
| 8 | + * @param {es.HeadingModel} model Heading model to view |
8 | 9 | */ |
9 | 10 | es.HeadingView = function( model ) { |
10 | | - // Extension |
11 | | - var view = es.extendObject( new es.DocumentViewLeafNode( model, $('<h' + model.getElementAttribute( 'level' ) +'/>') ), this ); |
12 | | - view.$.addClass( 'editSurface-headingBlock' ); |
13 | | - return view; |
14 | | -}; |
\ No newline at end of file |
| 11 | + // Inheritance |
| 12 | + es.DocumentViewLeafNode.call( this, model ); |
| 13 | + |
| 14 | + // DOM Changes |
| 15 | + this.$.addClass( 'editSurface-headingBlock' ); |
| 16 | +}; |
| 17 | + |
| 18 | +/* Inheritance */ |
| 19 | + |
| 20 | +es.extendClass( es.HeadingView, es.DocumentViewLeafNode ); |
Index: trunk/parsers/wikidom/lib/hype/views/es.TableRowView.js |
— | — | @@ -4,10 +4,16 @@ |
5 | 5 | * @class |
6 | 6 | * @constructor |
7 | 7 | * @extends {es.DocumentViewBranchNode} |
| 8 | + * @param {es.TableRowModel} model Table row model to view |
8 | 9 | */ |
9 | 10 | es.TableRowView = function( model ) { |
10 | | - // Extension |
11 | | - var view = es.extendObject( new es.DocumentViewBranchNode( model, $( '<tr>' ), true ), this ); |
12 | | - view.$.attr( 'style', model.getElementAttribute( 'html/style' ) ); |
13 | | - return view; |
14 | | -}; |
\ No newline at end of file |
| 11 | + // Inheritance |
| 12 | + es.DocumentViewBranchNode.call( this, model, $( '<tr>' ) ); |
| 13 | + |
| 14 | + // DOM Changes |
| 15 | + this.$.attr( 'style', model.getElementAttribute( 'html/style' ) ); |
| 16 | +}; |
| 17 | + |
| 18 | +/* Inheritance */ |
| 19 | + |
| 20 | +es.extendClass( es.TableRowView, es.DocumentViewBranchNode ); |
Index: trunk/parsers/wikidom/demos/hype/es.js |
— | — | @@ -122,7 +122,7 @@ |
123 | 123 | ] |
124 | 124 | } |
125 | 125 | ] |
126 | | - }, |
| 126 | + } |
127 | 127 | ] |
128 | 128 | } |
129 | 129 | ] |
Index: trunk/parsers/wikidom/demos/hype/index.html |
— | — | @@ -61,10 +61,9 @@ |
62 | 62 | |
63 | 63 | <!-- Bases --> |
64 | 64 | <script src="../../lib/hype/bases/es.EventEmitter.js"></script> |
65 | | - <script src="../../lib/hype/bases/es.ModelNode.js"></script> |
66 | | - <script src="../../lib/hype/bases/es.ViewNode.js"></script> |
67 | 65 | <script src="../../lib/hype/bases/es.DocumentNode.js"></script> |
68 | 66 | <script src="../../lib/hype/bases/es.DocumentModelNode.js"></script> |
| 67 | + <script src="../../lib/hype/bases/es.DocumentViewNode.js"></script> |
69 | 68 | <script src="../../lib/hype/bases/es.DocumentViewBranchNode.js"></script> |
70 | 69 | <script src="../../lib/hype/bases/es.DocumentViewLeafNode.js"></script> |
71 | 70 | |