r101526 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r101525‎ | r101526 | r101527 >
Date:20:55, 1 November 2011
Author:tparscal
Status:deferred
Tags:
Comment:
Switched from extending native arrays to encapsulating arrays of children as a property. Extending native arrays was a clever idea, but in the end there were some costs that overcame the benefits. High on the list of costs was how FireBug, jQuery, QUnit and other debugging tools were unable to identify these objects as anything but arrays, ignoring their properties in comparison, and not displaying the correct constructor information in debugging output. The code also, while more succinct, required more explanation for new developers.
Modified paths:
  • /trunk/parsers/wikidom/demos/hype/es.js (modified) (history)
  • /trunk/parsers/wikidom/demos/hype/index.html (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.DocumentModelNode.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.DocumentNode.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.DocumentViewBranchNode.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.DocumentViewLeafNode.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.DocumentViewNode.js (added) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.ModelNode.js (deleted) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.ViewNode.js (deleted) (history)
  • /trunk/parsers/wikidom/lib/hype/es.Transaction.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/models/es.DocumentModel.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/models/es.HeadingModel.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/models/es.ListItemModel.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/models/es.ListModel.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/models/es.ParagraphModel.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/models/es.SurfaceModel.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/models/es.TableCellModel.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/models/es.TableModel.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/models/es.TableRowModel.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/views/es.ContentView.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/views/es.DocumentView.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/views/es.HeadingView.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/views/es.ListItemView.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/views/es.ListView.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/views/es.ParagraphView.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/views/es.SurfaceView.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/views/es.TableCellView.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/views/es.TableRowView.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/views/es.TableView.js (modified) (history)
  • /trunk/parsers/wikidom/tests/hype/es.DocumentModel.test.js (modified) (history)
  • /trunk/parsers/wikidom/tests/hype/es.DocumentNode.test.js (modified) (history)
  • /trunk/parsers/wikidom/tests/hype/es.ModelNode.test.js (deleted) (history)
  • /trunk/parsers/wikidom/tests/hype/index.html (modified) (history)

Diff [purge]

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' );
33
44 function DocumentNodeStub( items, name, size ) {
55 this.name = name;
@@ -275,7 +275,7 @@
276276 { 'node': g, 'range': new es.Range( 0, 5 ) }
277277 ],
278278 'desc': 'Range starting at the end of a node and ending in the middle of the next node'
279 - },
 279+ }
