-
Notifications
You must be signed in to change notification settings - Fork 16
/
backbone_marionette.javascript.txt
792 lines (689 loc) · 55.8 KB
/
backbone_marionette.javascript.txt
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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
BACKBONE/MARIONETTE
VERSION ==> #Backbone 1.2.3, must load first:
# - Underscore (depends on 1.6.0) or Lodash
# - jQuery, set to Backbone.$ (can be overriden)
#Marionette 2.4.4, must load first Backbone (depends on 1.2.3)
#Marionette has the chapters starting with M*
Backbone #Global object
#Can be unset and returned by Backbone.noConflict()
Mn|[Backbone.]Marionette #MARIONETTE
UNDERSCORE/LODASH ==> #Mix in some methods:
# - MODEL:
# - main: chain()
# - basic: keys|values()
# - type checking: isEmpty()
# - filtering: pick|omit()
# - processing: pairs|invert()
# - helper: matches()
# - COLL/MREGIONMANAGER/MLAYOUTVIEW:
# - main: chain()
# - basic: size|toArray()
# - type checking: isEmpty()
# - finding: find|[lastI|i]ndexOf()
# - testing: every|some|contains
# - filtering: filter|reject|first|initial|rest|last|sample|without|difference()
# - processing: forEach|map|reduce[Right]|invoke|groupBy|countBy|indexBy|partition()
# - sorting: sortBy|shuffle()
# - math: max|min()
# - CHILDVIEWCTNER:
# - type checking: isEmpty()
# - cloning/creating: toArray()
# - finding: find()
# - testing: every|some|contains
# - filtering: filter|reject|first|initial|rest|last|without()
# - processing: forEach|map|reduce|invoke|pluck()
IN SHORT ==> # - G*: basic object, allowing OO with extend|initialize()
# - MOBJECT: also MOBJECT.options, specified at instantiation
# - EVENTS: like EventEmitter in Node
# - MEVENT: also fire MOBJECT.onMEVENT(...)
# - RADIO: global (augmented) EVENTS
# - MAPPLICATION/MMODULE: global/local objects where the app is assigned, loaded in order
# - MODEL: an augmented OBJ (or database row server-side), with events, synced server-side
# - COLL: MODEL_ARR (or database table server-side). Can be auto-sorted.
# - ROUTER: callbacks fired when URL changes
# - MAPPROUTER: dissocie appRoutes (routing) from handlers (controller)
# - VIEW: DOM element, setting up event handlers
# - MVIEW: listening to MODEL|COLLECTION events, firing MEVENT, dissociate MVIEW.ui from
# MVIEW.behaviors (event triggering/handling)
# - MITEMVIEW: render() which gets simple template SELECTOR, can add templateHelpers
# - MCOLLVIEW: MITEMVIEW_ARR, updating with changes. Can have empty MVIEW.
# Can listen to children MEVENT. Can auto-sort and filter.
# - MCOMPVIEW: MITEMVIEW + MCOLLVIEW
# - MLAYOUTVIEW: MITEMVIEW with regions, i.e. containers of other MVIEW
RECURSION ==> #Events:
# - MCOLLVIEW|MLAYOUTVIEW gets children events as "childview:EVENT", except initial "render"
# - childEvents: for easy child events handling
#render():
# - MCOLLVIEW|MLAYOUTVIEW render their children, but children can render themselves without
# parent rendering itself
#showChildView(): children must use showChildView() themselves in beforeShow event handler
PERFORMANCE ==> #Optimize number of calls to:
# - Backbone.sync(), i.e. MODEL.fetch|save|destroy() and COLL.fetch|create()
# - render():
# - only when DOM changes (e.g. do not call if model did not change)
# - prefer calling on lowest possible descendant[s], e.g. on parent if all children need
# to be rendered, or on few of its children if only some of them need to be rendered.
MODEL SYNC ==> #MCOLLVIEW listens to COLL events, but MITEMVIEW must explicitely do it, e.g.
# modelEvents: { change: "render" }
CHROME EXTENSIONS ==> # - Backbone Debugger 0.3.0: show VIEW, MODEL, COLLECTION, ROUTER attributes|events
# - Marionette Inspector 0.5.6: show Marionette types attributes|events
# - if Backbone|Marionette not global objects, must call:
# if (window.__agent) { window.__agent.start(Backbone, Marionette); }
/=+===============================+=\
/ : : \
)==: GENERAL :==(
\ :_______________________________: /
\=+===============================+=/
G* #Means MODEL|COLLECTION|ROUTER|HISTORY|VIEW. Inherits from EVENTS.
#Describe the object system used by main Backbone objects
Backbone.G* #Root G*_TYPE, camelcase, e.g. Backbone.Collection
G*_PARENT_TYPE.extend #Returns G*_TYPE. Like normal inheritance except:
([OBJ[, OBJ2]]) # - different syntax:
# - OBJ.constructor(...) instead of constructor G*_TYPE(...)
# (def: just call G*_PARENT_TYPE() with same args)
# - use OBJ|OBJ2 instead of assigning manually to
# G*_TYPE.prototype (shared members) and G*_TYPE (static members)
# (using _.extend())
# - extra features:
# - inherits static members (using _.extend())
# - G*_TYPE.__super__ === G*_TYPE_PARENT.prototype
# - using extend(OBJ.prototype) allows easily doing mixins,
# for multiple inheritance
#Equivalent in ES6:
# class G*_TYPE extends G*_PARENT_TYPE {
# constructor() // OBJ.constructor
# [static] FUNC() // OBJ[2].FUNC
# }
#Differences:
# - G*.super -> G*_TYPE.__super__ + G*_TYPE.__super__.constructor
# - OBJ|OBJ2.VAR do not have to be FUNC
# - inherits static members
G*_TYPE.prototype.initialize(...) #All G* constructor call this at the end, with same arguments.
#Used to allow augmenting a constructor instead of overriding it.
MARIONETTE.Object #MOBJECT: is a G* with some extra methods. See also MEVENT below.
#Main Marionette objects are MOBJECT: MAPPLICATION, MAPPROUTER, MVIEW, MBEHAVIOR, MREGION
MOBJECT.options #Is OBJ[()], which can be overriden by new MOBJECT_TYPE([OBJ])
#Exceptions:
# - MAPPROUTER can only use MOBJECT_TYPE to define it
# - MVIEW can use new MOBJECT_TYPE([OBJ[()]])
MOBJECT.getOption("VAR") #Returns either OBJ.options.VAR or OBJ.VAR
MOBJECT..VAR #Notation for MOBJECT.getOption('VAR')
MOBJECT.mergeOptions
(OBJ, STR[_ARR]) #Adds each OBJ[STR] to MOBJECT[STR]
/=+===============================+=\
/ : : \
)==: MAPPLICATION/MMODULE :==(
\ :_______________________________: /
\=+===============================+=/
MARIONETTE.Module #MMODULE: set of objects getting initialized/stopped and attached to MMODULE together.
#Is a G* but not a MOBJECT
new MMODULE_TYPE
("MODULE", MAPPLICATION, OBJ) #MMODULE.moduleName|app|options gets arguments
MMODULE.start(OBJ)|stop() #Fires MEVENT [before:]start(OBJ)|stop()
#Calls all children MMODULE2.start(OBJ)|stop unless MMODULE2.startWithParent false,
#starting with descendants.
#Idempotent operation.
MARIONETTE.Application #MAPPLICATION: global/main object
MAPPLICATION.module("MODULE") #Retrieve registered MMODULE
MAPPLICATION.module #Register new MMODULE_TYPE("MODULE", MAPPLICATION, OBJ) then fires:
("MODULE", OBJ[, ...]) # - OBJ|MMODULE.define(MMODULE, MAPPLICATION, BACKBONE, MARIONETTE, JQ, __, ...)
# Called at each MAPPLICATION.module("MODULE", OBJ), cannot be inherited.
# - OBJ|MMODULE.initialize("MODULE", MAPPLICATION, OBJ)
# Called only once, can be inherited.
#Can use "MODULE.SUBMODULE...": will create MMODULE.submodules chain
#MMODULE_TYPE: can redefine with OBJ.moduleClass
#OBJ can be:
# - FUNC instead of { define FUNC }
# - MMODULE_TYPE instead of { moduleClass MMODULE_TYPE }
MMODULE|MAPPLICATION.submodules #{ "MODULE": MMODULE ... } children
MAPPLICATION.start([OBJ]) #Trigger each MMODULE.start([OBJ]), including the ones define afterwards, as soon as
#they are defined.
#Fires MEVENT [before:]start(OBJ)
MAPPLICATION.addInitializer #Same as MAPPLICATION.on("start", FUNC(OBJ)) but:
(FUNC([OBJ])) # - actually fired between before:start and start
# - fire right away if already started
# - deprecated
/=+===============================+=\
/ : : \
)==: EVENTS :==(
\ :_______________________________: /
\=+===============================+=/
Backbone.Events #EVENTS.
#Makes an OBJ event listener by mixing in, i.e. _.extend(OBJ, EVENTS)
#Callbacks are called synchronously, not async (but do not return anything)
#All methods below return EVENTS
#Most Backbone-native events can be prevented by using OBJ.silent true in the function
#firing them, e.g. MODEL.set(..., { silent: true })
EVENTS.on|once
("EVENT", FUNC(...)[, THIS]) #"EVENT" can be:
EVENTS.on|once # - a space-delimited list.
({ "EVENT": FUNC(...) }[, THIS]) # - "all": pass actual "EVENT" as first arg
EVENTS.off #If:
(["EVENT"[, FUNC[, THIS]]]) # - "EVENT"|FUNC null: means any
# - THIS: if defined, means only when THIS was used in on()
EVENTS.trigger("EVENT"[, ...]) #
EVENTS.listenTo[Once](EVENTS2,...)
EVENTS.stopListening #Like EVENTS2.on|once|off(..., EVENTS), but semantically indicates that EVENTS "eavesdrops"
([EVENTS2, ]...) #on another EVENTS2
MEVENT(...) #Means either fire event MEVENT(...) or (if available) calls MOBJECT.onMEVENT(...), where
#MEVENT has different case: "aa:bb:cc" -> "AaBbCc"
#Most of the time, "before:MEVENT" is before DOM manipulation, "MEVENT" after.
MOBJECT.triggerMethod
("MEVENT"[, ...]) #Fires MEVENT(...)
MOBJECT.[un]bindEntityEvents #OBJ is { EVENT: FUNC|"FUNC ..." ... }
(EVENTS, OBJ[()]) #Make events fired on EVENTS fire on MOBJECT too, by calling each
#MOBJECT.listenTo(EVENTS, "EVENT", FUNC|EVENTS.FUNC)
MOBJECT.destroy() #Calls stopListening() and fires MEVENT [before:]destroy()
/=+===============================+=\
/ : : \
)==: BACKBONE.WREQR :==(
\ :_______________________________: /
\=+===============================+=/
Backbone.Wreqr.radio #RADIO
#Like EVENTS but also add:
# - CHANNEL: namespaces
# - REQRES|commands:
# - only one callback by event, so means several emitters, few listeners
# (as opposed to EVENTS)
# - REQRES returns value, "commands" does not
# - "commands" buffers calls until first listener setup
#Used as a global app-wide event register/handler.
#Version 1.3.2
RADIO.channel("CHANNEL") #Returns WCHANNEL
RADIO.*("CHANNEL", ...) #Same as WCHANNEL.*(...)
WCHANNEL.channelName #
WCHANNEL.reset() #Remove all WCHANNEL.vent|commands|reqres handlers
WCHANNEL.vent #EVENTS
WCHANNEL.reqres #REQRES. Similar to EVENTS but sync
REQRES.setHandler
("HDLR", FUNC[, THIS])
REQRES.setHandlers #Register an event listener
({ "HDLR": FUNC|WOBJ }) #WOBJ: callback FUNC()[, context THIS]
REQRES.getHandler("HDLR") #Returns FUNC
REQRES.hasHandler("HDLR") #
REQRES.removeHandler("HDLR") #
REQRES.removeAllHandlers() #
REQRES.request("HDLR", ...) #Fires event listener FUNC(...) synchronously and return value
WCHANNEL.commands #Same as WCHANNEL.reqres but:
# - if event listener missing, buffers calls until it is declared
# - use execute() instead of request(), which does not return value
/=+===============================+=\
/ : : \
)==: MODELS :==(
\ :_______________________________: /
\=+===============================+=/
new MODEL_TYPE([ATTR_OBJ[, OBJ2]])#Returns a MODEL, i.e. an "augmented OBJ" (client-side) or a database row (server-side):
#OBJ2 is options passed to initial MODEL.set()
MODEL.defaults OBJ3[()] #Default ATTR_OBJ
#Uses _.defaults(), so for non-native type OBJ3.VAR, use OBJ3() to pass by value instead of
#reference.
MODEL.clone() #Returns new MODEL_TYPE(MODEL.attributes)
MODEL.get|escape("VAR")
MODEL.set("VAR", VAL[, OBJ]) #Manipulates ATTR_OBJ. "VAR" should not include spaces.
MODEL.set({ VAR: VAL }[, OBJ]) #escape() returns as HTML-escaped STR
MODEL.unset("VAR"[, OBJ]) #set|unset|clear() fires events change(MODEL, OBJ) and change:VAR(MODEL, VAL, OBJ)
MODEL.clear([OBJ]) #providing it changed (using _.isEqual())
MODEL.has("VAR") #If null|undefined
MODEL.changedAttributes([OBJ]) #Returns the part of ATTR_OBJ modified by the last MODEL.set(), or false if it did not
#change anything.
#Use OBJ not to return any attributes that match same key+val.
#Internaly use MODEL.changed, which is like MODEL.attributes but keep only track of changes.
MODEL.hasChanged(['VAR']) #Returns true if MODEL.changedAttributes() empty
MODEL.previousAttributes() #Returns ATTR_OBJ before the modification by the last MODEL.set().
#Only available in "change[:VAR]" event handlers.
MODEL.previous('VAR') #Same as MODEL.previousAttributes().VAR
MODEL.id #MODEL ID.
#Equal to ATTR_OBJ[MODEL.idAttribute (def: "id")]
#Should be defined server-side (by MODEL.save()), not client-side (by new MODEL())
MODEL.cid #Unique ID assigned by Backbone, useful when MODEL.id not available (e.g. not saved on
#server yet).
#By def., an incremented number prepended by "c" (or MODEL.cidPrefix STR)
MODEL.isNew() #Returns true if MODEL.id undefined
MODEL.toJSON([OBJ]) #JSON.stringify() takes MODEL.toJSON() instead of MODEL as input.
#Should return MODEL as OBJ2 (not "OBJ2")
#Can be overriden.
#By def., returns ATTR_OBJ shallow copy.
Backbone.ajax(OBJ) #Hardlink to $.ajax(OBJ). Can be overriden.
#Conventions:
# - return value is XHR_RET (JQXHR with jQuery)
# - XHR_VAL is the first argument passed to OBJ.success|error() callbacks
# (with jQuery: the return value for success, the JQXHR for error)
Backbone|MODEL.sync #Calls and returns Backbone.ajax(OBJ), with OBJ also having:
(METHOD_STR, MODEL[, OBJ]) # - type STR: according to METHOD_STR:
# - "create": POST
# - "read" : GET
# - "update": PUT
# - "patch" : PATCH
# - "delete": DELETE
# - url STR:
# - OBJ.url if defined
# - or "/COLL_NAME[/ID]":
# - "/COLL_NAME" is MODEL.urlRoot STR[()], or MODEL.collection.url STR[()]
# - /ID is "[/]MODEL.id", not defined if MODEL.isNew()
# - dataType "json"
# - emulateHTTP|JSON BOOL: see below
# (not for GET nor DELETE)
# - contentType "application/json"
# - data STR: JSON.stringify(MODEL.toJSON(OBJ))
# - success|error(...): MODEL.fetch|save|destroy wrap it to take as arguments
# (MODEL, XHR_VAL, OBJ).
# Can use OBJ.context to define this in the wrapped callback
#For older servers, if:
# - Backbone.emulateHTTP true, use only GET|POST + HTTP-Method-Override METHOD header
# - Backbone.emulateHTTP + Backbone.emulateJSON true, use also _method METHOD query param
# - Backbone.emulateJSON true, send as "application/x-www-form-urlencoded" instead of
# "application/json"
#Can be overriden globally, or only for a MODEL by overriding MODEL.sync()
#Events:
# - request(MODEL, XHR_RET, OBJ): when request start
# - sync|error(MODEL, XHR_VAL, OBJ): when request succeeded|errored, only with
# MODEL.fetch|save|destroy()
MODEL.fetch([OBJ]) #Calls and returns MODEL.sync("read", MODEL[, OBJ]), then do MODEL.set(XHR_VAL)
MODEL.save(...) #Calls MODEL.set(...), then calls/returns Backbone.sync("create|update|patch", MODEL[, OBJ]):
# - "create": if MODEL.isNew()
# - "update": if not MODEL.isNew() and OBJ.patch false
# - "patch": if not MODEL.isNew() and OBJ.patch true
# As opposed to "create|update", only send attributes specified by ... (not whole ATTROBJ)
#then call MODEL.set(XHR_VAL)
#If OBJ.wait true, only does the second MODEL.set()
MODEL.destroy([OBJ]) #Calls and returns Backbone.sync("delete", MODEL[, OBJ])
#If MODEL.isNew(): does not call Backbone.sync(), but does the rest and returns false.
#Fire COLL.remove(MODEL) + destroy(MODEL, COLL, OBJ) event right away.
#Calls MODEL.stopListening()
#If OBJ.wait true, does COLL.remove() + destroy() event after Backbone.sync() successfully
#answered.
MODEL.validate(ATTR_OBJ, OBJ) #Can be user-defined. Must return ERROR[_STR] if problem, nothing otherwise.
#Called by MODEL.save() and (if OBJ.validate true) by MODEL.set|fetch()
#OBJ is MODEL.save|set|fetch() OBJ
#If problem:
# - stops operation by returning false
# - fire invalid(MODEL, ERROR[_STR], OBJ), with OBJ.validationError ERROR[_STR]
# - sets MODEL.validationError ERROR[_STR]
#Check Backbone.Validation for a plugin that sets this up.
MODEL.isValid([OBJ]) #Runs MODEL.validate(OBJ), then returns BOOL.
MODEL.parse(VAL[, OBJ])->VAL #Can be defined to modify XHR_VAL when calling MODEL.fetch|save([OBJ]) (unless OBJ2.parse
#false) and (if OBJ2.parse true) new MODEL_TYPE(A_OBJ, OBJ2)
#Modifies the XHR_VAL used by MODEL.set(...) by those methods, but not the one used in the
#success callback.
/=+===============================+=\
/ : : \
)==: COLLECTIONS :==(
\ :_______________________________: /
\=+===============================+=/
new COLL_TYPE #Represent a MODEL_ARR:
([COLL_ELEM[_ARR][, OBJ]]) # - COLL_ELEM means either:
# - MODEL
# - ATTR_OBJ: calling new MODEL_TYPE(ATTR_OBJ[, OBJ]), where MODEL_TYPE is
# COLL.model (def: Backbone.Model)
# - OBJ is passed to initial COLL.set()
# - any MODEL event bubbles up to its collection, e.g. "destroy", "change:VAR", "invalid"
COLL.clone() #
COLL.models #Internal MODEL_ARR
MODEL.collection #COLL
#Can be also be set with new MODEL_TYPE(A_OBJ, OBJ2) OBJ2.collection (usually useless)
COLL.set(COLL_ELEM[_ARR][, OBJ]) #Compare each current element to COLL_ELEM[_ARR] and:
# - if current element same as COLL_ELEM[_ARR]:
# - if OBJ.merge false, does nothing
# - if OBJ.merge true (def), merges it.
# - if current element but not in COLL_ELEM[ARR]:
# - if OBJ.remove true (def): removes it.
# Fires event remove(MODEL, COLL, OBJ), where OBJ.index NUM is the element index.
# - if COLL_ELEM[ARR] but not in current elements:
# - if OBJ.add true (def): adds it at position OBJ.at NUM (def: end)
# Fires event add(MODEL, COLL, OBJ)
# - if MODEL have been removed or added, fires event update(COLL, OBJ)
#Compare COLL_ELEM according to COLL.modelId(ATTR_OBJ)->VAL (def: return MODEL.id)
#Returns new MODEL_ARR.
#All COLL_ELEM[_ARR] must have MODEL.id if OBJ.remove|merge true
COLL.reset([...]) #Removes all models, then (if ...) calls and returns COLL.add(...).
#Similar to COLL.set() with OBJ.remove true, OBJ.add true and OBJ.merge true except:
# - for big difference, faster
# - replaces instead of merging
# - different events: only fire event reset(COLL, OBJ), with OBJ.previousModels MODEL_ARR
# set
COLL.add(...) #Same as COLL.set(...) with different default OBJ.remove false
COLL.push|unshift(...) #Same as COLL.add(...) but with OBJ.at COLL.length|0
COLL.remove #Removes and returns COLL_ELEM[_ARR] or VAL (i.e. MODEL.id|cid)
(COLL_ELEM[_ARR]|VAL[,OBJ]) #Fires same event "remove" as COLL.set()
COLL.pop|shift([OBJ]) #Same but for the last|first MODEL
COLL.get(VAL) #Returns a MODEL, where VAL can be the MODEL.id, MODEL.cid or MODEL itself
#Returns undefined if none found.
COLL.at(NUM) #Returns a MODEL. Error if out-of-bound.
COLL.slice(NUM[, NUM2]) #Same as ARR.slice(...) (including that it returns copy), but for COLL
COLL.length #
COLL.findWhere(...) #Same as COLL.where(...)[0]
COLL.comparator(...) #Is a LFUNC or FUNC(VAL, VAL2)->-1|0|1
#If defined:
# - keep the collection sorted accordingly when models are changed, unless using
# OBJ.sort false (to COLL.add(), etc.)
# - can manually sort with COLL.sort(). Only useful after OBJ.sort false has been used.
# - each time it is sorted (automatically or with COLL.sort()) and order changed, fire
# event sort(COLL, OBJ)
COLL.toJSON(...) #Same as for MODEL (def: concanates all MODEL.toJSON(...))
COLL.sync(...) #Same as for MODEL, except does not use urlRoot
COLL.fetch([OBJ]) #Same as for MODEL but:
# - calls and returns COLL.sync("read", COLL[, OBJ]), then do COLL.set(XHR_VAL[, OBJ]) or
# (if OBJ.reset true) COLL.reset(XHR_VAL[, OBJ]).
# Prefer OBJ.reset true during initial page load.
# - events request|sync|error fired too, but first arg is COLL not MODEL
COLL.create(COLL_ELEM[, OBJ]) #COLL.add(COLL_ELEM[, OBJ]) then MODEL.save() (or the other way around if OBJ.wait true)
#OBJ.success() is proxied like for COLL.fetch()
COLL.parse(COLL_ELEM[_ARR][, OBJ])#Called on COLL.set(COLL_ELEM[_ARR], OBJ) when OBJ.parse true (def: false, except within
#COLL.fetch()), to modify the input COLL_ELEM[_ARR].
#If COLL.set() OBJ.parse true, will also call MODEL.parse() when a MODEL is updated
#(with OBJ.merge true)
/=+===============================+=\
/ : : \
)==: ROUTER :==(
\ :_______________________________: /
\=+===============================+=/
new ROUTER_TYPE([OBJ]) #Functions fired when R_PATH changes:
# - setup by:
# - ROUTER.routes { R_PATH: "ROUTE" }[()]
# - ROUTER.route(R_PATH_STR|REGEXP[, "ROUTE"][, R_FUNC])
# - R_PATH:
# - can have:
# - ":R_VAR": up to next /
# - "*R_VAR": same up to end
# - "(...)": optional
# - no leading slash
# - when R_PATH changes and matches (checked by HISTORY):
# - fires ROUTER.ROUTE([R_VAR...]) or (if defined) R_FUNC([R_VAR...])
# - can proxy calls to those functions (e.g. modify/add arguments) by reassigning
# ROUTER.execute(FUNC, ARR, "ROUTE"). By def, only does:
# if ( FUNC ) FUNC.apply( this, ARR );
# If execute() returns exactly false, do not fire events.
# - fires events:
# - on ROUTER: "route:ROUTE"([R_VAR...])
# - on ROUTER: route("ROUTE", R_VAR_ARR)
# - on HISTORY: route(ROUTER, "ROUTE", R_VAR_ARR)
Backbone.history #Default HISTORY
HISTORY.start([OBJ]) #Call HISTORY.loadUrl() which triggers R_FUNC() of matching R_PATH:
# - when (in priority order) (only when R_PATH changed):
# - if OBJ.pushState BOOL true (def: false) and HTML5 History API supported,
# WINDOW "popstate" event, triggered by using HTML5 History
# (done by HISTORY.navigate())
# - if OBJ.hashChange true (def), WINDOW "hashchange" event.
# - otherwise, poll every OBJ.interval ms (def: 50)
# - right away unless OBJ.silent true. Returns true if R_PATH matched.
#R_PATH:
# - is HISTORY.getFragment()
# - if OBJ.pushState true, path (without leading slash nor hash), otherwise hash part.
#Set HISTORY.started to true
#OBJ.root (def: "/") should be app root path.
#To do when DOM ready, and after ROUTER setup.
HISTORY.stop() #
HISTORY|ROUTER.navigate #Modify current R_PATH.
(R_PATH[, OBJ]) #Only triggers RFUNC if R_PATH changed and if OBJ.trigger true (def: false)
#If OBJ.replace true and using HTML5 history, replace history entry instead of adding
#a new one
#OBJ can be true, i.e. { trigger: true }
#Returns true if matched a R_PATH.
/=+===============================+=\
/ : : \
)==: MAPPROUTER :==(
\ :_______________________________: /
\=+===============================+=/
MARIONETTE.AppRouter #MAPPROUTER
#Child of ROUTER, which uses MAPPROUTER..appRoutes instead of ROUTER.routes, same but use:
# - MAPPROUTER..controller.ROUTE(...) instead of ROUTER.ROUTE(...)
# Goal: separate MAPPROUTER..controller OBJ (logic) from MAPPROUTER (routing)
# - MAPPROUTER.appRoute(...) instead of ROUTER.route(...) (cannot use last arg R_FUNC)
# - MAPPROUTER.onRoute("ROUTE", R_PATH, R_VAR_ARR) instead of
# EVENT route("ROUTE", R_VAR_ARR).
# Based on MAPPROUTER..appRoutes
/=+===============================+=\
/ : : \
)==: VIEW :==(
\ :_______________________________: /
\=+===============================+=/
new VIEW_TYPE([OBJ]) #Creates/queries a DOM element(s) and setup event listeners.
#OBJ is merged into VIEW for el|id|tagName|className|model|collection|attributes|events
#Must be instantiated after DOM ready event.
VIEW.remove() #Remove element from DOM and its event handlers
VIEW.el #ELEM|JQ|SELECTOR describing the DOM element(s).
#If not specified create one according to VIEW.id|tagName|className|attributes VAL[()]
#(def: empty <div>)
#To change runtime, do VIEW.setElement(ELEM|JQ|SELECTOR)
#After initialisation, VIEW.el will be ELEM, and VIEW.$el JQ
VIEW.events #OBJ[()] { "EVENT[ SELECTOR]": "FUNC"|FUNC() }:
# - "FUNC" is VIEW["FUNC"]
# - fires FUNC(...) on "EVENT". SELECTOR is within VIEW.$el children
#Setup/reset by VIEW.delegateEvents() (done at init), removed by VIEW.undelegateEvents()
VIEW.cid #Unique ID assigned automatically
VIEW.$(SELECTOR) #Shortcut to VIEW.$el.find(SELECTOR)
CONVENTIONS ==> #The following are not used by Backbone, but are conventions for the application code
VIEW.model|collection #MODEL|COLL
VIEW.render() #Handler of linked MODELs "change" event, e.g. put in initialize():
# this.listenTo( this.model, "change", this.render );
#Should return this.
#Good idea to also put handler of linked MODELs "destroy" event, e.g. in initialize():
# this.listenTo( this.model, "destroy", this.OTHER_FUNC );
VIEW.template(OBJ[, OBJ2]) #Template function, e.g.:
# template: HANDLEBARS.compile( "<div>{{VAR}}</div>" )
#Typically fired in VIEW.render(), with result assigned via VIEW.$el.html()
#Should load "HTML" from a separate file instead of putting "HTML" in JavaScript.
/=+===============================+=\
/ : : \
)==: MVIEW :==(
\ :_______________________________: /
\=+===============================+=/
MARIONETTE.View #Child of VIEW
MVIEW.ui #{ KEY: SELECTOR }
#MVIEW.bindUIElements(), called by all M*VIEW.render() (but not MVIEW.render()), assigns
#MVIEW.$(SELECTOR) to:
# - MVIEW.ui.KEY
# - @SELECTOR, i.e. SELECTOR that can also be "@ui.KEY".
# Should always use when possible, in order to decouple UI from logic.
MVIEW..model|collectionEvents #Like MVIEW.events but:
# - listen to MVIEW.model|collection events
# - can use "FUNC ..." instead of "FUNC"
# - no SELECTOR
MVIEW.events #Can use @SELECTOR
MVIEW.triggers #Like MVIEW.events, but use "MEVENT" instead of "FUNC", firing MEVENT(OBJ):
# - OBJ is { view MVIEW, model|collection MVIEW.model|collection }
# - can use { event: "MEVENT", preventDefault|stopPropagation BOOL } instead of "MEVENT"
MVIEW.destroy() #Like MOBJECT.destroy() but also:
# - remove from DOM
# - sets MVIEW.isDestroyed true
MVIEW.isRendered #Set to true after render(), false after destroy() by all M*VIEW (not MVIEW itself)
MVIEW|MBEHAVIOR.behaviors OBJ[()] #{ BKEY: BOBJ }
#Build the MBEHAVIOR, which decouple the logic ([M]EVENT triggers/handling) of MVIEW.
#MBEHAVIOR proxies MVIEW:
# - inherits its ui|$|el|$el
# - MBEHAVIOR.view = MVIEW
# - can define its model|collectionEvents (will use MVIEW.model|collection),
# events|triggers, MEVENTs handlers and MVIEW.FUNC() event handlers
# - for MVIEW.FUNC() event handler, the model|collectionEvents|events must be in
# same MBEHAVIOR
#Fire new MBEHAVIOR_TYPE(BOBJ, MVIEW):
# - look up MBEHAVIOR_TYPE in:
# - BOBJ.behaviorClass
# - or MARIONETTE.Behaviors.behaviorsLookup(BOBJ, BKEY)[BKEY]
# behaviorsLookup() must be redefined, e.g. returning global object
# { BKEY: MBEHAVIOR_TYPE }
# - MBEHAVIOR.options = BOBJ (can use MBEHAVIOR.defaults OBJ[()])
#MBEHAVIOR is MARIONETTE.Behavior
/=+===============================+=\
/ : : \
)==: MITEMVIEW :==(
\ :_______________________________: /
\=+===============================+=/
MARIONETTE.TemplateCache.get #Returns TEMPLATE_FUNC. By def., returns __.template($(ID).html()[, OBJ])
(ID[, OBJ]) #Details (in order):
# - new MARIONETTE.TemplateCache(ID)->TEMPLATECACHE, with TEMPLATECACHE.templateId ID
# - TEMPLATECACHE.loadTemplate(ID[, OBJ])->"TEMPLATE" (def: $(ID).html())
# - TEMPLATECACHE.compileTemplate("TEMPLATECACHE"[, OBJ])->TEMPLATE_FUNC
# (def: forward to _.template(...)),
# - TEMPLATECACHE.compiledTemplate = TEMPLATE_FUNC
#Last two functions can be overriden.
#Caching:
# - stores TEMPLATECACHE in MARIONETTE.TemplateCache.templateCaches[ID] used in next call
# - can MARIONETTE.TemplateCache.clear([ID...])
MARIONETTE.ItemView #MITEMVIEW. Child of MVIEW, to render a single MODEL (or sometimes a simple COLL)
MITEMVIEW.serializeData([...]) #MITEMVIEW.model.toJSON(...)
#or (if no MITEMVIEW.model) { items: MITEMVIEW.collection.toJSON(...) }
#mixed in MITEMVIEW..templateHelpers OBJ[()]
MITEMVIEW.render() #Calls (unless MITEMVIEW..template false):
# - "COMPILED_TEMPLATE" = MARIONETTE.Renderer.render
# (MITEMVIEW..template VAL, MITEMVIEW.serializeData() OBJ, MITEMVIEW) which by def:
# - if VAL FUNC, calls FUNC(OBJ)
# - otherwise MARIONETTE.TemplateCache.get(VAL)(OBJ)
# - MITEMVIEW.attachElContent("COMPILED_TEMPLATE") (def: MITEMVIEW.$el.html(...))
# - both functions can be overriden
#Fires MEVENT "[before:]render"(MITEMVIEW)
/=+===============================+=\
/ : : \
)==: MCOLLVIEW :==(
\ :_______________________________: /
\=+===============================+=/
new Backbone.ChildViewContainer #Container for VIEW_ARR, underlying MCOLLVIEW (i.e. MCOLLVIEW.children)
([VIEW_ARR]) #Based on Backbone.Babysitter 0.1.6
CHILDVIEWCTNER.add(VIEW[, KEY]) #
CHILDVIEWCTNER.remove(VIEW) #
CHILDVIEWCTNER.length #
CHILDVIEWCTNER.call("FUNC"[, ...])#
CHILDVIEWCTNER.apply("FUNC"[,ARR])#Call each VIEW.FUNC(...)
CHILDVIEWCTNER.findByModel(MODEL) #
CHILDVIEWCTNER.findByModelCid(VAL)#Retrieve VIEW by MODEL.cid
CHILDVIEWCTNER.findByCid(VAL) #Retrieve VIEW by VIEW.cid
CHILDVIEWCTNER.findByCustom(KEY) #Retrieve VIEW by KEY
CHILDVIEWCTNER.findByIndex(NUM) #Retrieve VIEW by position
MARIONETTE.CollectionView #MCOLLVIEW. Child of MVIEW, to render a COLL.
MCOLLVIEW.collection #COLL
MCOLLVIEW.children #CHILDVIEWCTNER, rebuilt by MCOLLVIEW.render()
MCOLLVIEW.childEvents #Like VIEW.events except as { "MEVENT": FUNC }:
# - refers to children MEVENTs
# - setup by render()
#Children events also trigger MEVENT "PREFIX:EVENT"(...), where PREFIX is
#MCOLLVIEW..childViewEventPrefix (def: "childview")
MCOLLVIEW.render() #For each child MODEL:
# - create/add a CHILD_MVIEW:
# - CHILD_MVIEW_TYPE = MCOLLVIEW.getChildView(MODEL) (def: MCOLLVIEW..childView)
# - OPTS = MCOLLVIEW..childViewOptions OBJ[(MODEL, NUM)])
# - CHILD_MVIEW = new CHILD_MVIEW_TYPE(OPTS), adding also OPTS.model MODEL,
# or overriding MCOLLVIEW.buildChildView(MODEL, CHILD_MVIEW_TYPE, OPTS)
# - CHILD_MVIEW.render(), then appends it to MCOLLVIEW.$el
#Listens to COLL events "add|remove|reset" to keep child views in sync with collection models
#If MCOLLVIEW.collection is empty:
# - add child MODEL like above but:
# - use new MODEL() as MODEL
# - must use emptyView|getEmptyView instead of childView|getChildView
# - can use emptyViewOptions instead of childViewOptions
# - can override MCOLLVIEW.isEmpty()->BOOL (def: no COLL or COLL.length === 0)
#Fires MEVENT:
# - [before:]render(COLL)
# - [before:]render:collection(COLL): if not empty
# - [before:]render:empty(): if empty
# - [before:]add|remove:child(CHILD_MVIEW)
# - [before:]remove:empty()
MCOLLVIEW..viewComparator #Sort CHILD_MVIEW in the DOM according to their MODEL.
#Can be "VAR", LFUNC(MODEL)->NUM or FUNC(MODEL, MODEL2)->-1|0|1
#Sort when:
# - MCOLLVIEW.render()
# - manual MCOLLVIEW.reorder():
# - does DOM manipulation but no MCOLLVIEW.render()
# - fires MEVENT [before:]reorder()
# - COLL event "sort":
# - calls MCOLLVIEW.render() if MCOLLVIEW..reorderOnSort false (def), otherwise
# MCOLLVIEW.reorder()
# - disable with MCOLLVIEW..sort false (to force manual sorts)
MCOLLVIEW..filter
(MODEL, NUM, COLL)->BOOL #Do not show children returning false
MCOLLVIEW.destroy() #Like MOBJECT but also:
# - fire MEVENT [before:]destroy:collection()
# - destroy children, firing MEVENT [before:]remove:child(CHILD_MVIEW)
/=+===============================+=\
/ : : \
)==: MCOMPVIEW :==(
\ :_______________________________: /
\=+===============================+=/
MARIONETTE.CompositeView #MCOMPVIEW. Mix of a MCOLLVIEW and a MITEMVIEW, e.g. for a tree (root node and children)
#Using MCOMPVIEW.collection, is like MCOLLVIEW but:
# - can use MCOMPVIEW..childViewContainer @SELECTOR[()] to attach children to something
# else than MCOMPVIEW.$el (can be inside the MITEMVIEW)
# (otherwise appended after the MITEMVIEW)
# - def CHILD_MVIEW_TYPE is MCOMPVIEW_TYPE
#Using MCOMPVIEW.model, is like MITEMVIEW.
#Renders MITEMVIEW first, then MCOLLVIEW:
# - MEVENT [before:]render(MCOMPVIEW) fired before|after MITEMVIEW+MCOLLVIEW
# - MEVENT [before:]render:template() fired before|after MITEMVIEW
/=+===============================+=\
/ : : \
)==: MREGION/MLAYOUTVIEW :==(
\ :_______________________________: /
\=+===============================+=/
MARIONETTE.Region #MREGION. Container of a MVIEW.
MREGION..el #ELEM|SELECTOR, to define the container DOM element.
#Can be @SELECTOR from a MLAYOUTVIEW
#If undefined, MREGION.show() will throw error unless MREGION..allowMissingEl true
MREGION..$el #JQ, to use.
MREGION.show(MVIEW[, OBJ]) #Does:
# - MVIEW.render()
# - then put as unique DOM child with MREGION.attachHtml(MVIEW), which by def:
# - $el.contents().detach() (remove current DOM child)
# - el.appendChild(MVIEW.el)
# Can redefine for transitions effects.
#Former MVIEW2:
# - if same, does nothing unless OBJ.forceShow true
# - is destroyed with MREGION.empty() unless OBJ.preventDestroy true
#Fires MEVENT:
# - with parameters (MVIEW, MREGION, OBJ): no OBJ for [before:]attach(),
# nothing for dom:refresh
# - after MVIEW.render(), before|after attached to DOM, except:
# - [before:]swapOut(): before|after MVIEW.render()
# - if:
# - [before:]swap[Out]: MVIEW2 changes for another MVIEW
# - [before:]show(): always
# - [before:]attach|dom:refresh(): MREGION attached to DOM.
# Can prevent with OBJ|MREGION.trigger[Before]Attach false (to improve performance)
# - recursion:
# - not recursive: [before:]swap[Out]()
# - recursive:
# - [before:]attach():
# - currently shown only
# - starting with ancestors
# - [before:]show|dom:refresh():
# - will fire on future new children too (together with [before:]add:child())
# - starting with descendants
MREGION.currentView MVIEW
MREGION.attachView(MVIEW) #Adds already render()'d MVIEW. Does not fire any MEVENT.
MREGION.empty([OBJ]) #Remove MVIEW.
#If OBJ.preventDestroy true, do not call MVIEW.destroy()
#Fires MEVENT [before:]empty(MVIEW)
MREGION.reset() #Same but also clear cache for MREGION..$el
MREGION.hasView()->BOOL #
MARIONETTE.RegionManager #MREGIONMANAGER. Is a MREGION_ARR.
MREGIONMANAGER.addRegions #Calls each MREGIONMANAGER.addRegion(R_NAME, VAL)
({ R_NAME: VAL ... }[, OBJ2]) #OBJ2 are default VAL value.
#Called with MREGIONMANAGER..regions OBJ at instantiation.
#Returns MREGIONMANAGER.getRegions()
MREGIONMANAGER.addRegion #Stores new MREGION_TYPE(OBJ) where OBJ can also have:
(R_NAME, OBJ) # - selector: same as el. Should prefer using selector.
# - regionClass TYPE: use instead of MREGION_TYPE
#OBJ can be also be:
# - STR: same as { selector: STR }
# - TYPE: same as { regionClass: TYPE }
#Fires MEVENT [before:]add:region(R_NAME, MREGION)
MREGIONMANAGR.get(R_NAME)->MREGION#
MREGIONMANAGER.getRegions() #Returns { R_NAME: MREGION ... }
MREGIONMANAGR.removeRegion(R_NAME)#Does MREGION.empty() and remove from MREGIONMANAGER.
MREGIONMANAGER.removeRegions() #Fires MEVENT [before:]remove:region(R_NAME, MREGION)
MREGIONMANAGER.emptyRegions() #Call each MREGION.empty(), but keep in MREGIONMANAGER.
MARIONETTE.LayoutView #MLAYOUTVIEW. Child of both MITEMVIEW and MREGIONMANAGER, but:
new MLAYOUTVIEW_TYPE([OBJ]) # - use MLAYOUTVIEW|OBJ..regions { R_NAME: VAL ... }[(OBJ)]
# - MLAYOUTVIEW|OBJ..regionClass instead of OBJ.regionClass
# - MREGION..el is scoped within MLAYOUTVIEW..el
# - no addRegions() OBJ2, no removeRegions|emptyRegions()
# - getRegion(R_NAME) instead of get(R_NAME)
# - can override MLAYOUTVIEW.getRegionManager()->MREGIONMANAGER to provide custom one
# (def: new MREGIONMANAGER())
MLAYOUTVIEW.render() #Calls MITEMVIEW.render() and MREGIONMANAGER.removeRegions()
MLAYOUTVIEW.showChildView #Same as getRegion(R_NAME).show(MVIEW)
(R_NAME, MVIEW) #If MVIEW is a MLAYOUTVIEW, it should do MLAYOUTVIEW.showChildView() on its children in its
#before:show handler in order to be recursive.
MLAYOUTVIEW.getChildView(R_NAME)
->MVIEW
MLAYOUTVIEW.childEvents #Like MCOLLVIEW, including children events triggering "PREFIX:EVENT"