r98377 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r98376‎ | r98377 | r98378 >
Date:22:40, 28 September 2011
Author:tparscal
Status:deferred
Tags:
Comment:
Merged List and Item base classes into Nodes
Modified paths:
  • /trunk/parsers/wikidom/lib/hype/bases/es.DocumentModelNode.js (modified) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.ModelItem.js (deleted) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.ModelList.js (deleted) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.ModelNode.js (added) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.ViewItem.js (deleted) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.ViewList.js (deleted) (history)
  • /trunk/parsers/wikidom/lib/hype/bases/es.ViewNode.js (added) (history)
  • /trunk/parsers/wikidom/tests/hype/index.html (modified) (history)
  • /trunk/parsers/wikidom/tests/hype/test.js (modified) (history)

Diff [purge]

Index: trunk/parsers/wikidom/tests/hype/index.html
@@ -13,10 +13,8 @@
1414 <script src="../../lib/hype/es.js"></script>
1515 <script src="../../lib/synth/bases/es.AggregateArray.js"></script>
1616 <script src="../../lib/hype/bases/es.EventEmitter.js"></script>
17 - <script src="../../lib/hype/bases/es.ModelList.js"></script>
18 - <script src="../../lib/hype/bases/es.ModelItem.js"></script>
19 - <script src="../../lib/hype/bases/es.ViewList.js"></script>
20 - <script src="../../lib/hype/bases/es.ViewItem.js"></script>
 17+ <script src="../../lib/hype/bases/es.ModelNode.js"></script>
 18+ <script src="../../lib/hype/bases/es.ViewNode.js"></script>