280280 ];
281281
282282 for ( var i = 0; i < selectNodesTests.length; i++ ) {
Index: trunk/parsers/wikidom/tests/hype/index.html
@@ -16,8 +16,6 @@
1717 <script src="../../lib/hype/es.Range.js"></script>
1818 <script src="../../lib/hype/es.Transaction.js"></script>
1919 <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>
2220 <script src="../../lib/hype/bases/es.DocumentNode.js"></script>
2321 <script src="../../lib/hype/bases/es.DocumentModelNode.js"></script>
2422 <script src="../../lib/hype/models/es.DocumentModel.js"></script>
@@ -28,7 +26,6 @@
2927 <script src="../../lib/hype/models/es.TableModel.js"></script>
3028 <script src="../../lib/hype/models/es.TableRowModel.js"></script>
3129 <script src="es.test.js"></script>
32 - <script src="es.ModelNode.test.js"></script>
3330 <script src="es.DocumentNode.test.js"></script>
3431 <script src="es.DocumentModel.test.js"></script>
3532 </body>
Index: trunk/parsers/wikidom/tests/hype/es.DocumentModel.test.js
@@ -1,4 +1,4 @@
2 -module( 'Models' );
 2+module( 'es/models' );
33
44 /*
55 * Sample plain object (WikiDom).
@@ -208,11 +208,30 @@
209209 deepEqual( documentModel.getData(), data, 'Flattening plain objects results in correct data' );
210210 } );
211211
212 -test( 'es.DocumentModel.slice', 1, function() {
 212+test( 'es.DocumentModel.getChildren', 1, function() {
213213 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+ }
214230
215231 // 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+ );
217236 } );
218237
219238 test( 'es.DocumentModel.getRelativeContentOffset', 7, function() {
@@ -263,11 +282,12 @@
264283 } );
265284
266285 test( 'es.DocumentModel.getContent', 6, function() {
267 - var documentModel = es.DocumentModel.newFromPlainObject( obj );
 286+ var documentModel = es.DocumentModel.newFromPlainObject( obj ),
 287+ childNodes = documentModel.getChildren();
268288
269289 // Test 1
270290 deepEqual(
271 - documentModel[0].getContent( new es.Range( 1, 3 ) ),
 291+ childNodes[0].getContent( new es.Range( 1, 3 ) ),
272292 [
273293 ['b', { 'type': 'bold', 'hash': '#bold' }],
274294 ['c', { 'type': 'italic', 'hash': '#italic' }]
@@ -277,34 +297,34 @@
278298
279299 // Test 2
280300 deepEqual(
281 - documentModel[0].getContent( new es.Range( 0, 2 ) ),
 301+ childNodes[0].getContent( new es.Range( 0, 2 ) ),
282302 ['a', ['b', { 'type': 'bold', 'hash': '#bold' }]],
283303 'getContent can return a beginning portion of the content'
284304 );
285305
286306 // Test 3
287307 deepEqual(
288 - documentModel[0].getContent( new es.Range( 1, 2 ) ),
 308+ childNodes[0].getContent( new es.Range( 1, 2 ) ),
289309 [['b', { 'type': 'bold', 'hash': '#bold' }]],
290310 'getContent can return a middle portion of the content'
291311 );
292312
293313 // Test 4
294314 try {
295 - documentModel[0].getContent( new es.Range( -1, 3 ) );
 315+ childNodes[0].getContent( new es.Range( -1, 3 ) );
296316 } catch ( negativeIndexError ) {
297317 ok( true, 'getContent throws exceptions when given a range with start < 0' );
298318 }
299319
300320 // Test 5
301321 try {
302 - documentModel[0].getContent( new es.Range( 0, 4 ) );
 322+ childNodes[0].getContent( new es.Range( 0, 4 ) );
303323 } catch ( outOfRangeError ) {
304324 ok( true, 'getContent throws exceptions when given a range with end > length' );
305325 }
306326
307327 // 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' );
309329 } );
310330
311331 test( 'es.DocumentModel.getIndexOfAnnotation', 3, function() {
@@ -395,21 +415,21 @@
396416 // Test 1
397417 deepEqual(
398418 documentModel.prepareElementAttributeChange( 0, 'set', 'test', 1234 ),
399 - [
 419+ new es.Transaction( [
400420 { 'type': 'attribute', 'method': 'set', 'key': 'test', 'value': 1234 },
401421 { 'type': 'retain', 'length': 28 }
402 - ],
 422+ ] ),
403423 'prepareElementAttributeChange retains data after attribute change for first element'
404424 );
405425
406426 // Test 2
407427 deepEqual(
408428 documentModel.prepareElementAttributeChange( 5, 'set', 'test', 1234 ),
409 - [
 429+ new es.Transaction( [
410430 { 'type': 'retain', 'length': 5 },
411431 { 'type': 'attribute', 'method': 'set', 'key': 'test', 'value': 1234 },
412432 { 'type': 'retain', 'length': 23 }
413 - ],
 433+ ] ),
414434 'prepareElementAttributeChange retains data before and after attribute change'
415435 );
416436
@@ -440,7 +460,7 @@
441461 // Test 1
442462 deepEqual(
443463 documentModel.prepareContentAnnotation( new es.Range( 1, 4 ), 'set', { 'type': 'bold' } ),
444 - [
 464+ new es.Transaction( [
445465 { 'type': 'retain', 'length': 1 },
446466 {
447467 'type': 'annotate',
@@ -470,7 +490,7 @@
471491 'annotation': { 'type': 'bold', 'hash': '#bold' }
472492 },
473493 { 'type': 'retain', 'length': 24 }
474 - ],
 494+ ] ),
475495 'prepareContentAnnotation skips over content that is already set or cleared'
476496 );
477497 } );
@@ -481,7 +501,7 @@
482502 // Test 1
483503 deepEqual(
484504 documentModel.prepareRemoval( new es.Range( 1, 4 ) ),
485 - [
 505+ new es.Transaction( [
486506 { 'type': 'retain', 'length': 1 },
487507 {
488508 'type': 'remove',
@@ -492,14 +512,14 @@
493513 ]
494514 },
495515 { 'type': 'retain', 'length': 24 }
496 - ],
 516+ ] ),
497517 'prepareRemoval includes the content being removed'
498518 );
499519
500520 // Test 2
501521 deepEqual(
502522 documentModel.prepareRemoval( new es.Range( 15, 18 ) ),
503 - [
 523+ new es.Transaction( [
504524 { 'type': 'retain', 'length': 15 },
505525 {
506526 'type': 'remove',
@@ -510,14 +530,14 @@
511531 ]
512532 },
513533 { 'type': 'retain', 'length': 10 }
514 - ],
 534+ ] ),
515535 'prepareRemoval removes entire elements'
516536 );
517537
518538 // Test 3
519539 deepEqual(
520540 documentModel.prepareRemoval( new es.Range( 17, 19 ) ),
521 - [
 541+ new es.Transaction( [
522542 { 'type': 'retain', 'length': 17 },
523543 {
524544 'type': 'remove',
@@ -527,7 +547,7 @@
528548 ]
529549 },
530550 { 'type': 'retain', 'length': 9 }
531 - ],
 551+ ] ),
532552 'prepareRemoval merges two list items'
533553 );
534554 } );
@@ -538,11 +558,11 @@
539559 // Test 1
540560 deepEqual(
541561 documentModel.prepareInsertion( 1, ['d', 'e', 'f'] ),
542 - [
 562+ new es.Transaction( [
543563 { 'type': 'retain', 'length': 1 },
544564 { 'type': 'insert', 'data': ['d', 'e', 'f'] },
545565 { 'type': 'retain', 'length': 27 }
546 - ],
 566+ ] ),
547567 'prepareInsertion retains data up to the offset and includes the content being inserted'
548568 );
549569
@@ -552,14 +572,14 @@
553573 5,
554574 [{ 'type': 'paragraph' }, 'd', 'e', 'f', { 'type': '/paragraph' }]
555575 ),
556 - [
 576+ new es.Transaction( [
557577 { 'type': 'retain', 'length': 5 },
558578 {
559579 'type': 'insert',
560580 'data': [{ 'type': 'paragraph' }, 'd', 'e', 'f', { 'type': '/paragraph' }]
561581 },
562582 { 'type': 'retain', 'length': 23 }
563 - ],
 583+ ] ),
564584 'prepareInsertion inserts a paragraph between two structural elements'
565585 );
566586
@@ -569,14 +589,14 @@
570590 5,
571591 ['d', 'e', 'f']
572592 ),
573 - [
 593+ new es.Transaction( [
574594 { 'type': 'retain', 'length': 5 },
575595 {
576596 'type': 'insert',
577597 'data': [{ 'type': 'paragraph' }, 'd', 'e', 'f', { 'type': '/paragraph' }]
578598 },
579599 { 'type': 'retain', 'length': 23 }
580 - ],
 600+ ] ),
581601 'prepareInsertion wraps unstructured content inserted between elements in a paragraph'
582602 );
583603
@@ -586,14 +606,14 @@
587607 5,
588608 [{ 'type': 'paragraph' }, 'd', 'e', 'f']
589609 ),
590 - [
 610+ new es.Transaction( [
591611 { 'type': 'retain', 'length': 5 },
592612 {
593613 'type': 'insert',
594614 'data': [{ 'type': 'paragraph' }, 'd', 'e', 'f', { 'type': '/paragraph' }]
595615 },
596616 { 'type': 'retain', 'length': 23 }
597 - ],
 617+ ] ),
598618 'prepareInsertion completes opening elements in inserted content'
599619 );
600620
@@ -603,14 +623,14 @@
604624 2,
605625 [ { 'type': 'table' }, { 'type': '/table' } ]
606626 ),
607 - [
 627+ new es.Transaction( [
608628 { 'type': 'retain', 'length': 2 },
609629 {
610630 'type': 'insert',
611631 'data': [ { 'type': '/paragraph' }, { 'type': 'table' }, { 'type': '/table' }, { 'type': 'paragraph' } ]
612632 },
613633 { 'type': 'retain', 'length': 26 }
614 - ],
 634+ ] ),
615635 'prepareInsertion splits up paragraph when inserting a table in the middle'
616636 );
617637
@@ -620,14 +640,14 @@
621641 2,
622642 [ 'f', 'o', 'o', { 'type': '/paragraph' }, { 'type': 'paragraph' }, 'b', 'a', 'r' ]
623643 ),
624 - [
 644+ new es.Transaction( [
625645 { 'type': 'retain', 'length': 2 },
626646 {
627647 'type': 'insert',
628648 'data': [ 'f', 'o', 'o', { 'type': '/paragraph' }, { 'type': 'paragraph' }, 'b', 'a', 'r' ]
629649 },
630650 { 'type': 'retain', 'length': 26 }
631 - ],
 651+ ] ),
632652 'prepareInsertion splits up paragraph when inserting a paragraph closing and opening into a paragraph'
633653 );
634654
@@ -637,13 +657,13 @@
638658 0,
639659 [ { 'type': 'paragraph' }, 'f', 'o', 'o', { 'type': '/paragraph' } ]
640660 ),
641 - [
 661+ new es.Transaction( [
642662 {
643663 'type': 'insert',
644664 'data': [ { 'type': 'paragraph' }, 'f', 'o', 'o', { 'type': '/paragraph' } ]
645665 },
646666 { 'type': 'retain', 'length': 28 }
647 - ],
 667+ ] ),
648668 'prepareInsertion inserts at the beginning, then retains up to the end'
649669 );
650670
@@ -653,13 +673,13 @@
654674 28,
655675 [ { 'type': 'paragraph' }, 'f', 'o', 'o', { 'type': '/paragraph' } ]
656676 ),
657 - [
 677+ new es.Transaction( [
658678 { 'type': 'retain', 'length': 28 },
659679 {
660680 'type': 'insert',
661681 'data': [ { 'type': 'paragraph' }, 'f', 'o', 'o', { 'type': '/paragraph' } ]
662682 }
663 - ],
 683+ ] ),
664684 'prepareInsertion inserts at the end'
665685 );
666686
@@ -786,7 +806,7 @@
787807
788808 // Test 6
789809 deepEqual(
790 - documentModel[0].getContent(),
 810+ documentModel.getChildren()[0].getContent(),
791811 [
792812 'a',
793813 ['b', { 'type': 'bold', 'hash': '#bold' }],
@@ -812,7 +832,7 @@
813833
814834 // Test 8
815835 deepEqual(
816 - documentModel[0].getContent(),
 836+ documentModel.getChildren()[0].getContent(),
817837 [
818838 'a',
819839 ['b', { 'type': 'bold', 'hash': '#bold' }],
@@ -850,3 +870,126 @@
851871 );
852872
853873 } );
 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 @@
77 *
88 * @class
99 * @constructor
 10+ * @extends {es.DocumentModelNode}
1011 * @param {Array} data Model data to initialize with, such as data from es.DocumentModel.getData()
1112 * @param {Object} attributes Document attributes
1213 */
1314 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 );
1617
1718 // 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 : {};
2021
2122 // Auto-generate model tree
22 - var nodes = es.DocumentModel.createNodesFromData( node.data );
 23+ var nodes = es.DocumentModel.createNodesFromData( this.data );
