-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdomo_on_routes.js
316 lines (238 loc) · 9.08 KB
/
domo_on_routes.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
// domoOnRoutes.js 0.1.1
// (c) 2013 M.( Mathias Prinz )
// is distributed under the MIT license.
! function () {
typeof module == "object"
? module.exports = Route
: window.ROUTE = Route
;
function Route () {
var args = copy( arguments )
, attributes = args.shift()
, lookup
, domo = domo || carton
;
function findState ( childs, state, followers, actions ) {
var child = childs.shift();
var isRegEx = child instanceof RegExp;
var match = matches( child );
// if state can't be found
if ( ! child && ! state ) {
manageLookup( [ '','' ], [], [] );
return stateIntoDom();
}
// if state has collected all
// childNodes create an entry in
// the lookup to cache the result
// and change the current state
if ( state && isRegEx || ! child ) {
manageLookup( state, followers, actions );
return stateIntoDom();
}
// every argument that follows
// the namespace is part of the
// matched state.
// if argument is an function
// remember it's position and body in actions
if ( state && ! isRegEx ) pushFollower( child, followers, actions );
// every reqular expression in
// the arguments is a state
// namespace if namespace could
// be found in url state will be
// defined to collect the following
// arguments until a new reqular
// expression follows
if ( ! state && isRegEx && match ) {
state = [ child, match ];
followers = [];
actions = [];
}
return arguments.callee( childs, state, followers, actions );
} // find state
function pushFollower ( arg, followers, actions, nameSpace ) {
if ( arg.apply ) actions.push( { func: arg, index: followers.length } );
followers.push( arg );
}
// insert state as object
// to the lookup table or
// updates if sate already
// exist
function manageLookup ( route, children, actions ) {
var name = route.join( '-' );
var match = route[ 1 ];
children = copy( children );
if ( ! lookup ) lookup = {};
if ( lookup.current ) lookup.previous = lookup.current;
if ( lookup && lookup[ name ] ) {
refreshActions( lookup[ name ], match );
lookup.current = lookup[ name ];
}
else {
initActions( actions, children, match );
lookup.current = lookup[ name ] = {
frag: domo.FRAGMENT.apply( null, children )
, actions: actions
, route: route
};
}
}
function stateIntoDom () {
return ( ! lookup.DOMFrame ? DOMFrame() : switchInDom() );
}
function DOMFrame () {
var domFrame = attributes.frame || domo.SECTION;
return lookup.DOMFrame = domFrame.apply( null, copy( lookup.current.frag.childNodes ) );
}
// take a look on a string ( url ) if a regular expression is part of it
function matches ( regEx ) {
if ( regEx instanceof RegExp === false ) return null;
var match = getUrl().match( regEx );
if ( match ) match = match[ 0 ];
return match;
}
// make copy of an array
// concat = Array.prototype.concat and
// concat.apply( [], element.childNodes )
// made problems with android native
// browser "internet"
function copy ( arr ) {
var deep = [], l = arr.length, i = 0;
for ( ; i < l; i = i + 1 ) { deep[ i ] = arr[ i ]; }
return deep;
}
// url can be set in attributes obj
// as { url: string } or instead of
// the attributes obj.
function getUrl () {
var url = typeof attributes === 'string' ? attributes : attributes.url;
return ( url.apply ? url() : url );
}
// run actions ( functions ) in single
// domoFRAGMENTS before they where put to
// the other children of the current
// lookup obj ( sate ) to be added
// together to objects fragment. This
// happend to bind the results of the triggert
// function ( childNodes of the single frag )
// to the action to update the results on a later
// reload of this state in realtime
function initActions ( actions, children, match ) {
if ( ! actions.length ) return;
var i = 0, l = actions.length;
var action = actions[ i ].func;
var actionFrag;
for ( ; i < l; i = i + 1 ) {
actionFrag = domo.FRAGMENT( action( match ) );
children[ actions[ i ].index ] = actionFrag;
actions[ i ].index = copy( actionFrag.childNodes );
}
}
// replaces former generated results ( childNodes )
// of an action, owned by an state already existing
function refreshActions ( obj, match ) {
if ( ! obj.actions.length || ! obj.frag.childNodes.length ) return;
var actions = obj.actions;
var i = 0, l = actions.length;
var frag = obj.frag;
var actionFrag;
var index;
function trigger ( action ) {
index = action.index;
actionFrag = domo.FRAGMENT.call( domo, action.func( match ) )
var i = 0, l = index.length;
for ( ; i < l; i++ ) updateChildren( i );
}
function updateChildren () {
var previous = index[ i ];
var following = actionFrag.childNodes[ i ];
index[ i ] = following;
frag.replaceChild( following, previous );
}
for ( ; i < l; i++ ) trigger( actions[ i ] );
}
// Bring state changes into DOM
// by copying the previous childs into lookup
// and following childs from lookup
function switchInDom () {
var previousChildren = copy( lookup.DOMFrame.childNodes );
var previous = lookup.previous;
var following = lookup.current;
if ( following.frag.childNodes.length && following.route ) {
dramaturgy(
copy( following.frag.childNodes )
, previousChildren
, function () {
// move current childNodes from
// dom to related dom fragment
// into lookup ( "Remove" previous state )
add( previous.frag, previousChildren );
// move childNodes form the following state
// out of lookup into dom ( "Create" next state )
add( lookup.DOMFrame, following.frag );
}
)
}
// none state is aktive in the dom
if ( ! following.route[ 0 ] ) {
dramaturgy( [], previousChildren, function () {
// move current childNodes from
// dom to related dom fragment
// into lookup ( "Remove" previous state )
add( previous.frag, previousChildren );
})
}
return lookup.DOMFrame;
}
// filter nodes by a special nodeType
function filterNodes ( n, type ) {
var filter = [];
var i = 0;
var l = n.length;
for ( ; i < l; i++ ) {
if ( n[ i ].nodeType == type ) {
filter.push( n[ i ] );
}
}
return filter;
}
// if childNodes need to be prepared before a drama
// can be startes, the dramaturgy callback will be triggered
// before, marked as initialisation ( 'init ') call by the
// first argument
function initDramaturgy ( children, moveOn ) {
var drama = attributes.dramaturgy;
if ( ! drama || !lookup.current ) { moveOn(); }
else { drama( 'init', children, moveOn ); }
}
// if a dramaturgy is defined in attributes it will be triggerd
// before the previous ( old ) state will be removed, after that
// if a state will follow it is triggerd again
function dramaturgy ( following, previous, moveOn ) {
if ( ! attributes.dramaturgy ) { moveOn(); return; }
following = filterNodes( following, 1 );
previous = filterNodes( previous, 1 );
var drama = attributes.dramaturgy;
var dramaPrevious = function () { drama( false, previous, ( following.length ? dramaFollow : moveOn ) ); }
var dramaFollow = function () {
moveOn();
initDramaturgy(
following
, function () {
drama( true, following, function () {} );
}
)
}
if ( ! previous.length ) dramaFollow();
else dramaPrevious();
}
// add child
function add ( dom, frag ) {
dom.appendChild( frag instanceof Array ? domo.FRAGMENT.apply( domo, frag ) : frag );
}
// trigger callback
if ( attributes.change ) {
attributes.change( function () { return findState.call( null, args.slice() ); } );
}
return findState.call( null, args.slice() );
}
}()