2119 <script src="../../lib/jquery.js"></script>
2220 <script src="../../lib/qunit.js"></script>
2321 <script src="test.js"></script>
Index: trunk/parsers/wikidom/tests/hype/test.js
@@ -1,44 +1,44 @@
22 module( 'Base classes' );
33
4 -test( 'es.ModelList and es.ModelItem', function() {
5 - var modelList = new es.ModelList(),
6 - modelItem1 = new es.ModelItem(),
7 - modelItem2 = new es.ModelItem(),
8 - modelItem3 = new es.ModelItem();
 4+test( 'es.ModelNode', function() {
 5+ var modelNode1 = new es.ModelNode(),
 6+ modelNode2 = new es.ModelNode(),
 7+ modelNode3 = new es.ModelNode(),
 8+ modelNode4 = new es.ModelNode();
99
1010 // Event triggering is detected using a callback that increments a number
1111 var updates = 0;
12 - modelList.on( 'update', function() {
 12+ modelNode1.on( 'update', function() {
1313 updates++
1414 } );
1515
1616 // Array methods
1717
18 - modelList.push( modelItem1 );
19 - equal( updates, 1, 'es.modelList emits update events on push' );
20 - equal( modelList[0], modelItem1, 'es.modelList appends item on push' );
 18+ modelNode1.push( modelNode2 );
 19+ equal( updates, 1, 'es.ModelNode emits update events on push' );
 20+ equal( modelNode1[0], modelNode2, 'es.ModelNode appends Node on push' );
2121
22 - modelList.unshift( modelItem2 );
23 - equal( updates, 2, 'es.modelList emits update events on unshift' );
24 - equal( modelList[0], modelItem2, 'es.modelList prepends item on unshift' );
 22+ modelNode1.unshift( modelNode3 );
 23+ equal( updates, 2, 'es.ModelNode emits update events on unshift' );
 24+ equal( modelNode1[0], modelNode3, 'es.ModelNode prepends Node on unshift' );
2525
26 - modelList.splice( 1, 0, modelItem3 );
27 - equal( updates, 3, 'es.modelList emits update events on splice' );
28 - equal( modelList[1], modelItem3, 'es.modelList inserts item on splice' );
 26+ modelNode1.splice( 1, 0, modelNode4 );
 27+ equal( updates, 3, 'es.ModelNode emits update events on splice' );
 28+ equal( modelNode1[1], modelNode4, 'es.ModelNode inserts Node on splice' );
2929
30 - modelList.pop();
31 - equal( updates, 4, 'es.modelList emits update events on pop' );
 30+ modelNode1.pop();
 31+ equal( updates, 4, 'es.ModelNode emits update events on pop' );
3232 deepEqual(
33 - modelList.slice( 0 ),
34 - [modelItem2, modelItem3],
35 - 'es.modelList removes last item on pop'
 33+ modelNode1.slice( 0 ),
 34+ [modelNode3, modelNode4],
 35+ 'es.ModelNode removes last Node on pop'
3636 );
3737
38 - modelList.shift();
39 - equal( updates, 5, 'es.modelList emits update events on shift' );
 38+ modelNode1.shift();
 39+ equal( updates, 5, 'es.ModelNode emits update events on shift' );
4040 deepEqual(
41 - modelList.slice( 0 ),
42 - [modelItem3],
43 - 'es.modelList removes first item on shift'
 41+ modelNode1.slice( 0 ),
 42+ [modelNode4],
 43+ 'es.ModelNode removes first Node on shift'
4444 );
4545 } );
Index: trunk/parsers/wikidom/lib/hype/bases/es.ModelItem.js
@@ -1,125 +0,0 @@
2 -/**
3 - * Creates an es.ModelItem object.
4 - *
5 - * @class
6 - * @constructor
7 - * @extends {es.EventEmitter}
8 - * @property {es.ModelList} list Reference to list this item is in
9 - */
10 -es.ModelItem = function() {
11 - es.EventEmitter.call( this );
12 - this.list = null;
13 -};
14 -
15 -/* Methods */
16 -
17 -/**
18 - * Creates a view for this model.
19 - *
20 - * @method
21 - * @returns {es.ViewItem} New item view associated with this item model
22 - */
23 -es.ModelItem.prototype.createView = function() {
24 - throw 'ModelItem.createView not implemented in this subclass:' + this.constructor;
25 -};
26 -
27 -/**
28 - * Gets a reference to the list this item is in.
29 - *
30 - * @method
31 - * @returns {es.ModelList} Reference to this list this item is in
32 - */
33 -es.ModelItem.prototype.getList = function() {
34 - return this.list;
35 -};
36 -
37 -/**
38 - * Gets the index of this item within the list that it's in.
39 - *
40 - * @method
41 - * @returns {Integer} Index of item in it's list, -1 if not in a list
42 - */
43 -es.ModelItem.prototype.getIndex = function() {
44 - if ( this.list ) {
45 - return this.list.indexOf( this );
46 - }
47 - return -1;
48 -};
49 -
50 -/**
51 - * Attaches item to a list.
52 - *
53 - * @method
54 - * @param {es.Container} list Container to attach to
55 - * @emits attach (list)
56 - */
57 -es.ModelItem.prototype.attach = function( list ) {
58 - this.list = list;
59 - this.emit( 'attach', list );
60 -};
61 -
62 -/**
63 - * Detaches item from a list.
64 - *
65 - * @method
66 - * @emits detach (list)
67 - */
68 -es.ModelItem.prototype.detach = function() {
69 - var list = this.list;
70 - this.list = null;
71 - this.emit( 'detach', list );
72 -};
73 -
74 -/**
75 - * Gets the previous item in list.
76 - *
77 - * @method
78 - * @returns {es.ModelItem} Previous item, or undefined if none exists
79 - */
80 -es.ModelItem.prototype.getPreviousItem = function() {
81 - if ( this.list ) {
82 - return this.list[this.list.indexOf( this ) - 1];
83 - }
84 -};
85 -
86 -/**
87 - * Gets the next item in list.
88 - *
89 - * @method
90 - * @returns {Object} Next item, or undefined if none exists
91 - */
92 -es.ModelItem.prototype.getNextItem = function() {
93 - if ( this.list ) {
94 - return this.list[this.list.indexOf( this ) + 1];
95 - }
96 -};
97 -
98 -/**
99 - * Checks if this item is the first in it's list.
100 - *
101 - * @method
102 - * @returns {Boolean} If item is in a list and is also the first item in that list
103 - */
104 -es.ModelItem.prototype.isFirstItem = function() {
105 - if ( this.list ) {
106 - return this === this.list.getFirstItem();
107 - }
108 - return false;
109 -};
110 -
111 -/**
112 - * Checks if this item is the last in it's list.
113 - *
114 - * @method
115 - * @returns {Boolean} If item is in a list and is also the last item in that list
116 - */
117 -es.ModelItem.prototype.isLastItem = function() {
118 - if ( this.list ) {
119 - return this === this.list.getLastItem();
120 - }
121 - return false;
122 -};
123 -
124 -/* Inheritance */
125 -
126 -es.extend( es.ModelItem, es.EventEmitter );
Index: trunk/parsers/wikidom/lib/hype/bases/es.ViewList.js
@@ -1,132 +0,0 @@
2 -/**
3 - * Creates an es.ViewList object.
4 - *
5 - * View lists follow the operations performed on a model lists and keep a list of views,
6 - * each correlating to a model in the model list.
7 - *
8 - * This will override this.$ (important in case of multiple inheritance).
9 - *
10 - * @class
11 - * @constructor
12 - * @extends {es.EventEmitter}
13 - * @param model {es.ModelList} Model to observe
14 - * @param {jQuery} [$element=New DIV element] Element to use as a container
15 - * @property {es.ModelItem} model Model being observed
16 - * @property {jQuery} $ Container element
17 - */
18 -es.ViewList = function( model, $element ) {
19 - es.EventEmitter.call( this );
20 - var list = new es.AggregateArray();
21 -
22 - // Extending this class will initialize it without any arguments, exiting early if no model
23 - // was given will prevent clogging up subclass prototypes with array methods
24 - if ( !model ) {
25 - return this;
26 - }
27 -
28 - this.model = model;
29 - this.$ = $element || $( '<div/>' );
30 -
31 - // Reusable function for passing update events upstream
32 - this.emitUpdate = function() {
33 - list.emit( 'update' );
34 - };
35 -
36 - // Append existing model items
37 - for ( var i = 0; i < model.length; i++ ) {
38 - this.onPush( model[i] );
39 - }
40 -
41 - // Observe and mimic changes on model
42 - this.addListenerMethods( list, {
43 - 'push': 'onPush',
44 - 'unshift': 'onUnshift',
45 - 'pop': 'onPop',
46 - 'shift': 'onShift',
47 - 'splice': 'onSplice',
48 - 'sort': 'onSort',
49 - 'reverse': 'onReverse'
50 - } );
51 -
52 - // Extend native array with method and properties of this
53 - return $.extend( list, this );
54 -};
55 -
56 -es.ViewList.onPush = function( itemModel ) {
57 - var itemView = itemModel.createView();
58 - itemView.attach( this );
59 - itemView.on( 'update', this.emitUpdate );
60 - this.push( itemView );
61 - this.$.append( itemView.$ );
62 - this.emit( 'push', itemView );
63 - this.emit( 'update' );
64 -};
65 -
66 -es.ViewList.onUnshift = function( itemModel ) {
67 - var itemView = itemModel.createView();
68 - itemView.attach( this );
69 - itemView.on( 'update', this.emitUpdate );
70 - this.unshift( itemView );
71 - this.$.prepend( itemView.$ );
72 - this.emit( 'unshift', itemView );
73 - this.emit( 'update' );
74 -};
75 -
76 -es.ViewList.onPop = function() {
77 - var itemView = this.pop();
78 - itemView.detach();
79 - itemView.removeEventListener( 'update', this.emitUpdate );
80 - itemView.$.detach();
81 - this.emit( 'pop' );
82 - this.emit( 'update' );
83 -};
84 -
85 -es.ViewList.onShift = function() {
86 - var itemView = this.shift();
87 - itemView.detach();
88 - itemView.removeEventListener( 'update', this.emitUpdate );
89 - itemView.$.detach();
90 - this.emit( 'shift' );
91 - this.emit( 'update' );
92 -};
93 -
94 -es.ViewList.onSplice = function( index, howmany ) {
95 - var args = Array.prototype.slice( arguments, 0 ),
96 - added = args.slice( 2 ),
97 - removed = this.splice.apply( this, args );
98 - this.$.children().slice( index, index + howmany ).detach();
99 - var $added = $.map( added, function( itemView ) {
100 - return itemView.$;
101 - } );
102 - this.$.children().get( index ).after( $added );
103 - this.emit.apply( ['splice'].concat( args ) );
104 - this.emit( 'update' );
105 -};
106 -
107 -es.ViewList.onSort = function() {
108 - for ( var i = 0; i < this.model.length; i++ ) {
109 - for ( var j = 0; j < this.length; j++ ) {
110 - if ( this[j].getModel() === this.model[i] ) {
111 - var itemView = this[j];
112 - this.splice( j, 1 );
113 - this.push( itemView );
114 - this.$.append( itemView.$ );
115 - }
116 - }
117 - }
118 - this.emit( 'sort' );
119 - this.emit( 'update' );
120 -};
121 -
122 -es.ViewList.onReverse = function() {
123 - this.reverse();
124 - this.$.children().each( function() {
125 - $(this).prependTo( $(this).parent() );
126 - } );
127 - this.emit( 'reverse' );
128 - this.emit( 'update' );
129 -};
130 -
131 -/* Inheritance */
132 -
133 -es.extend( es.ViewList, es.EventEmitter );
Index: trunk/parsers/wikidom/lib/hype/bases/es.ViewItem.js
@@ -1,76 +0,0 @@
2 -/**
3 - * Generic synchronized Object/Element container item.
4 - * This will override this.$ (important in case of multiple inheritance).
5 - *
6 - * @class
7 - * @constructor
8 - * @extends {es.EventEmitter}
9 - * @param {jQuery} $element jQuery object to use
10 - * @property {jQuery} $ Container element
11 - */
12 -es.ViewItem = function( model, $element ) {
13 - es.EventEmitter.call( this );
14 - this.model = model;
15 - this.$ = $element || $( '<div/>' );
16 - this.list = null;
17 -};
18 -
19 -/**
20 - * Gets a reference to the model this item observes.
21 - *
22 - * @method
23 - * @returns {es.ModelList} Reference to the model this item observes
24 - */
25 -es.ViewItem.prototype.getModel = function() {
26 - return this.model;
27 -};
28 -
29 -/**
30 - * Gets a reference to the list this item is in.
31 - *
32 - * @method
33 - * @returns {es.ModelList} Reference to this list this item is in
34 - */
35 -es.ViewItem.prototype.getList = function() {
36 - return this.list;
37 -};
38 -
39 -/**
40 - * Gets the index of this item within it's list.
41 - *
42 - * This method simply delegates to the model.
43 - *
44 - * @method
45 - * @returns {Integer} Index of item in it's container
46 - */
47 -es.ViewItem.prototype.getIndex = function() {
48 - return this.model.getIndex();
49 -};
50 -
51 -/**
52 - * Attaches item to a list.
53 - *
54 - * @method
55 - * @param {es.Container} list Container to attach to
56 - * @emits attach (list)
57 - */
58 -es.ViewItem.prototype.attach = function( list ) {
59 - this.list = list;
60 - this.emit( 'attach', list );
61 -};
62 -
63 -/**
64 - * Detaches item from a list.
65 - *
66 - * @method
67 - * @emits detach (list)
68 - */
69 -es.ViewItem.prototype.detach = function() {
70 - var list = this.list;
71 - this.list = null;
72 - this.emit( 'detach', list );
73 -};
74 -
75 -/* Inheritance */
76 -
77 -es.extend( es.ViewItem, es.EventEmitter );
\ No newline at end of file
Index: trunk/parsers/wikidom/lib/hype/bases/es.ModelList.js
@@ -1,182 +0,0 @@
2 -/**
3 - * Creates an es.ModelList object.
4 - *
5 - * es.ModelList extends native JavaScript Array objects, without changing Array.prototype by
6 - * dynamically extending an array literal with the methods of es.ModelList.
7 - *
8 - * Child objects must extend es.ModelItem.
9 - *
10 - * @class
11 - * @constructor
12 - * @extends {Array}
13 - * @extends {es.EventEmitter}
14 - */
15 -es.ModelList = function( items ) {
16 - es.EventEmitter.call( this );
17 - var list = new es.AggregateArray( list );
18 -
19 - // Reusable function for passing update events upstream
20 - this.emitUpdate = function() {
21 - list.emit( 'update' );
22 - };
23 -
24 - // Extend native array with method and properties of this
25 - return $.extend( list, this );
26 -};
27 -
28 -/* Methods */
29 -
30 -/**
31 - * Gets the first item in the list.
32 - *
33 - * @method
34 - * @returns {es.ModelItem|undefined} First item in the list, or undefined if none exists
35 - */
36 -es.ModelList.prototype.getFirstItem = function() {
37 - return this[0];
38 -};
39 -
40 -/**
41 - * Gets the last item in the list.
42 - *
43 - * @method
44 - * @returns {es.ModelItem|undefined} last item in the list, or undefined if none exists
45 - */
46 -es.ModelList.prototype.getLastItem = function() {
47 - return this[this.length - 1];
48 -};
49 -
50 -/**
51 - * Adds an item to the end of the list.
52 - *
53 - * @method
54 - * @param {es.ModelItem} item Item to add
55 - * @returns {Integer} New length of list
56 - * @emits push (item)
57 - * @emits update
58 - */
59 -es.ModelList.prototype.push = function( item ) {
60 - item.attach( this );
61 - item.on( 'update', this.emitUpdate );
62 - Array.prototype.push.call( this, item );
63 - this.emit( 'push', item );
64 - this.emit( 'update' );
65 - return this.length;
66 -};
67 -
68 -/**
69 - * Adds an item to the beginning of the list.
70 - *
71 - * @method
72 - * @param {es.ModelItem} item Item to add
73 - * @returns {Integer} New length of list
74 - * @emits unshift (item)
75 - * @emits update
76 - */
77 -es.ModelList.prototype.unshift = function( item ) {
78 - item.attach( this );
79 - item.on( 'update', this.emitUpdate );
80 - Array.prototype.unshift.call( this, item );
81 - this.emit( 'unshift', item );
82 - this.emit( 'update' );
83 - return this.length;
84 -};
85 -
86 -/**
87 - * Removes an item from the end of the list.
88 - *
89 - * @method
90 - * @returns {Integer} Removed item
91 - * @emits pop
92 - * @emits update
93 - */
94 -es.ModelList.prototype.pop = function() {
95 - if ( this.length ) {
96 - var item = this[this.length - 1];
97 - item.detach();
98 - item.removeListener( 'update', this.emitUpdate );
99 - Array.prototype.pop.call( this, item );
100 - this.emit( 'pop' );
101 - this.emit( 'update' );
102 - return item;
103 - }
104 -};
105 -
106 -/**
107 - * Removes an item from the beginning of the list.
108 - *
109 - * @method
110 - * @returns {Integer} Removed item
111 - * @emits shift
112 - * @emits update
113 - */
114 -es.ModelList.prototype.shift = function() {
115 - if ( this.length ) {
116 - var item = this[0];
117 - item.detach();
118 - item.removeListener( 'update', this.emitUpdate );
119 - Array.prototype.shift.call( this, item );
120 - this.emit( 'shift' );
121 - this.emit( 'update' );
122 - return item;
123 - }
124 -};
125 -
126 -/**
127 - * Removes an item from the beginning of the list.
128 - *
129 - * @method
130 - * @param {Integer} index Index to remove and or insert items
131 - * @param {Integer} howmany Number of items to remove
132 - * @param {es.ModelItem} [...] Variadic list of items to insert
133 - * @returns {es.ModelItem[]} Removed items
134 - * @emits splice (index, howmany, [...])
135 - * @emits update
136 - */
137 -es.ModelList.prototype.splice = function( index, howmany ) {
138 - var args = Array.prototype.slice.call( arguments, 0 );
139 - if ( args.length >= 3 ) {
140 - for ( var i = 2; i < args.length; i++ ) {
141 - args[i].attach( this );
142 - }
143 - }
144 - var removed = Array.prototype.splice.apply( this, args );
145 - for ( var i = 0; i < removed.length; i++ ) {
146 - removed[i].detach();
147 - removed[i].removeListener( 'update', this.emitUpdate );
148 - }
149 - this.emit.apply( this, ['splice'].concat( args ) );
150 - this.emit( 'update' );
151 - return removed;
152 -};
153 -
154 -/**
155 - * Sorts items in list.
156 - *
157 - * @method
158 - * @param {Function} sortfunc Function to use when sorting
159 - * @emits sort
160 - * @emits update
161 - */
162 -es.ModelList.prototype.sort = function( sortfunc ) {
163 - this.emit( 'sort' );
164 - this.emit( 'update' );
165 - Array.prototype.sort.call( this );
166 -};
167 -
168 -/**
169 - * Reverses the order of the list.
170 - *
171 - * @method
172 - * @emits reverse
173 - * @emits update
174 - */
175 -es.ModelList.prototype.reverse = function() {
176 - this.emit( 'reverse' );
177 - this.emit( 'update' );
178 - Array.prototype.reverse.call( this );
179 -};
180 -
181 -/* Inheritance */
182 -
183 -es.extend( es.ModelList, es.EventEmitter );
Index: trunk/parsers/wikidom/lib/hype/bases/es.ViewNode.js
@@ -0,0 +1,180 @@
 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+ var node = [];
 24+
 25+ // Extending this class will initialize it without any arguments, exiting early if no model
 26+ // was given will prevent clogging up subclass prototypes with array methods
 27+ if ( !model ) {
 28+ return this;
 29+ }
 30+
 31+ this.model = model;
 32+ this.$ = $element || $( '<div/>' );
 33+
 34+ // Reusable function for passing update events upstream
 35+ this.emitUpdate = function() {
 36+ node.emit( 'update' );
 37+ };
 38+
 39+ // Append existing model children
 40+ for ( var i = 0; i < model.length; i++ ) {
 41+ this.onPush( model[i] );
 42+ }
 43+
 44+ // Observe and mimic changes on model
 45+ this.addListenerMethods( node, {
 46+ 'push': 'onPush',
 47+ 'unshift': 'onUnshift',
 48+ 'pop': 'onPop',
 49+ 'shift': 'onShift',
 50+ 'splice': 'onSplice',
 51+ 'sort': 'onSort',
 52+ 'reverse': 'onReverse'
 53+ } );
 54+
 55+ // Extend native array with method and properties of this
 56+ return $.extend( node, this );
 57+};
 58+
 59+es.ViewNode.onPush = function( childModel ) {
 60+ var childView = childModel.createView();
 61+ childView.attach( this );
 62+ childView.on( 'update', this.emitUpdate );
 63+ this.push( childView );
 64+ this.$.append( childView.$ );
 65+ this.emit( 'push', childView );
 66+ this.emit( 'update' );
 67+};
 68+
 69+es.ViewNode.onUnshift = function( childModel ) {
 70+ var childView = childModel.createView();
 71+ childView.attach( this );
 72+ childView.on( 'update', this.emitUpdate );
 73+ this.unshift( childView );
 74+ this.$.prepend( childView.$ );
 75+ this.emit( 'unshift', childView );
 76+ this.emit( 'update' );
 77+};
 78+
 79+es.ViewNode.onPop = function() {
 80+ var childView = this.pop();
 81+ childView.detach();
 82+ childView.removeEventListener( 'update', this.emitUpdate );
 83+ childView.$.detach();
 84+ this.emit( 'pop' );
 85+ this.emit( 'update' );
 86+};
 87+
 88+es.ViewNode.onShift = function() {
 89+ var childView = this.shift();
 90+ childView.detach();
 91+ childView.removeEventListener( 'update', this.emitUpdate );
 92+ childView.$.detach();
 93+ this.emit( 'shift' );
 94+ this.emit( 'update' );
 95+};
 96+
 97+es.ViewNode.onSplice = function( index, howmany ) {
 98+ var args = Array.prototype.slice( arguments, 0 ),
 99+ added = args.slice( 2 ),
 100+ removed = this.splice.apply( this, args );
 101+ this.$.children().slice( index, index + howmany ).detach();
 102+ var $added = $.map( added, function( childView ) {
 103+ return childView.$;
 104+ } );
 105+ this.$.children().get( index ).after( $added );
 106+ this.emit.apply( ['splice'].concat( args ) );
 107+ this.emit( 'update' );
 108+};
 109+
 110+es.ViewNode.onSort = function() {
 111+ for ( var i = 0; i < this.model.length; i++ ) {
 112+ for ( var j = 0; j < this.length; j++ ) {
 113+ if ( this[j].getModel() === this.model[i] ) {
 114+ var childView = this[j];
 115+ this.splice( j, 1 );
 116+ this.push( childView );
 117+ this.$.append( childView.$ );
 118+ }
 119+ }
 120+ }
 121+ this.emit( 'sort' );
 122+ this.emit( 'update' );
 123+};
 124+
 125+es.ViewNode.onReverse = function() {
 126+ this.reverse();
 127+ this.$.children().each( function() {
 128+ $(this).prependTo( $(this).parent() );
 129+ } );
 130+ this.emit( 'reverse' );
 131+ this.emit( 'update' );
 132+};
 133+
 134+
 135+/**
 136+ * Gets a reference to the model this node observes.
 137+ *
 138+ * @method
 139+ * @returns {es.ModelNode} Reference to the model this node observes
 140+ */
 141+es.ViewNode.prototype.getModel = function() {
 142+ return this.model;
 143+};
 144+
 145+/**
 146+ * Gets a reference to this node's parent.
 147+ *
 148+ * @method
 149+ * @returns {es.ViewNode} Reference to this node's parent
 150+ */
 151+es.ViewNode.prototype.getParent = function() {
 152+ return this.parent;
 153+};
 154+
 155+/**
 156+ * Attaches node as a child to another node.
 157+ *
 158+ * @method
 159+ * @param {es.ViewNode} parent Node to attach to
 160+ * @emits attach (parent)
 161+ */
 162+es.ViewNode.prototype.attach = function( parent ) {
 163+ this.parent = parent;
 164+ this.emit( 'attach', parent );
 165+};
 166+
 167+/**
 168+ * Detaches node from it's parent.
 169+ *
 170+ * @method
 171+ * @emits detach (parent)
 172+ */
 173+es.ViewNode.prototype.detach = function() {
 174+ var parent = this.parent;
 175+ this.parent = null;
 176+ this.emit( 'detach', parent );
 177+};
 178+
 179+/* Inheritance */
 180+
 181+es.extend( es.ViewNode, es.EventEmitter );
Index: trunk/parsers/wikidom/lib/hype/bases/es.DocumentModelNode.js
@@ -7,6 +7,9 @@
88 * @property {Integer} contentLength Length of contents
99 */
1010 es.DocumentModelNode = function( contentLength ) {
 11+ // Inheritance
 12+ es.ModelNode.call( this );
 13+
1114 // Properties
1215 this.contentLength = contentLength || 0;
1316 };
@@ -20,3 +23,7 @@
2124 es.DocumentModelNode.getElementLength = function() {
2225 return this.contentLength + 2;
2326 };
 27+
 28+/* Inheritance */
 29+
 30+es.extend( es.DocumentModelNode, es.ModelNode );
Index: trunk/parsers/wikidom/lib/hype/bases/es.ModelNode.js
@@ -0,0 +1,207 @@
 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+ var node = $.isArray( children ) ? children : [];
 19+
 20+ // Reusable function for passing update events upstream
 21+ this.emitUpdate = function() {
 22+ node.emit( 'update' );
 23+ };
 24+
 25+ // Extend native array with method and properties of this
 26+ return $.extend( node, this );
 27+};
 28+
 29+/* Methods */
 30+
 31+/**
 32+ * Adds a node to the end of this node's children.
 33+ *
 34+ * @method
 35+ * @param {es.ModelItem} childModel Item to add
 36+ * @returns {Integer} New number of children
 37+ * @emits push (childModel)
 38+ * @emits update
 39+ */
 40+es.ModelNode.prototype.push = function( childModel ) {
 41+ childModel.attach( this );
 42+ childModel.on( 'update', this.emitUpdate );
 43+ Array.prototype.push.call( this, childModel );
 44+ this.emit( 'push', childModel );
 45+ this.emit( 'update' );
 46+ return this.length;
 47+};
 48+
 49+/**
 50+ * Adds a node to the beginning of this node's children.
 51+ *
 52+ * @method
 53+ * @param {es.ModelItem} childModel Item to add
 54+ * @returns {Integer} New number of children
 55+ * @emits unshift (childModel)
 56+ * @emits update
 57+ */
 58+es.ModelNode.prototype.unshift = function( childModel ) {
 59+ childModel.attach( this );
 60+ childModel.on( 'update', this.emitUpdate );
 61+ Array.prototype.unshift.call( this, childModel );
 62+ this.emit( 'unshift', childModel );
 63+ this.emit( 'update' );
 64+ return this.length;
 65+};
 66+
 67+/**
 68+ * Removes a node from the end of this node's children
 69+ *
 70+ * @method
 71+ * @returns {Integer} Removed childModel
 72+ * @emits pop
 73+ * @emits update
 74+ */
 75+es.ModelNode.prototype.pop = function() {
 76+ if ( this.length ) {
 77+ var childModel = this[this.length - 1];
 78+ childModel.detach();
 79+ childModel.removeListener( 'update', this.emitUpdate );
 80+ Array.prototype.pop.call( this, childModel );
 81+ this.emit( 'pop' );
 82+ this.emit( 'update' );
 83+ return childModel;
 84+ }
 85+};
 86+
 87+/**
 88+ * Removes a node from the beginning of this node's children
 89+ *
 90+ * @method
 91+ * @returns {Integer} Removed childModel
 92+ * @emits shift
 93+ * @emits update
 94+ */
 95+es.ModelNode.prototype.shift = function() {
 96+ if ( this.length ) {
 97+ var childModel = this[0];
 98+ childModel.detach();
 99+ childModel.removeListener( 'update', this.emitUpdate );
 100+ Array.prototype.shift.call( this, childModel );
 101+ this.emit( 'shift' );
 102+ this.emit( 'update' );
 103+ return childModel;
 104+ }
 105+};
 106+
 107+/**
 108+ * Adds and removes nodes from this node's children.
 109+ *
 110+ * @method
 111+ * @param {Integer} index Index to remove and or insert nodes at
 112+ * @param {Integer} howmany Number of nodes to remove
 113+ * @param {es.ModelItem} [...] Variadic list of nodes to insert
 114+ * @returns {es.ModelItem[]} Removed nodes
 115+ * @emits splice (index, howmany, [...])
 116+ * @emits update
 117+ */
 118+es.ModelNode.prototype.splice = function( index, howmany ) {
 119+ var args = Array.prototype.slice.call( arguments, 0 );
 120+ if ( args.length >= 3 ) {
 121+ for ( var i = 2; i < args.length; i++ ) {
 122+ args[i].attach( this );
 123+ }
 124+ }
 125+ var removed = Array.prototype.splice.apply( this, args );
 126+ for ( var i = 0; i < removed.length; i++ ) {
 127+ removed[i].detach();
 128+ removed[i].removeListener( 'update', this.emitUpdate );
 129+ }
 130+ this.emit.apply( this, ['splice'].concat( args ) );
 131+ this.emit( 'update' );
 132+ return removed;
 133+};
 134+
 135+/**
 136+ * Sorts this node's children.
 137+ *
 138+ * @method
 139+ * @param {Function} sortfunc Function to use when sorting
 140+ * @emits sort
 141+ * @emits update
 142+ */
 143+es.ModelNode.prototype.sort = function( sortfunc ) {
 144+ this.emit( 'sort' );
 145+ this.emit( 'update' );
 146+ Array.prototype.sort.call( this );
 147+};
 148+
 149+/**
 150+ * Reverses the order of this node's children.
 151+ *
 152+ * @method
 153+ * @emits reverse
 154+ * @emits update
 155+ */
 156+es.ModelNode.prototype.reverse = function() {
 157+ this.emit( 'reverse' );
 158+ this.emit( 'update' );
 159+ Array.prototype.reverse.call( this );
 160+};
 161+
 162+/**
 163+ * Gets a reference to this node's parent.
 164+ *
 165+ * @method
 166+ * @returns {es.ModelNode} Reference to this node's parent
 167+ */
 168+es.ModelNode.prototype.getParent = function() {
 169+ return this.parent;
 170+};
 171+
 172+/**
 173+ * Attaches this node to another as a child.
 174+ *
 175+ * @method
 176+ * @param {es.ModelNode} parent Node to attach to
 177+ * @emits attach (parent)
 178+ */
 179+es.ModelNode.prototype.attach = function( parent ) {
 180+ this.parent = parent;
 181+ this.emit( 'attach', parent );
 182+};
 183+
 184+/**
 185+ * Detaches this node from it's parent.
 186+ *
 187+ * @method
 188+ * @emits detach (parent)
 189+ */
 190+es.ModelNode.prototype.detach = function() {
 191+ var parent = this.parent;
 192+ this.parent = null;
 193+ this.emit( 'detach', parent );
 194+};
 195+
 196+/**
 197+ * Creates a view for this node.
 198+ *
 199+ * @method
 200+ * @returns {es.ViewNode} New item view associated with this model
 201+ */
 202+es.ModelNode.prototype.createView = function() {
 203+ throw 'ModelItem.createView not implemented in this subclass:' + this.constructor;
 204+};
 205+
 206+/* Inheritance */
 207+
 208+es.extend( es.ModelNode, es.EventEmitter );

Status & tagging log