2324 for ( var i = 0; i < nodes.length; i++ ) {
24 - node.push( nodes[i] );
 25+ this.push( nodes[i] );
2526 }
26 -
27 - return node;
2827 };
2928
3029 /* Static Members */
@@ -313,7 +312,7 @@
314313 i--;
315314 }
316315 }
317 - return currentNode.slice();
 316+ return currentNode.getChildren().slice( 0 );
318317 };
319318
320319 /**
@@ -1107,15 +1106,16 @@
11081107 */
11091108 es.DocumentModel.prototype.commit = function( transaction ) {
11101109 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];
11201120 if ( operation.type in es.DocumentModel.operations ) {
11211121 es.DocumentModel.operations[operation.type].commit.call( state, operation );
11221122 } else {
@@ -1133,15 +1133,16 @@
11341134 */
11351135 es.DocumentModel.prototype.rollback = function( transaction ) {
11361136 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];
11461147 if ( operation.type in es.DocumentModel.operations ) {
11471148 es.DocumentModel.operations[operation.type].rollback.call( state, operation );
11481149 } else {
Index: trunk/parsers/wikidom/lib/hype/models/es.HeadingModel.js
@@ -3,10 +3,13 @@
44 *
55 * @class
66 * @constructor
 7+ * @extends {es.DocumentModelNode}
 8+ * @param {Object} element Document data element of this node
 9+ * @param {Integer} length Length of document data element
710 */
811 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 );
1114 };
1215
1316 /* Methods */
@@ -29,3 +32,7 @@
3033 'parents': null,
3134 'children': []
3235 };
 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 @@
