marionette-rails 2.3.2 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 784f3ed30d496806b0e0eef14a7cf643152dbd24
|
4
|
+
data.tar.gz: 90e2455a564f630445b624cc51081fb35b143e07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6104cdf3edb687da3d167ea067fabe02a0bcdb67c9faff9ca917b8bc32b62311047d66db12e6b992dfa3cfa4bbaa2a3e7a40f4181c316c1fdb334bd957866db
|
7
|
+
data.tar.gz: 229f8eead03011880e83ccacd692c0be10da7df8265b92c78582af0aab09d819d0e31382bc53da8d0b38339f53333a4d401343958e12c51789bec7001c51b354
|
@@ -1,6 +1,6 @@
|
|
1
1
|
// MarionetteJS (Backbone.Marionette)
|
2
2
|
// ----------------------------------
|
3
|
-
// v2.
|
3
|
+
// v2.4.0
|
4
4
|
//
|
5
5
|
// Copyright (c)2015 Derick Bailey, Muted Solutions, LLC.
|
6
6
|
// Distributed under MIT license
|
@@ -38,9 +38,9 @@
|
|
38
38
|
/* istanbul ignore next */
|
39
39
|
// Backbone.BabySitter
|
40
40
|
// -------------------
|
41
|
-
// v0.1.
|
41
|
+
// v0.1.6
|
42
42
|
//
|
43
|
-
// Copyright (c)
|
43
|
+
// Copyright (c)2015 Derick Bailey, Muted Solutions, LLC.
|
44
44
|
// Distributed under MIT license
|
45
45
|
//
|
46
46
|
// http://github.com/marionettejs/backbone.babysitter
|
@@ -156,7 +156,7 @@
|
|
156
156
|
//
|
157
157
|
// Mix in methods from Underscore, for iteration, and other
|
158
158
|
// collection related features.
|
159
|
-
var methods = [ "forEach", "each", "map", "find", "detect", "filter", "select", "reject", "every", "all", "some", "any", "include", "contains", "invoke", "toArray", "first", "initial", "rest", "last", "without", "isEmpty", "pluck" ];
|
159
|
+
var methods = [ "forEach", "each", "map", "find", "detect", "filter", "select", "reject", "every", "all", "some", "any", "include", "contains", "invoke", "toArray", "first", "initial", "rest", "last", "without", "isEmpty", "pluck", "reduce" ];
|
160
160
|
_.each(methods, function(method) {
|
161
161
|
Container.prototype[method] = function() {
|
162
162
|
var views = _.values(this._views);
|
@@ -167,7 +167,7 @@
|
|
167
167
|
// return the public API
|
168
168
|
return Container;
|
169
169
|
}(Backbone, _);
|
170
|
-
Backbone.ChildViewContainer.VERSION = "0.1.
|
170
|
+
Backbone.ChildViewContainer.VERSION = "0.1.6";
|
171
171
|
Backbone.ChildViewContainer.noConflict = function() {
|
172
172
|
Backbone.ChildViewContainer = previousChildViewContainer;
|
173
173
|
return this;
|
@@ -490,13 +490,15 @@
|
|
490
490
|
})(Backbone, _);
|
491
491
|
|
492
492
|
var previousMarionette = root.Marionette;
|
493
|
+
var previousMn = root.Mn;
|
493
494
|
|
494
495
|
var Marionette = Backbone.Marionette = {};
|
495
496
|
|
496
|
-
Marionette.VERSION = '2.
|
497
|
+
Marionette.VERSION = '2.4.0';
|
497
498
|
|
498
499
|
Marionette.noConflict = function() {
|
499
500
|
root.Marionette = previousMarionette;
|
501
|
+
root.Mn = previousMn;
|
500
502
|
return this;
|
501
503
|
};
|
502
504
|
|
@@ -524,6 +526,11 @@
|
|
524
526
|
return Backbone.$.contains(document.documentElement, el);
|
525
527
|
};
|
526
528
|
|
529
|
+
// Merge `keys` from `options` onto `this`
|
530
|
+
Marionette.mergeOptions = function(options, keys) {
|
531
|
+
if (!options) { return; }
|
532
|
+
_.extend(this, _.pick(options, keys));
|
533
|
+
};
|
527
534
|
|
528
535
|
// Marionette.getOption
|
529
536
|
// --------------------
|
@@ -550,11 +557,7 @@
|
|
550
557
|
// undefined return a default value
|
551
558
|
Marionette._getValue = function(value, context, params) {
|
552
559
|
if (_.isFunction(value)) {
|
553
|
-
|
554
|
-
// to prevent `apply` from failing in ie8
|
555
|
-
params = params || [];
|
556
|
-
|
557
|
-
value = value.apply(context, params);
|
560
|
+
value = params ? value.apply(context, params) : value.call(context);
|
558
561
|
}
|
559
562
|
return value;
|
560
563
|
};
|
@@ -599,11 +602,21 @@
|
|
599
602
|
// allows for the use of the @ui. syntax within
|
600
603
|
// a given value for regions
|
601
604
|
// swaps the @ui with the associated selector
|
602
|
-
Marionette.normalizeUIValues = function(hash, ui) {
|
605
|
+
Marionette.normalizeUIValues = function(hash, ui, properties) {
|
603
606
|
_.each(hash, function(val, key) {
|
604
607
|
if (_.isString(val)) {
|
605
608
|
hash[key] = Marionette.normalizeUIString(val, ui);
|
606
609
|
}
|
610
|
+
else if (_.isObject(val) && _.isArray(properties)) {
|
611
|
+
_.extend(val, Marionette.normalizeUIValues(_.pick(val, properties), ui));
|
612
|
+
/* Value is an object, and we got an array of embedded property names to normalize. */
|
613
|
+
_.each(properties, function(property) {
|
614
|
+
var propertyVal = val[property];
|
615
|
+
if (_.isString(propertyVal)) {
|
616
|
+
val[property] = Marionette.normalizeUIString(propertyVal, ui);
|
617
|
+
}
|
618
|
+
});
|
619
|
+
}
|
607
620
|
});
|
608
621
|
return hash;
|
609
622
|
};
|
@@ -682,7 +695,7 @@
|
|
682
695
|
// trigger the event, if a trigger method exists
|
683
696
|
if (_.isFunction(context.trigger)) {
|
684
697
|
if (noEventArg + args.length > 1) {
|
685
|
-
context.trigger.apply(context, noEventArg ? args : [event].concat(_.
|
698
|
+
context.trigger.apply(context, noEventArg ? args : [event].concat(_.drop(args, 0)));
|
686
699
|
} else {
|
687
700
|
context.trigger(event);
|
688
701
|
}
|
@@ -984,6 +997,9 @@
|
|
984
997
|
// methods if the method exists
|
985
998
|
triggerMethod: Marionette.triggerMethod,
|
986
999
|
|
1000
|
+
// A handy way to merge options onto the instance
|
1001
|
+
mergeOptions: Marionette.mergeOptions,
|
1002
|
+
|
987
1003
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
988
1004
|
getOption: Marionette.proxyGetOption
|
989
1005
|
|
@@ -1015,12 +1031,17 @@
|
|
1015
1031
|
this.triggerMethod('before:destroy');
|
1016
1032
|
this.triggerMethod('destroy');
|
1017
1033
|
this.stopListening();
|
1034
|
+
|
1035
|
+
return this;
|
1018
1036
|
},
|
1019
1037
|
|
1020
1038
|
// Import the `triggerMethod` to trigger events with corresponding
|
1021
1039
|
// methods if the method exists
|
1022
1040
|
triggerMethod: Marionette.triggerMethod,
|
1023
1041
|
|
1042
|
+
// A handy way to merge options onto the instance
|
1043
|
+
mergeOptions: Marionette.mergeOptions,
|
1044
|
+
|
1024
1045
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
1025
1046
|
getOption: Marionette.proxyGetOption,
|
1026
1047
|
|
@@ -1235,20 +1256,28 @@
|
|
1235
1256
|
|
1236
1257
|
// Destroy the current view, if there is one. If there is no
|
1237
1258
|
// current view, it does nothing and returns immediately.
|
1238
|
-
empty: function() {
|
1259
|
+
empty: function(options) {
|
1239
1260
|
var view = this.currentView;
|
1240
1261
|
|
1262
|
+
var preventDestroy = Marionette._getValue(options, 'preventDestroy', this);
|
1241
1263
|
// If there is no view in the region
|
1242
1264
|
// we should not remove anything
|
1243
1265
|
if (!view) { return; }
|
1244
1266
|
|
1245
1267
|
view.off('destroy', this.empty, this);
|
1246
1268
|
this.triggerMethod('before:empty', view);
|
1247
|
-
|
1269
|
+
if (!preventDestroy) {
|
1270
|
+
this._destroyView();
|
1271
|
+
}
|
1248
1272
|
this.triggerMethod('empty', view);
|
1249
1273
|
|
1250
1274
|
// Remove region pointer to the currentView
|
1251
1275
|
delete this.currentView;
|
1276
|
+
|
1277
|
+
if (preventDestroy) {
|
1278
|
+
this.$el.contents().detach();
|
1279
|
+
}
|
1280
|
+
|
1252
1281
|
return this;
|
1253
1282
|
},
|
1254
1283
|
|
@@ -1371,6 +1400,7 @@
|
|
1371
1400
|
Marionette.RegionManager = Marionette.Controller.extend({
|
1372
1401
|
constructor: function(options) {
|
1373
1402
|
this._regions = {};
|
1403
|
+
this.length = 0;
|
1374
1404
|
|
1375
1405
|
Marionette.Controller.call(this, options);
|
1376
1406
|
|
@@ -1464,8 +1494,11 @@
|
|
1464
1494
|
|
1465
1495
|
// internal method to store regions
|
1466
1496
|
_store: function(name, region) {
|
1497
|
+
if (!this._regions[name]) {
|
1498
|
+
this.length++;
|
1499
|
+
}
|
1500
|
+
|
1467
1501
|
this._regions[name] = region;
|
1468
|
-
this._setLength();
|
1469
1502
|
},
|
1470
1503
|
|
1471
1504
|
// internal method to remove a region
|
@@ -1476,13 +1509,8 @@
|
|
1476
1509
|
|
1477
1510
|
delete region._parent;
|
1478
1511
|
delete this._regions[name];
|
1479
|
-
this.
|
1512
|
+
this.length--;
|
1480
1513
|
this.triggerMethod('remove:region', name, region);
|
1481
|
-
},
|
1482
|
-
|
1483
|
-
// set the number of regions current held
|
1484
|
-
_setLength: function() {
|
1485
|
-
this.length = _.size(this._regions);
|
1486
1514
|
}
|
1487
1515
|
});
|
1488
1516
|
|
@@ -1507,7 +1535,7 @@
|
|
1507
1535
|
// Get the specified template by id. Either
|
1508
1536
|
// retrieves the cached version, or loads it
|
1509
1537
|
// from the DOM.
|
1510
|
-
get: function(templateId) {
|
1538
|
+
get: function(templateId, options) {
|
1511
1539
|
var cachedTemplate = this.templateCaches[templateId];
|
1512
1540
|
|
1513
1541
|
if (!cachedTemplate) {
|
@@ -1515,7 +1543,7 @@
|
|
1515
1543
|
this.templateCaches[templateId] = cachedTemplate;
|
1516
1544
|
}
|
1517
1545
|
|
1518
|
-
return cachedTemplate.load();
|
1546
|
+
return cachedTemplate.load(options);
|
1519
1547
|
},
|
1520
1548
|
|
1521
1549
|
// Clear templates from the cache. If no arguments
|
@@ -1546,15 +1574,15 @@
|
|
1546
1574
|
_.extend(Marionette.TemplateCache.prototype, {
|
1547
1575
|
|
1548
1576
|
// Internal method to load the template
|
1549
|
-
load: function() {
|
1577
|
+
load: function(options) {
|
1550
1578
|
// Guard clause to prevent loading this template more than once
|
1551
1579
|
if (this.compiledTemplate) {
|
1552
1580
|
return this.compiledTemplate;
|
1553
1581
|
}
|
1554
1582
|
|
1555
1583
|
// Load the template and compile it
|
1556
|
-
var template = this.loadTemplate(this.templateId);
|
1557
|
-
this.compiledTemplate = this.compileTemplate(template);
|
1584
|
+
var template = this.loadTemplate(this.templateId, options);
|
1585
|
+
this.compiledTemplate = this.compileTemplate(template, options);
|
1558
1586
|
|
1559
1587
|
return this.compiledTemplate;
|
1560
1588
|
},
|
@@ -1564,7 +1592,7 @@
|
|
1564
1592
|
// For asynchronous loading with AMD/RequireJS, consider
|
1565
1593
|
// using a template-loader plugin as described here:
|
1566
1594
|
// https://github.com/marionettejs/backbone.marionette/wiki/Using-marionette-with-requirejs
|
1567
|
-
loadTemplate: function(templateId) {
|
1595
|
+
loadTemplate: function(templateId, options) {
|
1568
1596
|
var template = Backbone.$(templateId).html();
|
1569
1597
|
|
1570
1598
|
if (!template || template.length === 0) {
|
@@ -1581,8 +1609,8 @@
|
|
1581
1609
|
// this method if you do not need to pre-compile a template
|
1582
1610
|
// (JST / RequireJS for example) or if you want to change
|
1583
1611
|
// the template engine used (Handebars, etc).
|
1584
|
-
compileTemplate: function(rawTemplate) {
|
1585
|
-
return _.template(rawTemplate);
|
1612
|
+
compileTemplate: function(rawTemplate, options) {
|
1613
|
+
return _.template(rawTemplate, options);
|
1586
1614
|
}
|
1587
1615
|
});
|
1588
1616
|
|
@@ -1633,10 +1661,9 @@
|
|
1633
1661
|
|
1634
1662
|
this._behaviors = Marionette.Behaviors(this);
|
1635
1663
|
|
1636
|
-
Backbone.View.
|
1664
|
+
Backbone.View.call(this, this.options);
|
1637
1665
|
|
1638
1666
|
Marionette.MonitorDOMRefresh(this);
|
1639
|
-
this.on('show', this.onShowCalled);
|
1640
1667
|
},
|
1641
1668
|
|
1642
1669
|
// Get the template for this view
|
@@ -1674,10 +1701,10 @@
|
|
1674
1701
|
|
1675
1702
|
// normalize the values of passed hash with the views `ui` selectors.
|
1676
1703
|
// `{foo: "@ui.bar"}`
|
1677
|
-
normalizeUIValues: function(hash) {
|
1704
|
+
normalizeUIValues: function(hash, properties) {
|
1678
1705
|
var ui = _.result(this, 'ui');
|
1679
1706
|
var uiBindings = _.result(this, '_uiBindings');
|
1680
|
-
return Marionette.normalizeUIValues(hash, uiBindings || ui);
|
1707
|
+
return Marionette.normalizeUIValues(hash, uiBindings || ui, properties);
|
1681
1708
|
},
|
1682
1709
|
|
1683
1710
|
// Configure `triggers` to forward DOM events to view
|
@@ -1748,9 +1775,6 @@
|
|
1748
1775
|
return this;
|
1749
1776
|
},
|
1750
1777
|
|
1751
|
-
// Internal method, handles the `show` event.
|
1752
|
-
onShowCalled: function() {},
|
1753
|
-
|
1754
1778
|
// Internal helper method to verify whether the view hasn't been destroyed
|
1755
1779
|
_ensureViewIsIntact: function() {
|
1756
1780
|
if (this.isDestroyed) {
|
@@ -1766,7 +1790,7 @@
|
|
1766
1790
|
// for you. You can specify an `onDestroy` method in your view to
|
1767
1791
|
// add custom code that is called after the view is destroyed.
|
1768
1792
|
destroy: function() {
|
1769
|
-
if (this.isDestroyed) { return; }
|
1793
|
+
if (this.isDestroyed) { return this; }
|
1770
1794
|
|
1771
1795
|
var args = _.toArray(arguments);
|
1772
1796
|
|
@@ -1781,6 +1805,8 @@
|
|
1781
1805
|
// unbind UI elements
|
1782
1806
|
this.unbindUIElements();
|
1783
1807
|
|
1808
|
+
this.isRendered = false;
|
1809
|
+
|
1784
1810
|
// remove the view from the DOM
|
1785
1811
|
this.remove();
|
1786
1812
|
|
@@ -1887,15 +1913,42 @@
|
|
1887
1913
|
// import the `triggerMethod` to trigger events with corresponding
|
1888
1914
|
// methods if the method exists
|
1889
1915
|
triggerMethod: function() {
|
1916
|
+
var ret = Marionette._triggerMethod(this, arguments);
|
1917
|
+
|
1918
|
+
this._triggerEventOnBehaviors(arguments);
|
1919
|
+
this._triggerEventOnParentLayout(arguments[0], _.rest(arguments));
|
1920
|
+
|
1921
|
+
return ret;
|
1922
|
+
},
|
1923
|
+
|
1924
|
+
_triggerEventOnBehaviors: function(args) {
|
1890
1925
|
var triggerMethod = Marionette._triggerMethod;
|
1891
|
-
var ret = triggerMethod(this, arguments);
|
1892
1926
|
var behaviors = this._behaviors;
|
1893
1927
|
// Use good ol' for as this is a very hot function
|
1894
1928
|
for (var i = 0, length = behaviors && behaviors.length; i < length; i++) {
|
1895
|
-
triggerMethod(behaviors[i],
|
1929
|
+
triggerMethod(behaviors[i], args);
|
1896
1930
|
}
|
1931
|
+
},
|
1897
1932
|
|
1898
|
-
|
1933
|
+
_triggerEventOnParentLayout: function(eventName, args) {
|
1934
|
+
var layoutView = this._parentLayoutView();
|
1935
|
+
if (!layoutView) {
|
1936
|
+
return;
|
1937
|
+
}
|
1938
|
+
|
1939
|
+
// invoke triggerMethod on parent view
|
1940
|
+
var eventPrefix = Marionette.getOption(layoutView, 'childViewEventPrefix');
|
1941
|
+
var prefixedEventName = eventPrefix + ':' + eventName;
|
1942
|
+
|
1943
|
+
Marionette._triggerMethod(layoutView, [prefixedEventName, this].concat(args));
|
1944
|
+
|
1945
|
+
// call the parent view's childEvents handler
|
1946
|
+
var childEvents = Marionette.getOption(layoutView, 'childEvents');
|
1947
|
+
var normalizedChildEvents = layoutView.normalizeMethods(childEvents);
|
1948
|
+
|
1949
|
+
if (!!normalizedChildEvents && _.isFunction(normalizedChildEvents[eventName])) {
|
1950
|
+
normalizedChildEvents[eventName].apply(layoutView, [this].concat(args));
|
1951
|
+
}
|
1899
1952
|
},
|
1900
1953
|
|
1901
1954
|
// This method returns any views that are immediate
|
@@ -1916,10 +1969,35 @@
|
|
1916
1969
|
}, children);
|
1917
1970
|
},
|
1918
1971
|
|
1972
|
+
// Internal utility for building an ancestor
|
1973
|
+
// view tree list.
|
1974
|
+
_getAncestors: function() {
|
1975
|
+
var ancestors = [];
|
1976
|
+
var parent = this._parent;
|
1977
|
+
|
1978
|
+
while (parent) {
|
1979
|
+
ancestors.push(parent);
|
1980
|
+
parent = parent._parent;
|
1981
|
+
}
|
1982
|
+
|
1983
|
+
return ancestors;
|
1984
|
+
},
|
1985
|
+
|
1986
|
+
// Returns the containing parent view.
|
1987
|
+
_parentLayoutView: function() {
|
1988
|
+
var ancestors = this._getAncestors();
|
1989
|
+
return _.find(ancestors, function(parent) {
|
1990
|
+
return parent instanceof Marionette.LayoutView;
|
1991
|
+
});
|
1992
|
+
},
|
1993
|
+
|
1919
1994
|
// Imports the "normalizeMethods" to transform hashes of
|
1920
1995
|
// events=>function references/names to a hash of events=>function references
|
1921
1996
|
normalizeMethods: Marionette.normalizeMethods,
|
1922
1997
|
|
1998
|
+
// A handy way to merge passed-in options onto the instance
|
1999
|
+
mergeOptions: Marionette.mergeOptions,
|
2000
|
+
|
1923
2001
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
1924
2002
|
getOption: Marionette.proxyGetOption,
|
1925
2003
|
|
@@ -1986,6 +2064,7 @@
|
|
1986
2064
|
this.triggerMethod('before:render', this);
|
1987
2065
|
|
1988
2066
|
this._renderTemplate();
|
2067
|
+
this.isRendered = true;
|
1989
2068
|
this.bindUIElements();
|
1990
2069
|
|
1991
2070
|
this.triggerMethod('render', this);
|
@@ -2013,8 +2092,7 @@
|
|
2013
2092
|
}
|
2014
2093
|
|
2015
2094
|
// Add in entity data and template helpers
|
2016
|
-
var data = this.serializeData();
|
2017
|
-
data = this.mixinTemplateHelpers(data);
|
2095
|
+
var data = this.mixinTemplateHelpers(this.serializeData());
|
2018
2096
|
|
2019
2097
|
// Render and add to el
|
2020
2098
|
var html = Marionette.Renderer.render(template, data, this);
|
@@ -2055,21 +2133,25 @@
|
|
2055
2133
|
// that are forwarded through the collectionview
|
2056
2134
|
childViewEventPrefix: 'childview',
|
2057
2135
|
|
2136
|
+
// flag for maintaining the sorted order of the collection
|
2137
|
+
sort: true,
|
2138
|
+
|
2058
2139
|
// constructor
|
2059
2140
|
// option to pass `{sort: false}` to prevent the `CollectionView` from
|
2060
2141
|
// maintaining the sorted order of the collection.
|
2061
2142
|
// This will fallback onto appending childView's to the end.
|
2143
|
+
//
|
2144
|
+
// option to pass `{comparator: compFunction()}` to allow the `CollectionView`
|
2145
|
+
// to use a custom sort order for the collection.
|
2062
2146
|
constructor: function(options){
|
2063
|
-
var initOptions = options || {};
|
2064
|
-
if (_.isUndefined(this.sort)){
|
2065
|
-
this.sort = _.isUndefined(initOptions.sort) ? true : initOptions.sort;
|
2066
|
-
}
|
2067
2147
|
|
2068
2148
|
this.once('render', this._initialEvents);
|
2069
2149
|
this._initChildViewStorage();
|
2070
2150
|
|
2071
2151
|
Marionette.View.apply(this, arguments);
|
2072
2152
|
|
2153
|
+
this.on('show', this._onShowCalled);
|
2154
|
+
|
2073
2155
|
this.initRenderBuffer();
|
2074
2156
|
},
|
2075
2157
|
|
@@ -2077,7 +2159,6 @@
|
|
2077
2159
|
// it's much more performant to insert elements into a document
|
2078
2160
|
// fragment and then insert that document fragment into the page
|
2079
2161
|
initRenderBuffer: function() {
|
2080
|
-
this.elBuffer = document.createDocumentFragment();
|
2081
2162
|
this._bufferedChildren = [];
|
2082
2163
|
},
|
2083
2164
|
|
@@ -2089,7 +2170,9 @@
|
|
2089
2170
|
endBuffering: function() {
|
2090
2171
|
this.isBuffering = false;
|
2091
2172
|
this._triggerBeforeShowBufferedChildren();
|
2092
|
-
|
2173
|
+
|
2174
|
+
this.attachBuffer(this);
|
2175
|
+
|
2093
2176
|
this._triggerShowBufferedChildren();
|
2094
2177
|
this.initRenderBuffer();
|
2095
2178
|
},
|
@@ -2122,18 +2205,26 @@
|
|
2122
2205
|
this.listenTo(this.collection, 'remove', this._onCollectionRemove);
|
2123
2206
|
this.listenTo(this.collection, 'reset', this.render);
|
2124
2207
|
|
2125
|
-
if (this.sort) {
|
2208
|
+
if (this.getOption('sort')) {
|
2126
2209
|
this.listenTo(this.collection, 'sort', this._sortViews);
|
2127
2210
|
}
|
2128
2211
|
}
|
2129
2212
|
},
|
2130
2213
|
|
2131
2214
|
// Handle a child added to the collection
|
2132
|
-
_onCollectionAdd: function(child) {
|
2133
|
-
|
2134
|
-
|
2135
|
-
|
2136
|
-
|
2215
|
+
_onCollectionAdd: function(child, collection, opts) {
|
2216
|
+
var index;
|
2217
|
+
if (opts.at !== undefined) {
|
2218
|
+
index = opts.at;
|
2219
|
+
} else {
|
2220
|
+
index = _.indexOf(this._filteredSortedModels(), child);
|
2221
|
+
}
|
2222
|
+
|
2223
|
+
if (this._shouldAddChild(child, index)) {
|
2224
|
+
this.destroyEmptyView();
|
2225
|
+
var ChildView = this.getChildView(child);
|
2226
|
+
this.addChild(child, ChildView, index);
|
2227
|
+
}
|
2137
2228
|
},
|
2138
2229
|
|
2139
2230
|
// get the child view by model it holds, and remove it
|
@@ -2143,8 +2234,7 @@
|
|
2143
2234
|
this.checkEmpty();
|
2144
2235
|
},
|
2145
2236
|
|
2146
|
-
|
2147
|
-
onShowCalled: function() {
|
2237
|
+
_onShowCalled: function() {
|
2148
2238
|
this.children.each(_.partial(this._triggerMethodOnChild, 'show'));
|
2149
2239
|
},
|
2150
2240
|
|
@@ -2155,23 +2245,60 @@
|
|
2155
2245
|
this._ensureViewIsIntact();
|
2156
2246
|
this.triggerMethod('before:render', this);
|
2157
2247
|
this._renderChildren();
|
2248
|
+
this.isRendered = true;
|
2158
2249
|
this.triggerMethod('render', this);
|
2159
2250
|
return this;
|
2160
2251
|
},
|
2161
2252
|
|
2253
|
+
// Reorder DOM after sorting. When your element's rendering
|
2254
|
+
// do not use their index, you can pass reorderOnSort: true
|
2255
|
+
// to only reorder the DOM after a sort instead of rendering
|
2256
|
+
// all the collectionView
|
2257
|
+
reorder: function () {
|
2258
|
+
var children = this.children;
|
2259
|
+
var models = this._filteredSortedModels();
|
2260
|
+
var modelsChanged = _.find(models, function (model) {
|
2261
|
+
return !children.findByModel(model);
|
2262
|
+
});
|
2263
|
+
|
2264
|
+
// If the models we're displaying have changed due to filtering
|
2265
|
+
// We need to add and/or remove child views
|
2266
|
+
// So render as normal
|
2267
|
+
if (modelsChanged) {
|
2268
|
+
this.render();
|
2269
|
+
} else {
|
2270
|
+
// get the DOM nodes in the same order as the models
|
2271
|
+
var els = _.map(models, function (model) {
|
2272
|
+
return children.findByModel(model).el;
|
2273
|
+
});
|
2274
|
+
|
2275
|
+
// since append moves elements that are already in the DOM,
|
2276
|
+
// appending the elements will effectively reorder them
|
2277
|
+
this.triggerMethod('before:reorder');
|
2278
|
+
this.$el.append(els);
|
2279
|
+
this.triggerMethod('reorder');
|
2280
|
+
}
|
2281
|
+
},
|
2282
|
+
|
2162
2283
|
// Render view after sorting. Override this method to
|
2163
2284
|
// change how the view renders after a `sort` on the collection.
|
2164
2285
|
// An example of this would be to only `renderChildren` in a `CompositeView`
|
2165
2286
|
// rather than the full view.
|
2166
2287
|
resortView: function() {
|
2167
|
-
|
2288
|
+
if (Marionette.getOption(this, 'reorderOnSort')) {
|
2289
|
+
this.reorder();
|
2290
|
+
} else {
|
2291
|
+
this.render();
|
2292
|
+
}
|
2168
2293
|
},
|
2169
2294
|
|
2170
2295
|
// Internal method. This checks for any changes in the order of the collection.
|
2171
2296
|
// If the index of any view doesn't match, it will render.
|
2172
2297
|
_sortViews: function() {
|
2298
|
+
var models = this._filteredSortedModels();
|
2299
|
+
|
2173
2300
|
// check for any changes in sort order of views
|
2174
|
-
var orderChanged =
|
2301
|
+
var orderChanged = _.find(models, function(item, index){
|
2175
2302
|
var view = this.children.findByModel(item);
|
2176
2303
|
return !view || view._index !== index;
|
2177
2304
|
}, this);
|
@@ -2199,18 +2326,51 @@
|
|
2199
2326
|
this.showCollection();
|
2200
2327
|
this.endBuffering();
|
2201
2328
|
this.triggerMethod('render:collection', this);
|
2329
|
+
|
2330
|
+
// If we have shown children and none have passed the filter, show the empty view
|
2331
|
+
if (this.children.isEmpty()) {
|
2332
|
+
this.showEmptyView();
|
2333
|
+
}
|
2202
2334
|
}
|
2203
2335
|
},
|
2204
2336
|
|
2205
2337
|
// Internal method to loop through collection and show each child view.
|
2206
2338
|
showCollection: function() {
|
2207
2339
|
var ChildView;
|
2208
|
-
|
2340
|
+
|
2341
|
+
var models = this._filteredSortedModels();
|
2342
|
+
|
2343
|
+
_.each(models, function(child, index) {
|
2209
2344
|
ChildView = this.getChildView(child);
|
2210
2345
|
this.addChild(child, ChildView, index);
|
2211
2346
|
}, this);
|
2212
2347
|
},
|
2213
2348
|
|
2349
|
+
// Allow the collection to be sorted by a custom view comparator
|
2350
|
+
_filteredSortedModels: function() {
|
2351
|
+
var models;
|
2352
|
+
var viewComparator = this.getViewComparator();
|
2353
|
+
|
2354
|
+
if (viewComparator) {
|
2355
|
+
if (_.isString(viewComparator) || viewComparator.length === 1) {
|
2356
|
+
models = this.collection.sortBy(viewComparator, this);
|
2357
|
+
} else {
|
2358
|
+
models = _.clone(this.collection.models).sort(_.bind(viewComparator, this));
|
2359
|
+
}
|
2360
|
+
} else {
|
2361
|
+
models = this.collection.models;
|
2362
|
+
}
|
2363
|
+
|
2364
|
+
// Filter after sorting in case the filter uses the index
|
2365
|
+
if (this.getOption('filter')) {
|
2366
|
+
models = _.filter(models, function (model, index) {
|
2367
|
+
return this._shouldAddChild(model, index);
|
2368
|
+
}, this);
|
2369
|
+
}
|
2370
|
+
|
2371
|
+
return models;
|
2372
|
+
},
|
2373
|
+
|
2214
2374
|
// Internal method to show an empty view in place of
|
2215
2375
|
// a collection of child views, when the collection is empty
|
2216
2376
|
showEmptyView: function() {
|
@@ -2329,7 +2489,7 @@
|
|
2329
2489
|
// Internal method. This decrements or increments the indices of views after the
|
2330
2490
|
// added/removed view to keep in sync with the collection.
|
2331
2491
|
_updateIndices: function(view, increment, index) {
|
2332
|
-
if (!this.sort) {
|
2492
|
+
if (!this.getOption('sort')) {
|
2333
2493
|
return;
|
2334
2494
|
}
|
2335
2495
|
|
@@ -2355,6 +2515,12 @@
|
|
2355
2515
|
|
2356
2516
|
this.triggerMethod('before:add:child', view);
|
2357
2517
|
|
2518
|
+
// trigger the 'before:show' event on `view` if the collection view
|
2519
|
+
// has already been shown
|
2520
|
+
if (this._isShown && !this.isBuffering) {
|
2521
|
+
Marionette.triggerMethodOn(view, 'before:show');
|
2522
|
+
}
|
2523
|
+
|
2358
2524
|
// Store the child view itself so we can properly
|
2359
2525
|
// remove and/or destroy it later
|
2360
2526
|
this.children.add(view);
|
@@ -2417,8 +2583,17 @@
|
|
2417
2583
|
},
|
2418
2584
|
|
2419
2585
|
// You might need to override this if you've overridden attachHtml
|
2420
|
-
attachBuffer: function(collectionView
|
2421
|
-
collectionView.$el.append(
|
2586
|
+
attachBuffer: function(collectionView) {
|
2587
|
+
collectionView.$el.append(this._createBuffer(collectionView));
|
2588
|
+
},
|
2589
|
+
|
2590
|
+
// Create a fragment buffer from the currently buffered children
|
2591
|
+
_createBuffer: function(collectionView) {
|
2592
|
+
var elBuffer = document.createDocumentFragment();
|
2593
|
+
_.each(collectionView._bufferedChildren, function(b) {
|
2594
|
+
elBuffer.appendChild(b.el);
|
2595
|
+
});
|
2596
|
+
return elBuffer;
|
2422
2597
|
},
|
2423
2598
|
|
2424
2599
|
// Append the HTML to the collection's `el`.
|
@@ -2429,8 +2604,7 @@
|
|
2429
2604
|
// buffering happens on reset events and initial renders
|
2430
2605
|
// in order to reduce the number of inserts into the
|
2431
2606
|
// document, which are expensive.
|
2432
|
-
collectionView.
|
2433
|
-
collectionView._bufferedChildren.push(childView);
|
2607
|
+
collectionView._bufferedChildren.splice(index, 0, childView);
|
2434
2608
|
}
|
2435
2609
|
else {
|
2436
2610
|
// If we've already rendered the main collection, append
|
@@ -2446,7 +2620,7 @@
|
|
2446
2620
|
// the correct position.
|
2447
2621
|
_insertBefore: function(childView, index) {
|
2448
2622
|
var currentView;
|
2449
|
-
var findPosition = this.sort && (index < this.children.length - 1);
|
2623
|
+
var findPosition = this.getOption('sort') && (index < this.children.length - 1);
|
2450
2624
|
if (findPosition) {
|
2451
2625
|
// Find the view after this one
|
2452
2626
|
currentView = this.children.find(function (view) {
|
@@ -2475,7 +2649,7 @@
|
|
2475
2649
|
|
2476
2650
|
// Handle cleanup and other destroying needs for the collection of views
|
2477
2651
|
destroy: function() {
|
2478
|
-
if (this.isDestroyed) { return; }
|
2652
|
+
if (this.isDestroyed) { return this; }
|
2479
2653
|
|
2480
2654
|
this.triggerMethod('before:destroy:collection');
|
2481
2655
|
this.destroyChildren();
|
@@ -2493,6 +2667,18 @@
|
|
2493
2667
|
return childViews;
|
2494
2668
|
},
|
2495
2669
|
|
2670
|
+
// Return true if the given child should be shown
|
2671
|
+
// Return false otherwise
|
2672
|
+
// The filter will be passed (child, index, collection)
|
2673
|
+
// Where
|
2674
|
+
// 'child' is the given model
|
2675
|
+
// 'index' is the index of that model in the collection
|
2676
|
+
// 'collection' is the collection referenced by this CollectionView
|
2677
|
+
_shouldAddChild: function (child, index) {
|
2678
|
+
var filter = this.getOption('filter');
|
2679
|
+
return !_.isFunction(filter) || filter.call(this, child, index, this.collection);
|
2680
|
+
},
|
2681
|
+
|
2496
2682
|
// Set up the child view event forwarding. Uses a "childview:"
|
2497
2683
|
// prefix in front of all forwarded events.
|
2498
2684
|
proxyChildEvents: function(view) {
|
@@ -2514,11 +2700,15 @@
|
|
2514
2700
|
}
|
2515
2701
|
|
2516
2702
|
this.triggerMethod.apply(this, args);
|
2517
|
-
}
|
2703
|
+
});
|
2518
2704
|
},
|
2519
2705
|
|
2520
2706
|
_getImmediateChildren: function() {
|
2521
2707
|
return _.values(this.children._views);
|
2708
|
+
},
|
2709
|
+
|
2710
|
+
getViewComparator: function() {
|
2711
|
+
return this.getOption('viewComparator');
|
2522
2712
|
}
|
2523
2713
|
});
|
2524
2714
|
|
@@ -2554,7 +2744,7 @@
|
|
2554
2744
|
this.listenTo(this.collection, 'remove', this._onCollectionRemove);
|
2555
2745
|
this.listenTo(this.collection, 'reset', this._renderChildren);
|
2556
2746
|
|
2557
|
-
if (this.sort) {
|
2747
|
+
if (this.getOption('sort')) {
|
2558
2748
|
this.listenTo(this.collection, 'sort', this._sortViews);
|
2559
2749
|
}
|
2560
2750
|
}
|
@@ -2586,7 +2776,7 @@
|
|
2586
2776
|
// Renders the model and the collection.
|
2587
2777
|
render: function() {
|
2588
2778
|
this._ensureViewIsIntact();
|
2589
|
-
this.
|
2779
|
+
this._isRendering = true;
|
2590
2780
|
this.resetChildViewContainer();
|
2591
2781
|
|
2592
2782
|
this.triggerMethod('before:render', this);
|
@@ -2594,12 +2784,14 @@
|
|
2594
2784
|
this._renderTemplate();
|
2595
2785
|
this._renderChildren();
|
2596
2786
|
|
2787
|
+
this._isRendering = false;
|
2788
|
+
this.isRendered = true;
|
2597
2789
|
this.triggerMethod('render', this);
|
2598
2790
|
return this;
|
2599
2791
|
},
|
2600
2792
|
|
2601
2793
|
_renderChildren: function() {
|
2602
|
-
if (this.isRendered) {
|
2794
|
+
if (this.isRendered || this._isRendering) {
|
2603
2795
|
Marionette.CollectionView.prototype._renderChildren.call(this);
|
2604
2796
|
}
|
2605
2797
|
},
|
@@ -2643,9 +2835,9 @@
|
|
2643
2835
|
},
|
2644
2836
|
|
2645
2837
|
// You might need to override this if you've overridden attachHtml
|
2646
|
-
attachBuffer: function(compositeView
|
2838
|
+
attachBuffer: function(compositeView) {
|
2647
2839
|
var $container = this.getChildViewContainer(compositeView);
|
2648
|
-
$container.append(
|
2840
|
+
$container.append(this._createBuffer(compositeView));
|
2649
2841
|
},
|
2650
2842
|
|
2651
2843
|
// Internal method. Append a view to the end of the $el.
|
@@ -2710,6 +2902,14 @@
|
|
2710
2902
|
Marionette.LayoutView = Marionette.ItemView.extend({
|
2711
2903
|
regionClass: Marionette.Region,
|
2712
2904
|
|
2905
|
+
options: {
|
2906
|
+
destroyImmediate: false
|
2907
|
+
},
|
2908
|
+
|
2909
|
+
// used as the prefix for child view events
|
2910
|
+
// that are forwarded through the layoutview
|
2911
|
+
childViewEventPrefix: 'childview',
|
2912
|
+
|
2713
2913
|
// Ensure the regions are available when the `initialize` method
|
2714
2914
|
// is called.
|
2715
2915
|
constructor: function(options) {
|
@@ -2744,11 +2944,23 @@
|
|
2744
2944
|
// Handle destroying regions, and then destroy the view itself.
|
2745
2945
|
destroy: function() {
|
2746
2946
|
if (this.isDestroyed) { return this; }
|
2747
|
-
|
2947
|
+
// #2134: remove parent element before destroying the child views, so
|
2948
|
+
// removing the child views doesn't retrigger repaints
|
2949
|
+
if(this.getOption('destroyImmediate') === true) {
|
2950
|
+
this.$el.remove();
|
2951
|
+
}
|
2748
2952
|
this.regionManager.destroy();
|
2749
2953
|
return Marionette.ItemView.prototype.destroy.apply(this, arguments);
|
2750
2954
|
},
|
2751
2955
|
|
2956
|
+
showChildView: function(regionName, view) {
|
2957
|
+
return this.getRegion(regionName).show(view);
|
2958
|
+
},
|
2959
|
+
|
2960
|
+
getChildView: function(regionName) {
|
2961
|
+
return this.getRegion(regionName).currentView;
|
2962
|
+
},
|
2963
|
+
|
2752
2964
|
// Add a single region, by name, to the layoutView
|
2753
2965
|
addRegion: function(name, definition) {
|
2754
2966
|
var regions = {};
|
@@ -2808,7 +3020,7 @@
|
|
2808
3020
|
|
2809
3021
|
// Normalize region selectors hash to allow
|
2810
3022
|
// a user to use the @ui. syntax.
|
2811
|
-
regions = this.normalizeUIValues(regions);
|
3023
|
+
regions = this.normalizeUIValues(regions, ['selector', 'el']);
|
2812
3024
|
|
2813
3025
|
this.addRegions(regions);
|
2814
3026
|
},
|
@@ -2877,6 +3089,12 @@
|
|
2877
3089
|
this.view = view;
|
2878
3090
|
this.defaults = _.result(this, 'defaults') || {};
|
2879
3091
|
this.options = _.extend({}, this.defaults, options);
|
3092
|
+
// Construct an internal UI hash using
|
3093
|
+
// the views UI hash and then the behaviors UI hash.
|
3094
|
+
// This allows the user to use UI hash elements
|
3095
|
+
// defined in the parent view as well as those
|
3096
|
+
// defined in the given behavior.
|
3097
|
+
this.ui = _.extend({}, _.result(view, 'ui'), _.result(this, 'ui'));
|
2880
3098
|
|
2881
3099
|
Marionette.Object.apply(this, arguments);
|
2882
3100
|
},
|
@@ -2892,6 +3110,8 @@
|
|
2892
3110
|
// Overrides Object#destroy to prevent additional events from being triggered.
|
2893
3111
|
destroy: function() {
|
2894
3112
|
this.stopListening();
|
3113
|
+
|
3114
|
+
return this;
|
2895
3115
|
},
|
2896
3116
|
|
2897
3117
|
proxyViewProperties: function (view) {
|
@@ -2939,23 +3159,15 @@
|
|
2939
3159
|
|
2940
3160
|
behaviorEvents: function(behaviorEvents, behaviors) {
|
2941
3161
|
var _behaviorsEvents = {};
|
2942
|
-
var viewUI = this._uiBindings || _.result(this, 'ui');
|
2943
3162
|
|
2944
3163
|
_.each(behaviors, function(b, i) {
|
2945
3164
|
var _events = {};
|
2946
3165
|
var behaviorEvents = _.clone(_.result(b, 'events')) || {};
|
2947
|
-
var behaviorUI = b._uiBindings || _.result(b, 'ui');
|
2948
3166
|
|
2949
|
-
// Construct an internal UI hash first using
|
2950
|
-
// the views UI hash and then the behaviors UI hash.
|
2951
|
-
// This allows the user to use UI hash elements
|
2952
|
-
// defined in the parent view as well as those
|
2953
|
-
// defined in the given behavior.
|
2954
|
-
var ui = _.extend({}, viewUI, behaviorUI);
|
2955
3167
|
|
2956
3168
|
// Normalize behavior events hash to allow
|
2957
3169
|
// a user to use the @ui. syntax.
|
2958
|
-
behaviorEvents = Marionette.normalizeUIKeys(behaviorEvents,
|
3170
|
+
behaviorEvents = Marionette.normalizeUIKeys(behaviorEvents, getBehaviorsUI(b));
|
2959
3171
|
|
2960
3172
|
var j = 0;
|
2961
3173
|
_.each(behaviorEvents, function(behaviour, key) {
|
@@ -3042,7 +3254,6 @@
|
|
3042
3254
|
// for views
|
3043
3255
|
function BehaviorTriggersBuilder(view, behaviors) {
|
3044
3256
|
this._view = view;
|
3045
|
-
this._viewUI = _.result(view, 'ui');
|
3046
3257
|
this._behaviors = behaviors;
|
3047
3258
|
this._triggers = {};
|
3048
3259
|
}
|
@@ -3056,10 +3267,9 @@
|
|
3056
3267
|
|
3057
3268
|
// Internal method to build all trigger handlers for a given behavior
|
3058
3269
|
_buildTriggerHandlersForBehavior: function(behavior, i) {
|
3059
|
-
var ui = _.extend({}, this._viewUI, _.result(behavior, 'ui'));
|
3060
3270
|
var triggersHash = _.clone(_.result(behavior, 'triggers')) || {};
|
3061
3271
|
|
3062
|
-
triggersHash = Marionette.normalizeUIKeys(triggersHash,
|
3272
|
+
triggersHash = Marionette.normalizeUIKeys(triggersHash, getBehaviorsUI(behavior));
|
3063
3273
|
|
3064
3274
|
_.each(triggersHash, _.bind(this._setHandlerForBehavior, this, behavior, i));
|
3065
3275
|
},
|
@@ -3076,6 +3286,10 @@
|
|
3076
3286
|
}
|
3077
3287
|
});
|
3078
3288
|
|
3289
|
+
function getBehaviorsUI(behavior) {
|
3290
|
+
return behavior._uiBindings || behavior.ui;
|
3291
|
+
}
|
3292
|
+
|
3079
3293
|
return Behaviors;
|
3080
3294
|
|
3081
3295
|
})(Marionette, _);
|
@@ -3157,6 +3371,8 @@
|
|
3157
3371
|
this.route(route, methodName, _.bind(method, controller));
|
3158
3372
|
},
|
3159
3373
|
|
3374
|
+
mergeOptions: Marionette.mergeOptions,
|
3375
|
+
|
3160
3376
|
// Proxy `getOption` to enable getting options from this or this.options by name.
|
3161
3377
|
getOption: Marionette.proxyGetOption,
|
3162
3378
|
|
@@ -3464,7 +3680,7 @@
|
|
3464
3680
|
|
3465
3681
|
// get the custom args passed in after the module definition and
|
3466
3682
|
// get rid of the module name and definition function
|
3467
|
-
var customArgs = _.
|
3683
|
+
var customArgs = _.drop(arguments, 3);
|
3468
3684
|
|
3469
3685
|
// Split the module names and get the number of submodules.
|
3470
3686
|
// i.e. an example module name of `Doge.Wow.Amaze` would
|