44 *
55 * @class
66 * @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
710 */
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 );
1114 };
1215
1316 /* Methods */
@@ -29,3 +32,7 @@
3033 'parents': ['table'],
3134 'children': ['tableCell']
3235 };
 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 @@
44 *
55 * @class
66 * @constructor
 7+ * @extends {es.DocumentModelNode}
 8+ * @param {Object} element Document data element of this node
 9+ * @param {Integer} length Length of document data element
710 */
811 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 );
1114 };
1215
1316 /* Methods */
@@ -29,3 +32,7 @@
3033 'parents': null,
3134 'children': []
3235 };
 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 @@
44 *
55 * @class
66 * @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
710 */
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 );
1114 };
1215
1316 /* Methods */
@@ -29,3 +32,7 @@
3033 'parents': ['tableRow'],
3134 'children': null
3235 };
 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 @@
44 *
55 * @class
66 * @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
710 */
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 );
1114 };
1215
1316 /* Methods */
@@ -29,3 +32,7 @@
3033 'parents': null,
3134 'children': ['tableRow']
3235 };
 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 ) {
310 this.doc = doc;
411 };
512
 13+/* Methods */
 14+
615 es.SurfaceModel.prototype.getDocument = function() {
716 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 @@
44 *
55 * @class
66 * @constructor
 7+ * @extends {es.DocumentModelNode}
 8+ * @param {Object} element Document data element of this node
 9+ * @param {Integer} length Length of document data element
710 */
811 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 );
1114 };
1215
1316 /* Methods */
@@ -29,3 +32,7 @@
3033 'parents': ['list'],
3134 'children': []
3235 };
 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 @@
44 *
55 * @class
66 * @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
710 */
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 );
1114 };
1215
1316 /* Methods */
@@ -29,3 +32,7 @@
3033 'parents': null,
3134 'children': ['listItem']
3235 };
 36+
 37+/* Inheritance */
 38+
 39+es.extendClass( es.ListModel, es.DocumentModelNode );
Index: trunk/parsers/wikidom/lib/hype/es.Transaction.js
@@ -2,38 +2,42 @@
33 * Creates an es.Transaction object.
44 *
55 * @class
6 - * @extends {Array}
76 * @constructor
 7+ * @param {Object[]} operations List of operations
88 */
9 -es.Transaction = function() {
10 - return es.extendObject( [], this );
 9+es.Transaction = function( operations ) {
 10+ this.operations = es.isArray( operations ) ? operations : [];
1111 };
1212
1313 /* Methods */
1414
 15+es.Transaction.prototype.getOperations = function() {
 16+ return this.operations;
 17+};
 18+
1519 es.Transaction.prototype.pushRetain = function( length ) {
16 - this.push( {
 20+ this.operations.push( {
1721 'type': 'retain',
1822 'length': length
1923 } );
2024 };
2125
2226 es.Transaction.prototype.pushInsert = function( content ) {
23 - this.push( {
 27+ this.operations.push( {
2428 'type': 'insert',
2529 'data': content
2630 } );
2731 };
2832
2933 es.Transaction.prototype.pushRemove = function( data ) {
30 - this.push( {
 34+ this.operations.push( {
3135 'type': 'remove',
3236 'data': data
3337 } );
3438 };
3539
3640 es.Transaction.prototype.pushChangeElementAttribute = function( method, key, value ) {
37 - this.push( {
 41+ this.operations.push( {
3842 'type': 'attribute',
3943 'method': method,
4044 'key': key,
@@ -42,7 +46,7 @@
4347 };
4448
4549 es.Transaction.prototype.pushStartAnnotating = function( method, annotation ) {
46 - this.push( {
 50+ this.operations.push( {
4751 'type': 'annotate',
4852 'method': method,
4953 'bias': 'start',
@@ -51,7 +55,7 @@
5256 };
5357
5458 es.Transaction.prototype.pushStopAnnotating = function( method, annotation ) {
55 - this.push( {
 59+ this.operations.push( {
5660 'type': 'annotate',
5761 'method': method,
5862 '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 @@
22 /**
33 * Creates an es.DocumentNode object.
 4+ *
 5+ * @class
 6+ * @abstract
 7+ * @constructor
 8+ * @param {es.DocumentNode[]} nodes List of document nodes to initially add
49 */
510 es.DocumentNode = function( nodes ) {
6 - return es.extendObject( nodes === undefined ? [] : nodes, this );
 11+ this.children = es.isArray( nodes ) ? nodes : [];
712 };
813
 14+/* Abstract Methods */
 15+
916 /**
 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+/**
1041 * Gets the range within this node that a given child node covers.
1142 *
1243 * @method
@@ -14,20 +45,20 @@
1546 * @returns {es.Range|null} Range of node or null if node was not found
1647 */
1748 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() );
2253 }
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 );
2556 if ( range !== null ) {
2657 // Include opening of parent
2758 left++;
2859 return es.Range.newFromTranslatedRange( range, left );
2960 }
3061 }
31 - left += this[i].getElementLength();
 62+ left += this.children[i].getElementLength();
3263 }
3364 }
3465 return null;
@@ -47,19 +78,19 @@
4879 * @returns {Integer} Offset of node or -1 of node was not found
4980 */
5081 es.DocumentNode.prototype.getOffsetFromNode = function( node, shallow ) {
51 - if ( this.length ) {
 82+ if ( this.children.length ) {
5283 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 ) {
5586 return offset;
5687 }
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 );
5990 if ( childOffset !== -1 ) {
6091 return offset + 1 + childOffset;
6192 }
6293 }
63 - offset += this[i].getElementLength();
 94+ offset += this.children[i].getElementLength();
6495 }
6596 }
6697 return -1;
@@ -79,16 +110,16 @@
80111 * @returns {es.DocumentModelNode|null} Node at offset, or null if non was found
81112 */
82113 es.DocumentNode.prototype.getNodeFromOffset = function( offset, shallow ) {
83 - if ( this.length ) {
 114+ if ( this.children.length ) {
84115 var nodeOffset = 0,
85116 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();
88119 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 );
91122 } else {
92 - return this[i];
 123+ return this.children[i];
93124 }
94125 }
95126 nodeOffset += nodeLength;
@@ -121,7 +152,7 @@
122153 throw 'The start offset of the range is negative';
123154 }
124155
125 - if ( this.length === 0 ) {
 156+ if ( this.children.length === 0 ) {
126157 // Special case: this node doesn't have any children
127158 // The return value is simply the range itself, if it is not out of bounds
128159 if ( end > this.getContentLength() ) {
@@ -132,9 +163,9 @@
133164
134165 // This node has children, loop over them
135166 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();
139170
140171 if ( start == end && ( start == left - 1 || start == right + 1 ) ) {
141172 // Empty range outside of any node
@@ -142,54 +173,54 @@
143174 }
144175 if ( start == left - 1 && end == right + 1 ) {
145176 // The range covers the entire node, including its opening and closing elements
146 - return [ { 'node': this[i] } ];
 177+ return [ { 'node': this.children[i] } ];
147178 }
148179 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
150181 // We don't need to check for start < end here because we already have start != end and
151182 // start <= end
152183 start = left;
153184 }
154185 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
156187 // We don't need to check for start < end here because we already have start != end and
157188 // start <= end
158189 end = right;
159190 }
160191
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]?
163194
164195 if ( startInside && endInside ) {
165 - // The range is entirely inside this[i]
 196+ // The range is entirely inside this.children[i]
166197 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 ) }];
168199 } 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 ) );
171202 }
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
173204 // return
174205 return nodes;
175206 } 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 ) } );
179210 } 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 ) } );
183214 // We've found the end, so we're done
184215 return nodes;
185216 } 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
188219 // Add the entire node, so no range property
189 - nodes.push( { 'node': this[i] } );
 220+ nodes.push( { 'node': this.children[i] } );
190221 }
191222
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]
194225 left = right + 2;
195226 }
196227
Index: trunk/parsers/wikidom/lib/hype/bases/es.DocumentModelNode.js
@@ -6,74 +6,282 @@
77 *
88 * @class
99 * @constructor
10 - * @extends {es.ModelNode}
 10+ * @extends {es.DocumentNode}
 11+ * @extends {es.EventEmitter}
1112 * @param {Integer|Array} contents Either Length of content or array of child nodes to append
1213 * @property {Integer} contentLength Length of content
1314 */
1415 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+ };
1725
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 -
2726 // 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;
3031 if ( typeof contents === 'number' ) {
3132 if ( contents < 0 ) {
3233 throw 'Invalid content length error. Content length can not be less than 0.';
3334 }
34 - node.contentLength = contents;
 35+ this.contentLength = contents;
3536 } else if ( es.isArray( contents ) ) {
3637 for ( var i = 0; i < contents.length; i++ ) {
37 - node.push( contents[i] );
 38+ this.push( contents[i] );
3839 }
3940 }
40 -
41 - return node;
4241 };
4342
 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+
4456 /* Methods */
4557
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;
4877 };
4978
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;
5298 };
5399
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+ }
56121 };
57122
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+ }
60144 };
61145
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 ) {
63159 var i,
64160 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 );
68171 for ( i = 0, length = removed.length; i < length; i++ ) {
69172 diff -= removed[i].getElementLength();
 173+ removed[i].detach();
 174+ removed[i].removeListener( 'update', this.emitUpdate );
70175 }
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 );
73243 }
74 - this.adjustContentLength( diff );
75244 };
76245
77246 /**
 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+/**
78286 * Sets the content length.
79287 *
80288 * @method
@@ -208,3 +416,8 @@
209417 }
210418 return text;
211419 };
 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 @@
44 *
55 * @class
66 * @constructor
7 - * @extends {es.ViewNode}
 7+ * @extends {es.DocumentViewNode}
88 * @param model {es.ModelNode} Model to observe
99 * @param {jQuery} [$element] Element to use as a container
1010 */
1111 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 );
2018 };
2119
2220 /* Methods */
@@ -87,4 +85,8 @@
8886
8987 es.DocumentViewLeafNode.prototype.getRenderedLineRange = function( offset ) {
9088 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 @@
44 *
55 * @class
66 * @constructor
7 - * @extends {es.ViewNode}
 7+ * @extends {es.DocumentViewNode}
88 * @param model {es.ModelNode} Model to observe
99 * @param {jQuery} [$element] Element to use as a container
1010 */
1111 es.DocumentViewBranchNode = function( model, $element, horizontal ) {
 12+ // Inheritance
 13+ es.DocumentViewNode.call( this, model, $element );
 14+
 15+ // Properties
1216 this.horizontal = horizontal || false;
13 - // Extension
14 - return es.extendObject( new es.DocumentNode( new es.ViewNode( model, $element ) ), this );
1517 };
1618
1719 /* Methods */
@@ -21,8 +23,8 @@
2224 * @method
2325 */
2426 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();
2729 }
2830 };
2931
@@ -34,14 +36,14 @@
3537 */
3638 es.DocumentViewBranchNode.prototype.drawSelection = function( range ) {
3739 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 ) {
4042 for ( var j = 0; j < nodes.length; j++ ) {
4143 nodes[j].node.drawSelection( nodes[j].range );
4244 i++;
4345 }
4446 } else {
45 - this[i].clearSelection();
 47+ this.children[i].clearSelection();
4648 }
4749 }
4850 };
@@ -52,8 +54,8 @@
5355 * @method
5456 */
5557 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();
5860 }
5961 };
6062
@@ -65,17 +67,17 @@
6668 * @returns {Integer} Offset of position
6769 */
6870 es.DocumentViewBranchNode.prototype.getOffsetFromRenderedPosition = function( position ) {
69 - if ( this.length === 0 ) {
 71+ if ( this.children.length === 0 ) {
7072 return 0;
7173 }
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 ) {
7577 break;
76 - } else if ( this[i].$.offset().top > position.top ) {
 78+ } else if ( this.children[i].$.offset().top > position.top ) {
7779 break;
7880 }
79 - node = this[i];
 81+ node = this.children[i];
8082 }
8183 return node.getParent().getOffsetFromNode( node, true ) +
8284 node.getOffsetFromRenderedPosition( position ) + 1;
@@ -118,4 +120,8 @@
119121 );
120122 }
121123 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 @@
55 * @class
66 * @constructor
77 * @extends {es.DocumentViewLeafNode}
 8+ * @param {es.ParagraphModel} model Paragraph model to view
89 */
910 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 @@
55 * @class
66 * @constructor
77 * @extends {es.DocumentViewBranchNode}
 8+ * @param {es.TableCellModel} model Table cell model to view
89 */
910 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' ) );
1416 };
 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 @@
55 * @class
66 * @constructor
77 * @extends {es.DocumentViewBranchNode}
 8+ * @param {es.TableModel} model Table model to view
89 */
910 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' );
1518 };
 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+ */
210 es.SurfaceView = function( $container, model ) {
311 this.$ = $container.addClass( 'editSurface' );
412 this.$window = $( window );
@@ -30,7 +38,7 @@
3139 .prependTo( this.$ )
3240 .bind( {
3341 'focus' : function() {
34 - console.log("focus");
 42+ //console.log("focus");
3543 $document.unbind( '.editSurface' );
3644 $document.bind({
3745 'mousemove.editSurface' : function(e) {
@@ -43,12 +51,12 @@
4452 return surfaceView.onKeyDown( e );
4553 },
4654 'keyup.editSurface' : function( e ) {
47 - return surfaceView.onKeyUp( e );
 55+ return surfaceView.onKeyUp( e );
4856 }
4957 });
5058 },
5159 'blur': function( e ) {
52 - console.log("blur");
 60+ //console.log("blur");
5361 $document.unbind( '.editSurface' );
5462 surfaceView.hideCursor();
5563 }
@@ -107,6 +115,10 @@
108116 return false;
109117 };
110118
 119+es.SurfaceView.prototype.onKeyUp = function( e ) {
 120+ //
 121+};
 122+
111123 es.SurfaceView.prototype.moveCursor = function( direction ) {
112124 if ( direction === 'left') {
113125 this.showCursor( this.documentView.getModel().getRelativeContentOffset( this.cursor.offset, -1 ) );
Index: trunk/parsers/wikidom/lib/hype/views/es.ContentView.js
@@ -23,7 +23,10 @@
2424 * @property {Object} renderState
2525 */
2626 es.ContentView = function( $container, model ) {
 27+ // Inheritance
2728 es.EventEmitter.call( this );
 29+
 30+ // Properties
2831 this.$ = $container;
2932 this.model = model;
3033 this.boundaries = [];
@@ -32,19 +35,24 @@
3336 this.boundaryTest = /([ \-\t\r\n\f])/g;
3437 this.widthCache = {};
3538 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+ }
4957 };
5058
5159 /* Static Members */
Index: trunk/parsers/wikidom/lib/hype/views/es.ListItemView.js
@@ -4,15 +4,23 @@
55 * @class
66 * @constructor
77 * @extends {es.DocumentViewLeafNode}
 8+ * @param {es.ListItemModel} model List item model to view
89 */
910 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();
1725 };
1826
1927 es.ListItemView.prototype.setClasses = function() {
@@ -25,4 +33,8 @@
2634
2735 es.ListItemView.prototype.setNumber = function( number ) {
2836 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 @@
55 * @class
66 * @constructor
77 * @extends {es.DocumentViewBranchNode}
 8+ * @param {es.ListModel} model List model to view
89 */
910 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 );
1713
 14+ // DOM Changes
 15+ this.$.addClass( 'editSurface-listBlock' );
1816
 17+ // Events
 18+ this.on( 'update', this.enumerate );
1919
 20+ // Initialization
 21+ this.enumerate();
 22+};
 23+
2024 /**
2125 * Set the number labels of all ordered list items.
2226 *
@@ -24,15 +28,18 @@
2529 es.ListView.prototype.enumerate = function() {
2630 var styles,
2731 levels = [];
28 -
2932 for ( var i = 0; i < this.length; i++ ) {
3033 styles = this[i].model.getElementAttribute( 'styles' );
3134 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;
3538 }
36 - this[i].setNumber( ++levels[ styles.length - 1 ] );
 39+ this[i].setNumber( ++levels[styles.length - 1] );
3740 }
3841 }
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' );
720 };
821
922 /**
@@ -15,4 +28,8 @@
1629 es.DocumentView.prototype.getOffsetFromEvent = function( e ) {
1730 var position = es.Position.newFromEventPagePosition( e );
1831 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 @@
55 * @class
66 * @constructor
77 * @extends {es.DocumentViewLeafNode}
 8+ * @param {es.HeadingModel} model Heading model to view
89 */
910 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 @@
55 * @class
66 * @constructor
77 * @extends {es.DocumentViewBranchNode}
 8+ * @param {es.TableRowModel} model Table row model to view
89 */
910 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 @@
123123 ]
124124 }
125125 ]
126 - },
 126+ }
127127 ]
128128 }
129129 ]
Index: trunk/parsers/wikidom/demos/hype/index.html
@@ -61,10 +61,9 @@
6262
6363 <!-- Bases -->
6464 <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>
6765 <script src="../../lib/hype/bases/es.DocumentNode.js"></script>
6866 <script src="../../lib/hype/bases/es.DocumentModelNode.js"></script>
 67+ <script src="../../lib/hype/bases/es.DocumentViewNode.js"></script>
6968 <script src="../../lib/hype/bases/es.DocumentViewBranchNode.js"></script>
7069 <script src="../../lib/hype/bases/es.DocumentViewLeafNode.js"></script>
7170

Status & tagging log