New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

marionette.toolkit

Package Overview
Dependencies
Maintainers
5
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

marionette.toolkit - npm Package Compare versions

Comparing version 4.0.0 to 5.0.0-alpha.1

348

dist/marionette.toolkit.js
/**
* marionette.toolkit - A collection of opinionated Backbone.Marionette extensions for large scale application architecture.
* @version v4.0.0
* @version v5.0.0-alpha.1
* @link https://github.com/RoundingWellOS/marionette.toolkit

@@ -9,9 +9,8 @@ * @license MIT

(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('underscore'), require('backbone.marionette'), require('backbone')) :
typeof define === 'function' && define.amd ? define(['underscore', 'backbone.marionette', 'backbone'], factory) :
(global.Marionette = global.Marionette || {}, global.Marionette.Toolkit = factory(global._,global.Marionette,global.Backbone));
}(this, function (_,Marionette,Backbone) { 'use strict';
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('underscore'), require('backbone'), require('backbone.marionette')) :
typeof define === 'function' && define.amd ? define(['exports', 'underscore', 'backbone', 'backbone.marionette'], factory) :
(factory((global.Marionette = global.Marionette || {}, global.Marionette.Toolkit = global.Marionette.Toolkit || {}),global._,global.Backbone,global.Marionette));
}(this, function (exports,_,Backbone,backbone_marionette) { 'use strict';
_ = 'default' in _ ? _['default'] : _;
Marionette = 'default' in Marionette ? Marionette['default'] : Marionette;
Backbone = 'default' in Backbone ? Backbone['default'] : Backbone;

@@ -23,3 +22,3 @@

* This provides methods used for keeping state using a Backbone.Model. It's meant to
* be used with either a Marionette.Object or Backbone.View.
* be used with either a Marionette.MnObject or Backbone.View.
*

@@ -144,6 +143,3 @@ * @mixin

throw new Marionette.Error({
name: 'InvalidStateModelError',
message: '"StateModel" must be a model class or a function that returns a model class'
});
throw new Error('"StateModel" must be a model class or a function that returns a model class');
},

@@ -200,2 +196,31 @@

/**
* Toggle a property on the _stateModel.
*
* @public
* @method toggleState
* @param {String} attr - Attribute name of stateModel.
* @param {val} [value] - Attribute value.
* @returns {Backbone.Model} - The _stateModel or attribute value.
*/
toggleState: function toggleState(attr, val) {
if (arguments.length > 1) return this._stateModel.set(attr, !!val);
return this._stateModel.set(attr, !this._stateModel.get(attr));
},
/**
* Check if _stateModel has a property
*
* @public
* @method hasState
* @param {String} [attr] - Attribute name of stateModel.
* @returns {Boolean}
*/
hasState: function hasState(attr) {
return this._stateModel.has(attr);
},
/**
* Clean up any listeners on the _stateModel.

@@ -256,20 +281,17 @@ *

}
this._initListeners();
},
_getChildStartOpts: function _getChildStartOpts(childApp) {
var _this = this;
var tkOpts = childApp._tkOpts || {};
/**
* The child apps should be handled while the app is running;
* After start, before stop, and before destroy.
*
* @private
* @method _initListeners
*/
_initListeners: function _initListeners() {
this.on({
'start': this._startChildApps,
'before:stop': this._stopChildApps,
'before:destroy': this._destroyChildApps
var opts = {
region: this.getRegion(tkOpts.regionName)
};
_.each(tkOpts.getOptions, function (opt) {
opts[opt] = _this.getOption(opt);
});
return opts;
},

@@ -285,6 +307,10 @@

_startChildApps: function _startChildApps() {
var _this2 = this;
var shouldStartOption = this._isRestarting ? 'restartWithParent' : 'startWithParent';
_.each(this._childApps, function (childApp) {
if (_.result(childApp, 'startWithParent')) {
childApp.start();
}
if (!_.result(childApp, shouldStartOption)) return;
var opts = _this2._getChildStartOpts(childApp);
childApp.start(opts);
});

@@ -301,4 +327,5 @@ },

_stopChildApps: function _stopChildApps() {
var shouldStopOption = this._isRestarting ? 'restartWithParent' : 'stopWithParent';
_.each(this._childApps, function (childApp) {
if (_.result(childApp, 'stopWithParent')) {
if (_.result(childApp, shouldStopOption)) {
childApp.stop();

@@ -319,3 +346,5 @@ }

startChildApp: function startChildApp(appName, options) {
return this.getChildApp(appName).start(options);
var childApp = this.getChildApp(appName);
var opts = this._getChildStartOpts(childApp);
return childApp.start(_.extend(opts, options));
},

@@ -328,7 +357,8 @@

* @param {String} appName - Name of childApp to stop
* @param {Object} options - Stop options for app
* @public
* @method stopChildApp
*/
stopChildApp: function stopChildApp(appName) {
return this.getChildApp(appName).stop();
stopChildApp: function stopChildApp(appName, options) {
return this.getChildApp(appName).stop(options);
},

@@ -362,5 +392,9 @@

var AppClass = appConfig.AppClass;
var options = _.omit(appConfig, 'AppClass');
var options = _.omit(appConfig, 'AppClass', 'regionName', 'getOptions');
return this.buildApp(AppClass, options);
var app = this.buildApp(AppClass, options);
app._tkOpts = _.pick(appConfig, 'regionName', 'getOptions');
return app;
},

@@ -417,6 +451,3 @@

if (this._childApps[appName]) {
throw new Marionette.Error({
name: 'DuplicateChildAppError',
message: 'A child App with name "' + appName + '" has already been added.'
});
throw new Error('A child App with name "' + appName + '" has already been added.');
}

@@ -459,6 +490,3 @@ },

if (!childApp) {
throw new Marionette.Error({
name: 'AddChildAppError',
message: 'App build failed. Incorrect configuration.'
});
throw new Error('App build failed. Incorrect configuration.');
}

@@ -471,3 +499,4 @@

// When the app is destroyed remove the cached app.
childApp.on('destroy', _.partial(this._removeChildApp, appName), this);
// Listener setup relative to the childApp's running state (using _on)
childApp._on('destroy', _.partial(this._removeChildApp, appName), this);

@@ -630,3 +659,3 @@ if (this.isRunning() && _.result(childApp, 'startWithParent')) {

return Marionette.Object.prototype.on.apply(this, arguments);
return backbone_marionette.MnObject.prototype.on.apply(this, arguments);
},

@@ -636,2 +665,11 @@

/**
* Keep a copy of non-running on for internal use
*
* @private
* @method _on
* @returns {EventListeners}
*/
_on: backbone_marionette.MnObject.prototype.on,
/**
* Overrides `Backbone.Event.listenTo()`

@@ -649,3 +687,3 @@ * If this `App` is running it will register the listener for removal `onStop`

}
return Marionette.Object.prototype.listenTo.apply(this, arguments);
return backbone_marionette.MnObject.prototype.listenTo.apply(this, arguments);
},

@@ -655,2 +693,11 @@

/**
* Keep a copy of non-running on for internal use
*
* @private
* @method _listenTo
* @returns {EventListeners}
*/
_listenTo: backbone_marionette.MnObject.prototype.listenTo,
/**
* Overrides `Backbone.Event.listenToOnce()`

@@ -669,3 +716,3 @@ * If this `App` is running it will register the listener for removal `onStop`

return Marionette.Object.prototype.listenToOnce.apply(this, arguments);
return backbone_marionette.MnObject.prototype.listenToOnce.apply(this, arguments);
}

@@ -750,3 +797,3 @@ };

var ClassOptions$1 = ['startWithParent', 'stopWithParent', 'startAfterInitialized', 'preventDestroy', 'StateModel', 'stateEvents', 'viewEventPrefix', 'viewEvents', 'viewTriggers'];
var ClassOptions$1 = ['startWithParent', 'restartWithParent', 'stopWithParent', 'startAfterInitialized', 'preventDestroy', 'StateModel', 'stateEvents', 'viewEventPrefix', 'viewEvents', 'viewTriggers'];

@@ -761,3 +808,3 @@ /**

*/
var App = Marionette.Application.extend({
var App = backbone_marionette.Application.extend({

@@ -774,2 +821,11 @@ /**

/**
* Internal flag indiciate when `App` is in the process of stopping then starting.
*
* @private
* @type {Boolean}
* @default false
*/
_isRestarting: false,
/**
* Set to true if a parent `App` should not be able to destroy this `App`.

@@ -807,2 +863,10 @@ *

/**
* Set to true if a parent `App` should be able to restart this `App`.
*
* @type {Boolean|Function}
* @default false
*/
restartWithParent: false,
/**
* @public

@@ -812,2 +876,3 @@ * @constructs App

* @param {Boolean} [options.startWithParent]
* @param {Boolean} [options.restartWithParent]
* @param {Boolean} [options.stopWithParent]

@@ -825,9 +890,6 @@ * @param {Boolean} [options.startAfterInitialized]

// ViewEventMixin
this._buildEventProxies();
// ChildAppsMixin
this._initChildApps(options);
Marionette.Application.call(this, options);
backbone_marionette.Application.call(this, options);

@@ -841,16 +903,2 @@ if (_.result(this, 'startAfterInitialized')) {

/**
* Override of Marionette's Application._initRegion
* Allows region monitor to be setup prior to initialize
*
* @private
* @method _initRegion
* @memberOf App
*/
_initRegion: function _initRegion() {
Marionette.Application.prototype._initRegion.call(this);
this._regionEventMonitor();
},
/**
* Internal helper to verify if `App` has been destroyed

@@ -865,6 +913,3 @@ *

if (this._isDestroyed) {
throw new Marionette.Error({
name: 'AppDestroyedError',
message: 'App has already been destroyed and cannot be used.'
});
throw new Error('App has already been destroyed and cannot be used.');
}

@@ -930,2 +975,5 @@ },

// ViewEventMixin
this._buildEventProxies();
this.triggerMethod('before:start', options);

@@ -935,5 +983,6 @@

// StateMixin
this.delegateStateEvents();
this._bindRunningEvents();
this._startChildApps();
this.triggerStart(options);

@@ -946,2 +995,24 @@

/**
* Sets up region, view, and state events.
* To only be called after `isRunning` is true
*
* @private
* @method _bindRunningEvents
* @memberOf App
*/
_bindRunningEvents: function _bindRunningEvents() {
if (this._region) {
this._regionEventMonitor();
}
if (this._view) {
this._proxyViewEvents(this._view);
}
// StateMixin
this.delegateStateEvents();
},
/**
* Sets the app lifecycle to not running

@@ -1001,2 +1072,4 @@ * then sets the app lifecycle to running with ending state

this._stopChildApps();
this._isRunning = false;

@@ -1029,6 +1102,8 @@

delete this._view;
this._removeView();
Marionette.Application.prototype.destroy.apply(this, arguments);
this._destroyChildApps();
backbone_marionette.Application.prototype.destroy.apply(this, arguments);
return this;

@@ -1054,4 +1129,10 @@ },

this._regionEventMonitor();
if (region.currentView) {
this.setView(region.currentView);
}
if (this._isRunning) {
this._regionEventMonitor();
}
return region;

@@ -1070,3 +1151,6 @@ },

_regionEventMonitor: function _regionEventMonitor() {
this.listenTo(this._region, 'before:show', this._onBeforeShow);
this.listenTo(this._region, {
'before:show': this._onBeforeShow,
'empty': this._onEmpty
});
},

@@ -1088,2 +1172,29 @@

/**
* Region monitor handler which empties the region's view
*
* @private
* @method _onEmpty
* @memberOf App
*/
_onEmpty: function _onEmpty() {
this._removeView();
},
/**
* Region monitor handler which deletes the region's view and listeners to view
*
* @private
* @method _removeView
* @memberOf App
*/
_removeView: function _removeView() {
if (this._view) {
this.stopListening(this._view);
delete this._view;
}
},
/**
* Get the Application's Region or

@@ -1128,4 +1239,9 @@ * Get a region from the Application's View

// ViewEventsMixin
this._proxyViewEvents(view);
if (this._isRunning) {
this._proxyViewEvents(view);
}
// Internal non-running listener
this._listenTo(this._view, 'destroy', this._removeView);
return view;

@@ -1144,3 +1260,3 @@ },

getView: function getView() {
return this._view;
return this._view || this._region && this._region.currentView;
},

@@ -1214,3 +1330,3 @@

/**
* Reusable Marionette.Object with View management boilerplate
* Reusable Marionette.MnObject with View management boilerplate
*

@@ -1222,3 +1338,3 @@ * @public

*/
var Component = Marionette.Object.extend({
var Component = backbone_marionette.MnObject.extend({

@@ -1230,3 +1346,3 @@ /**

*/
ViewClass: Marionette.View,
ViewClass: backbone_marionette.View,

@@ -1259,3 +1375,3 @@ /**

Marionette.Object.call(this, options);
backbone_marionette.MnObject.call(this, options);

@@ -1313,13 +1429,7 @@ // StateMixin

if (this._isShown) {
throw new Marionette.Error({
name: 'ComponentShowError',
message: 'Component has already been shown in a region.'
});
throw new Error('Component has already been shown in a region.');
}
if (!region) {
throw new Marionette.Error({
name: 'ComponentRegionError',
message: 'Component has no defined region.'
});
throw new Error('Component has no defined region.');
}

@@ -1377,6 +1487,3 @@

throw new Marionette.Error({
name: 'InvalidViewClassError',
message: '"ViewClass" must be a view class or a function that returns a view class'
});
throw new Error('"ViewClass" must be a view class or a function that returns a view class');
},

@@ -1415,4 +1522,3 @@

// Show the view in the region
this.getRegion().show(view);
this.showView(view);

@@ -1428,2 +1534,16 @@ this._shouldDestroy = true;

/**
* Override this to change how the component's view is shown in the region
*
* @public
* @method showView
* @memberOf Component
* @param {Object} view - view built from a viewClass and viewOptions
*/
showView: function showView(view) {
// Show the view in the region
this.getRegion().show(view);
},
/**
* Mixin initial State with any other viewOptions

@@ -1472,3 +1592,3 @@ *

if (this._shouldDestroy) {
Marionette.Object.prototype.destroy.apply(this, arguments);
backbone_marionette.MnObject.prototype.destroy.apply(this, arguments);
}

@@ -1521,12 +1641,5 @@ },

var previousToolkit = Marionette.Toolkit;
var VERSION = '5.0.0-alpha.1';
var Toolkit = Marionette.Toolkit = {};
Toolkit.noConflict = function () {
Marionette.Toolkit = previousToolkit;
return this;
};
Toolkit.MixinState = function (classDefinition) {
function MixinState(classDefinition) {
var _StateMixin = StateMixin;

@@ -1539,16 +1652,21 @@

_.extend(classDefinition.prototype, _StateMixin);
}
var marionette_toolkit = {
MixinState: MixinState,
VERSION: VERSION,
StateMixin: StateMixin,
App: App,
Component: Component
};
Toolkit.VERSION = '4.0.0';
exports.MixinState = MixinState;
exports.VERSION = VERSION;
exports.StateMixin = StateMixin;
exports.App = App;
exports.Component = Component;
exports['default'] = marionette_toolkit;
Toolkit.StateMixin = StateMixin;
Toolkit.App = App;
Toolkit.Component = Component;
return Toolkit;
}));
//# sourceMappingURL=marionette.toolkit.js.map
/**
* marionette.toolkit - A collection of opinionated Backbone.Marionette extensions for large scale application architecture.
* @version v4.0.0
* @version v5.0.0-alpha.1
* @link https://github.com/RoundingWellOS/marionette.toolkit
* @license MIT
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("underscore"),require("backbone.marionette"),require("backbone")):"function"==typeof define&&define.amd?define(["underscore","backbone.marionette","backbone"],e):(t.Marionette=t.Marionette||{},t.Marionette.Toolkit=e(t._,t.Marionette,t.Backbone))}(this,function(t,e,i){"use strict";t="default"in t?t.default:t,e="default"in e?e.default:e,i="default"in i?i.default:i;var n=["StateModel","stateEvents"],s={StateModel:i.Model,initState:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this._initState(t),this.delegateStateEvents(),this},_initState:function(t){this.mergeOptions(t,n),this._removeEventHandlers();var e=this._getStateModel(t);this._stateModel=new e(t.state),this._setEventHandlers()},delegateStateEvents:function(){return this.undelegateStateEvents(),this.bindEvents(this._stateModel,t.result(this,"stateEvents")),this},undelegateStateEvents:function(){return this.unbindEvents(this._stateModel),this},_setEventHandlers:function(){this.on("destroy",this._destroyState)},_removeEventHandlers:function(){this._stateModel&&(this.undelegateStateEvents(),this._stateModel.stopListening(),this.off("destroy",this._destroyState))},_getStateModel:function(n){if(this.StateModel.prototype instanceof i.Model||this.StateModel===i.Model)return this.StateModel;if(t.isFunction(this.StateModel))return this.StateModel.call(this,n);throw new e.Error({name:"InvalidStateModelError",message:'"StateModel" must be a model class or a function that returns a model class'})},setState:function(){return this._stateModel.set.apply(this._stateModel,arguments)},resetStateDefaults:function(){var e=t.result(this._stateModel,"defaults");return this._stateModel.set(e)},getState:function(t){return t?this._stateModel.get.apply(this._stateModel,arguments):this._stateModel},_destroyState:function(){this._stateModel.stopListening()}},r=["childApps","childAppOptions"],o={_initChildApps:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this._childApps={},this.mergeOptions(e,r);var i=this.childApps;i&&(t.isFunction(i)&&(i=i.call(this,e)),this.addChildApps(i)),this._initListeners()},_initListeners:function(){this.on({start:this._startChildApps,"before:stop":this._stopChildApps,"before:destroy":this._destroyChildApps})},_startChildApps:function(){t.each(this._childApps,function(e){t.result(e,"startWithParent")&&e.start()})},_stopChildApps:function(){t.each(this._childApps,function(e){t.result(e,"stopWithParent")&&e.stop()})},startChildApp:function(t,e){return this.getChildApp(t).start(e)},stopChildApp:function(t){return this.getChildApp(t).stop()},_destroyChildApps:function(){t.each(this._childApps,function(e){t.result(e,"preventDestroy")||e.destroy()})},_buildAppFromObject:function(e){var i=e.AppClass,n=t.omit(e,"AppClass");return this.buildApp(i,n)},_buildApp:function(e,i){return t.isFunction(e)?this.buildApp(e,i):t.isObject(e)?this._buildAppFromObject(e):void 0},buildApp:function(e,i){return i=t.extend({},this.childAppOptions,i),new e(i)},_ensureAppIsUnique:function(t){if(this._childApps[t])throw new e.Error({name:"DuplicateChildAppError",message:'A child App with name "'+t+'" has already been added.'})},addChildApps:function(e){t.each(e,t.bind(function(t,e){this.addChildApp(e,t)},this))},addChildApp:function(i,n,s){this._ensureAppIsUnique(i);var r=this._buildApp(n,s);if(!r)throw new e.Error({name:"AddChildAppError",message:"App build failed. Incorrect configuration."});return r._name=i,this._childApps[i]=r,r.on("destroy",t.partial(this._removeChildApp,i),this),this.isRunning()&&t.result(r,"startWithParent")&&r.start(),r},getName:function(){return this._name},getChildApps:function(){return t.clone(this._childApps)},getChildApp:function(t){return this._childApps[t]},_removeChildApp:function(t){delete this._childApps[t]._name,delete this._childApps[t]},removeChildApps:function(){var e=this.getChildApps();return t.each(this._childApps,t.bind(function(t,e){this.removeChildApp(e)},this)),e},removeChildApp:function(e,i){i=t.extend({},i);var n=this.getChildApp(e);if(n)return i.preventDestroy||t.result(n,"preventDestroy")?this._removeChildApp(e):n.destroy(),n}},h={_stopRunningEvents:function(){t.each(this._runningEvents,t.bind(function(t){this.off.apply(this,t)},this))},_stopRunningListeners:function(){t.each(this._runningListeningTo,t.bind(function(t){this.stopListening.apply(this,t)},this))},on:function(){return this._isRunning&&(this._runningEvents=this._runningEvents||[],this._runningEvents.push(arguments)),e.Object.prototype.on.apply(this,arguments)},listenTo:function(){return this._isRunning&&(this._runningListeningTo=this._runningListeningTo||[],this._runningListeningTo.push(arguments)),e.Object.prototype.listenTo.apply(this,arguments)},listenToOnce:function(){return this._isRunning&&(this._runningListeningTo=this._runningListeningTo||[],this._runningListeningTo.push(arguments)),e.Object.prototype.listenToOnce.apply(this,arguments)}},a={viewEventPrefix:!1,_buildEventProxies:function(){var e=t.result(this,"viewEvents")||{};this._viewEvents=this.normalizeMethods(e),this._viewTriggers=t.result(this,"viewTriggers")||{},this._viewEventPrefix=t.result(this,"viewEventPrefix")},_proxyViewEvents:function(t){this.listenTo(t,"all",this._childViewEventHandler)},_childViewEventHandler:function(e){for(var i=this._viewEvents,n=arguments.length,s=Array(n>1?n-1:0),r=1;r<n;r++)s[r-1]=arguments[r];t.isFunction(i[e])&&i[e].apply(this,s);var o=this._viewTriggers;t.isString(o[e])&&this.triggerMethod.apply(this,[o[e]].concat(s));var h=this._viewEventPrefix;if(h!==!1){var a=h+":"+e;this.triggerMethod.apply(this,[a].concat(s))}}},p=["startWithParent","stopWithParent","startAfterInitialized","preventDestroy","StateModel","stateEvents","viewEventPrefix","viewEvents","viewTriggers"],u=e.Application.extend({_isRunning:!1,preventDestroy:!1,startAfterInitialized:!1,startWithParent:!1,stopWithParent:!0,constructor:function(){var i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.mergeOptions(i,p),this.options=t.extend({},t.result(this,"options"),i),this._buildEventProxies(),this._initChildApps(i),e.Application.call(this,i),t.result(this,"startAfterInitialized")&&this.start(i)},_initRegion:function(){e.Application.prototype._initRegion.call(this),this._regionEventMonitor()},_ensureAppIsIntact:function(){if(this._isDestroyed)throw new e.Error({name:"AppDestroyedError",message:"App has already been destroyed and cannot be used."})},isRunning:function(){return this._isRunning},isRestarting:function(){return this._isRestarting},start:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this._ensureAppIsIntact(),this._isRunning?this:(t.region&&this.setRegion(t.region),t.view&&this.setView(t.view),this._initState(t),this.triggerMethod("before:start",t),this._isRunning=!0,this.delegateStateEvents(),this.triggerStart(t),this)},restart:function(){var t=this.getState().attributes;return this._isRestarting=!0,this.stop().start({state:t}),this._isRestarting=!1,this},triggerStart:function(t){this.triggerMethod("start",t)},stop:function(t){return this._isRunning?(this.triggerMethod("before:stop",t),this._isRunning=!1,this.triggerMethod("stop",t),this._stopRunningListeners(),this._stopRunningEvents(),this):this},destroy:function(){return this._isDestroyed?this:(this.stop(),delete this._view,e.Application.prototype.destroy.apply(this,arguments),this)},setRegion:function(t){return this._region&&this.stopListening(this._region),this._region=t,this._regionEventMonitor(),t},_regionEventMonitor:function(){this.listenTo(this._region,"before:show",this._onBeforeShow)},_onBeforeShow:function(t,e){this.setView(e)},getRegion:function(t){return t?this.getView().getRegion(t):this._region},setView:function(t){return this._view===t?t:(this._view&&this.stopListening(this._view),this._view=t,this._proxyViewEvents(t),t)},getView:function(){return this._view},showView:function(){for(var t,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this._view,i=arguments.length,n=Array(i>1?i-1:0),s=1;s<i;s++)n[s-1]=arguments[s];return(t=this.getRegion()).show.apply(t,[e].concat(n)),e},showChildView:function(t,e){for(var i,n=arguments.length,s=Array(n>2?n-2:0),r=2;r<n;r++)s[r-2]=arguments[r];return(i=this.getView()).showChildView.apply(i,[t,e].concat(s)),e},getChildView:function(t){return this.getView().getChildView(t)}});t.extend(u.prototype,s,o,h,a);var d=["ViewClass","viewEventPrefix","viewEvents","viewTriggers","viewOptions","region"],l=e.Object.extend({ViewClass:e.View,constructor:function(){var i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.mergeOptions(i,d),this.options=t.extend({},t.result(this,"options"),i),this._buildEventProxies(),this._initState(i),e.Object.call(this,i),this.delegateStateEvents()},_shouldDestroy:!0,showIn:function(t,e){return this.region=t,this.show(e),this},show:function(t){var i=this.getRegion();if(this._isShown)throw new e.Error({name:"ComponentShowError",message:"Component has already been shown in a region."});if(!i)throw new e.Error({name:"ComponentRegionError",message:"Component has no defined region."});return this.triggerMethod("before:show"),this.renderView(t),this._isShown=!0,this.triggerMethod("show"),this.listenTo(i,"empty",this._destroy),this},getRegion:function(){return this.region},_getViewClass:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},s=this.ViewClass;if(s.prototype instanceof i.View||s===i.View)return s;if(t.isFunction(s))return s.call(this,n);throw new e.Error({name:"InvalidViewClassError",message:'"ViewClass" must be a view class or a function that returns a view class'})},renderView:function(t){var e=this._getViewClass(t),i=this.mixinOptions(t),n=this.buildView(e,i);return this.currentView=n,this._proxyViewEvents(n),this.triggerMethod("before:render:view",n),this._shouldDestroy=!1,this.getRegion().show(n),this._shouldDestroy=!0,this.triggerMethod("render:view",n),this},mixinOptions:function(e){var i=t.result(this,"viewOptions");return t.extend({state:this.getState().attributes},i,e)},buildView:function(t,e){return new t(e)},_destroy:function(){this._shouldDestroy&&e.Object.prototype.destroy.apply(this,arguments)},_emptyRegion:function(t){var e=this.getRegion();e&&(this.stopListening(e,"empty"),e.empty(t))},destroy:function(t){return this._emptyRegion(t),this._shouldDestroy=!0,this._destroy(t),this}});t.extend(l.prototype,s,a);var c=e.Toolkit,g=e.Toolkit={};return g.noConflict=function(){return e.Toolkit=c,this},g.MixinState=function(e){var i=s;e.prototype.StateModel&&(i=t.omit(s,"StateModel")),t.extend(e.prototype,i)},g.VERSION="4.0.0",g.StateMixin=s,g.App=u,g.Component=l,g});
!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports,require("underscore"),require("backbone"),require("backbone.marionette")):"function"==typeof define&&define.amd?define(["exports","underscore","backbone","backbone.marionette"],i):i((t.Marionette=t.Marionette||{},t.Marionette.Toolkit=t.Marionette.Toolkit||{}),t._,t.Backbone,t.Marionette)}(this,function(t,i,e,n){"use strict";function s(t){var e=o;t.prototype.StateModel&&(e=i.omit(o,"StateModel")),i.extend(t.prototype,e)}i="default"in i?i.default:i,e="default"in e?e.default:e;var r=["StateModel","stateEvents"],o={StateModel:e.Model,initState:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this._initState(t),this.delegateStateEvents(),this},_initState:function(t){this.mergeOptions(t,r),this._removeEventHandlers();var i=this._getStateModel(t);this._stateModel=new i(t.state),this._setEventHandlers()},delegateStateEvents:function(){return this.undelegateStateEvents(),this.bindEvents(this._stateModel,i.result(this,"stateEvents")),this},undelegateStateEvents:function(){return this.unbindEvents(this._stateModel),this},_setEventHandlers:function(){this.on("destroy",this._destroyState)},_removeEventHandlers:function(){this._stateModel&&(this.undelegateStateEvents(),this._stateModel.stopListening(),this.off("destroy",this._destroyState))},_getStateModel:function(t){if(this.StateModel.prototype instanceof e.Model||this.StateModel===e.Model)return this.StateModel;if(i.isFunction(this.StateModel))return this.StateModel.call(this,t);throw new Error('"StateModel" must be a model class or a function that returns a model class')},setState:function(){return this._stateModel.set.apply(this._stateModel,arguments)},resetStateDefaults:function(){var t=i.result(this._stateModel,"defaults");return this._stateModel.set(t)},getState:function(t){return t?this._stateModel.get.apply(this._stateModel,arguments):this._stateModel},toggleState:function(t,i){return arguments.length>1?this._stateModel.set(t,!!i):this._stateModel.set(t,!this._stateModel.get(t))},hasState:function(t){return this._stateModel.has(t)},_destroyState:function(){this._stateModel.stopListening()}},h=["childApps","childAppOptions"],a={_initChildApps:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this._childApps={},this.mergeOptions(t,h);var e=this.childApps;e&&(i.isFunction(e)&&(e=e.call(this,t)),this.addChildApps(e))},_getChildStartOpts:function(t){var e=this,n=t._tkOpts||{},s={region:this.getRegion(n.regionName)};return i.each(n.getOptions,function(t){s[t]=e.getOption(t)}),s},_startChildApps:function(){var t=this,e=this._isRestarting?"restartWithParent":"startWithParent";i.each(this._childApps,function(n){if(i.result(n,e)){var s=t._getChildStartOpts(n);n.start(s)}})},_stopChildApps:function(){var t=this._isRestarting?"restartWithParent":"stopWithParent";i.each(this._childApps,function(e){i.result(e,t)&&e.stop()})},startChildApp:function(t,e){var n=this.getChildApp(t),s=this._getChildStartOpts(n);return n.start(i.extend(s,e))},stopChildApp:function(t,i){return this.getChildApp(t).stop(i)},_destroyChildApps:function(){i.each(this._childApps,function(t){i.result(t,"preventDestroy")||t.destroy()})},_buildAppFromObject:function(t){var e=t.AppClass,n=i.omit(t,"AppClass","regionName","getOptions"),s=this.buildApp(e,n);return s._tkOpts=i.pick(t,"regionName","getOptions"),s},_buildApp:function(t,e){return i.isFunction(t)?this.buildApp(t,e):i.isObject(t)?this._buildAppFromObject(t):void 0},buildApp:function(t,e){return e=i.extend({},this.childAppOptions,e),new t(e)},_ensureAppIsUnique:function(t){if(this._childApps[t])throw new Error('A child App with name "'+t+'" has already been added.')},addChildApps:function(t){i.each(t,i.bind(function(t,i){this.addChildApp(i,t)},this))},addChildApp:function(t,e,n){this._ensureAppIsUnique(t);var s=this._buildApp(e,n);if(!s)throw new Error("App build failed. Incorrect configuration.");return s._name=t,this._childApps[t]=s,s._on("destroy",i.partial(this._removeChildApp,t),this),this.isRunning()&&i.result(s,"startWithParent")&&s.start(),s},getName:function(){return this._name},getChildApps:function(){return i.clone(this._childApps)},getChildApp:function(t){return this._childApps[t]},_removeChildApp:function(t){delete this._childApps[t]._name,delete this._childApps[t]},removeChildApps:function(){var t=this.getChildApps();return i.each(this._childApps,i.bind(function(t,i){this.removeChildApp(i)},this)),t},removeChildApp:function(t,e){e=i.extend({},e);var n=this.getChildApp(t);if(n)return e.preventDestroy||i.result(n,"preventDestroy")?this._removeChildApp(t):n.destroy(),n}},p={_stopRunningEvents:function(){i.each(this._runningEvents,i.bind(function(t){this.off.apply(this,t)},this))},_stopRunningListeners:function(){i.each(this._runningListeningTo,i.bind(function(t){this.stopListening.apply(this,t)},this))},on:function(){return this._isRunning&&(this._runningEvents=this._runningEvents||[],this._runningEvents.push(arguments)),n.MnObject.prototype.on.apply(this,arguments)},_on:n.MnObject.prototype.on,listenTo:function(){return this._isRunning&&(this._runningListeningTo=this._runningListeningTo||[],this._runningListeningTo.push(arguments)),n.MnObject.prototype.listenTo.apply(this,arguments)},_listenTo:n.MnObject.prototype.listenTo,listenToOnce:function(){return this._isRunning&&(this._runningListeningTo=this._runningListeningTo||[],this._runningListeningTo.push(arguments)),n.MnObject.prototype.listenToOnce.apply(this,arguments)}},u={viewEventPrefix:!1,_buildEventProxies:function(){var t=i.result(this,"viewEvents")||{};this._viewEvents=this.normalizeMethods(t),this._viewTriggers=i.result(this,"viewTriggers")||{},this._viewEventPrefix=i.result(this,"viewEventPrefix")},_proxyViewEvents:function(t){this.listenTo(t,"all",this._childViewEventHandler)},_childViewEventHandler:function(t){for(var e=this._viewEvents,n=arguments.length,s=Array(n>1?n-1:0),r=1;r<n;r++)s[r-1]=arguments[r];i.isFunction(e[t])&&e[t].apply(this,s);var o=this._viewTriggers;i.isString(o[t])&&this.triggerMethod.apply(this,[o[t]].concat(s));var h=this._viewEventPrefix;if(h!==!1){var a=h+":"+t;this.triggerMethod.apply(this,[a].concat(s))}}},d=["startWithParent","restartWithParent","stopWithParent","startAfterInitialized","preventDestroy","StateModel","stateEvents","viewEventPrefix","viewEvents","viewTriggers"],l=n.Application.extend({_isRunning:!1,_isRestarting:!1,preventDestroy:!1,startAfterInitialized:!1,startWithParent:!1,stopWithParent:!0,restartWithParent:!1,constructor:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.mergeOptions(t,d),this.options=i.extend({},i.result(this,"options"),t),this._initChildApps(t),n.Application.call(this,t),i.result(this,"startAfterInitialized")&&this.start(t)},_ensureAppIsIntact:function(){if(this._isDestroyed)throw new Error("App has already been destroyed and cannot be used.")},isRunning:function(){return this._isRunning},isRestarting:function(){return this._isRestarting},start:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this._ensureAppIsIntact(),this._isRunning?this:(t.region&&this.setRegion(t.region),t.view&&this.setView(t.view),this._initState(t),this._buildEventProxies(),this.triggerMethod("before:start",t),this._isRunning=!0,this._bindRunningEvents(),this._startChildApps(),this.triggerStart(t),this)},_bindRunningEvents:function(){this._region&&this._regionEventMonitor(),this._view&&this._proxyViewEvents(this._view),this.delegateStateEvents()},restart:function(){var t=this.getState().attributes;return this._isRestarting=!0,this.stop().start({state:t}),this._isRestarting=!1,this},triggerStart:function(t){this.triggerMethod("start",t)},stop:function(t){return this._isRunning?(this.triggerMethod("before:stop",t),this._stopChildApps(),this._isRunning=!1,this.triggerMethod("stop",t),this._stopRunningListeners(),this._stopRunningEvents(),this):this},destroy:function(){return this._isDestroyed?this:(this.stop(),this._removeView(),this._destroyChildApps(),n.Application.prototype.destroy.apply(this,arguments),this)},setRegion:function(t){return this._region&&this.stopListening(this._region),this._region=t,t.currentView&&this.setView(t.currentView),this._isRunning&&this._regionEventMonitor(),t},_regionEventMonitor:function(){this.listenTo(this._region,{"before:show":this._onBeforeShow,empty:this._onEmpty})},_onBeforeShow:function(t,i){this.setView(i)},_onEmpty:function(){this._removeView()},_removeView:function(){this._view&&(this.stopListening(this._view),delete this._view)},getRegion:function(t){return t?this.getView().getRegion(t):this._region},setView:function(t){return this._view===t?t:(this._view&&this.stopListening(this._view),this._view=t,this._isRunning&&this._proxyViewEvents(t),this._listenTo(this._view,"destroy",this._removeView),t)},getView:function(){return this._view||this._region&&this._region.currentView},showView:function(){for(var t,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this._view,e=arguments.length,n=Array(e>1?e-1:0),s=1;s<e;s++)n[s-1]=arguments[s];return(t=this.getRegion()).show.apply(t,[i].concat(n)),i},showChildView:function(t,i){for(var e,n=arguments.length,s=Array(n>2?n-2:0),r=2;r<n;r++)s[r-2]=arguments[r];return(e=this.getView()).showChildView.apply(e,[t,i].concat(s)),i},getChildView:function(t){return this.getView().getChildView(t)}});i.extend(l.prototype,o,a,p,u);var g=["ViewClass","viewEventPrefix","viewEvents","viewTriggers","viewOptions","region"],c=n.MnObject.extend({ViewClass:n.View,constructor:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.mergeOptions(t,g),this.options=i.extend({},i.result(this,"options"),t),this._buildEventProxies(),this._initState(t),n.MnObject.call(this,t),this.delegateStateEvents()},_shouldDestroy:!0,showIn:function(t,i){return this.region=t,this.show(i),this},show:function(t){var i=this.getRegion();if(this._isShown)throw new Error("Component has already been shown in a region.");if(!i)throw new Error("Component has no defined region.");return this.triggerMethod("before:show"),this.renderView(t),this._isShown=!0,this.triggerMethod("show"),this.listenTo(i,"empty",this._destroy),this},getRegion:function(){return this.region},_getViewClass:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=this.ViewClass;if(n.prototype instanceof e.View||n===e.View)return n;if(i.isFunction(n))return n.call(this,t);throw new Error('"ViewClass" must be a view class or a function that returns a view class')},renderView:function(t){var i=this._getViewClass(t),e=this.mixinOptions(t),n=this.buildView(i,e);return this.currentView=n,this._proxyViewEvents(n),this.triggerMethod("before:render:view",n),this._shouldDestroy=!1,this.showView(n),this._shouldDestroy=!0,this.triggerMethod("render:view",n),this},showView:function(t){this.getRegion().show(t)},mixinOptions:function(t){var e=i.result(this,"viewOptions");return i.extend({state:this.getState().attributes},e,t)},buildView:function(t,i){return new t(i)},_destroy:function(){this._shouldDestroy&&n.MnObject.prototype.destroy.apply(this,arguments)},_emptyRegion:function(t){var i=this.getRegion();i&&(this.stopListening(i,"empty"),i.empty(t))},destroy:function(t){return this._emptyRegion(t),this._shouldDestroy=!0,this._destroy(t),this}});i.extend(c.prototype,o,u);var _="5.0.0-alpha.1",v={MixinState:s,VERSION:_,StateMixin:o,App:l,Component:c};t.MixinState=s,t.VERSION=_,t.StateMixin=o,t.App=l,t.Component=c,t.default=v});
//# sourceMappingURL=marionette.toolkit.min.js.map

@@ -16,2 +16,3 @@ # Marionette.Toolkit.App

* [App's `startWithParent`](#apps-startwithparent)
* [App's `restartWithParent`](#apps-restartwithparent)
* [App's `stopWithParent`](#apps-stopwithparent)

@@ -23,2 +24,3 @@ * [Lifecycle API](#lifecycle-api)

* [App `isRunning`](#app-isrunning)
* [App `isRestarting`](#app-isrestarting)
* [App `destroy`](#app-destroy)

@@ -129,2 +131,38 @@ * [Lifecycle Events](#lifecycle-events)

### App's `restartWithParent`
Calls `stop` then `start` on the child app when the parent app restarts. Default value is `false`.
It can also be defined as a function returning a boolean value.
```js
var myApp = new Marionette.Toolkit.App();
var persistantChildApp = myApp.addChildApp('persistantChildApp', {
AppClass: Marionette.Toolkit.App,
restartWithParent: false
});
persistantChildApp.on('stop start', function(options) {
console.log(this.isRestarting());
});
// does not log
myApp.restart();
var restartingChildApp = myApp.addChildApp('restartingChildApp', {
AppClass: Marionette.Toolkit.App,
restartWithParent: true
});
myApp.start();
restartingChildApp.on('stop start', function(options) {
console.log(this.isRestarting());
});
// logs true twice
myApp.restart();
```
### App's `stopWithParent`

@@ -131,0 +169,0 @@

@@ -24,2 +24,3 @@ # Marionette.Toolkit.Component

* [Component `currentView`](#component-currentview)
* [Component `showView`](#component-showview)
* [Component `mixinOptions`](#component-mixinoptions)

@@ -270,3 +271,3 @@ * [Component `buildView`](#component-buildview)

Builds the view from the ViewClass with the options from [`mixinOptions`](#component-mixinoptions)
and attaches it to the component's `currentView`. It then shows the `currentView` in the component's `region`.
and attaches it to the component's `currentView`. It then shows the `currentView` in the component's `region` via `showView`.
During this `region.show` the component will not destroy itself on the region's empty event.

@@ -317,2 +318,24 @@ While a component can only be shown once, it can be re-rendered many times.

### Component `showView`
Called by `renderView`, it shows the `view` in the component's `region`.
This method can be overridden to change a component's behavior.
```js
var MyComponent = Marionette.Toolkit.Component.extend({
ViewClass: MyViewClass,
region: someRegion,
showView(view) {
this.getRegion().show(view, { replaceElement: true });
}
});
var myComponent = new MyComponent();
// region el is now <div class="my-component-class">
myComponent.renderView({
className: 'my-component-class'
});
```
### Component `mixinOptions`

@@ -319,0 +342,0 @@

@@ -272,8 +272,11 @@ # ChildAppsMixin

// This is equivalent to childAppInstance.stop();
myApp.stopChildApp('cA1');
myApp.stopChildApp('cA1', { foo: 'bar' });
// false
console.log(childAppInstance.isRunning());
// bar
console.log(childAppInstance.getOption('foo'));
```
Note: The parentApp instance is returned for chaining.

@@ -17,2 +17,4 @@ # Marionette.Toolkit.StateMixin

* [Getting State `getState`](#getting-state)
* [Toggling State `toggleState`](#toggle-state)
* [Checking State `hasState`](#checking-state)
* [Binding State Events `delegateStateEvents`](#binding-events)

@@ -191,3 +193,3 @@ * [Unbinding State Events `undelegateStateEvents`](#unbinding-events)

```js
var MyToolKitApp = new Marionette.Toolkit.App({
var myToolKitApp = new Marionette.Toolkit.App({
stateEvents: {

@@ -210,10 +212,12 @@ 'change:foo': 'alert'

```js
var MyToolKitApp = new Marionette.Toolkit.App({
StateModel: {
defaults: {
'foo': 'bar'
}
}
var MyStateModel = Backbone.Model.extend({
defaults: {
foo: 'bar'
}
});
var myToolKitApp = new Marionette.Toolkit.App({
StateModel: MyStateModel
});
// This will trigger the "change:foo" event and log "alert!" to the console.

@@ -237,3 +241,3 @@ myToolKitApp.setState('foo', 'hello');

```js
var MyToolKitApp = Backbone.Model.extend({
var MyStateModel = Backbone.Model.extend({
defaults: {

@@ -255,2 +259,46 @@ foo: 'bar'

### Toggling State
`StateMixin` has a `toggleState` method that sets the `StateModel` instance attribute to a boolean value.
Attributes that do not exist on the state will be created.
Not passing in a value will toggle the attribute's current value, while non-boolean values will be coerced to `true` or `false`.
```js
var myToolKitApp = new Marionette.Toolkit.App();
myToolKitApp.setState('foo', true);
// sets "foo" attribute to false
myToolKitApp.toggleState('foo');
// coerces "bar" string into boolean, setting "foo" attribute to true
myToolKitApp.toggleState('foo', 'bar');
// sets a "baz" attribute on the state with a true value
myToolKitApp.toggleState('baz');
```
### Checking State
`StateMixin` has a `hasState` method that checks the `StateModel` instance for a specified attribute.
Passing an attribute that does not exist on the state will return `false`.
```js
var myToolKitApp = new Marionette.Toolkit.App();
// returns false
myToolKitApp.hasState('foo')
myToolKitApp.setState('foo', 'bar');
// returns true
myToolKitApp.hasState('foo');
// coerces "bar" string into boolean, setting "foo" attribute to true
myToolKitApp.setState('foo', false);
// Still returns true
myToolKitApp.hasState('foo');
```
### Binding State Events

@@ -262,3 +310,3 @@

```js
var MyToolKitApp = new Marionette.Toolkit.App({
var myToolKitApp = new Marionette.Toolkit.App({
stateEvents: {

@@ -295,3 +343,3 @@ 'change:foo': 'alert'

```js
var MyToolKitApp = new Marionette.Toolkit.App({
var myToolKitApp = new Marionette.Toolkit.App({
stateEvents: {

@@ -298,0 +346,0 @@ 'change:foo': 'alert'

{
"name": "marionette.toolkit",
"version": "4.0.0",
"version": "5.0.0-alpha.1",
"description": "A collection of opinionated Backbone.Marionette extensions for large scale application architecture.",

@@ -41,4 +41,4 @@ "main": "./dist/marionette.toolkit.js",

"babel-register": "6.7.2",
"backbone": "^1.3.3",
"backbone.marionette": "^3.0.0",
"backbone": "~1.3.3",
"backbone.marionette": "^4.0.0 || 4.0.0-alpha.1",
"chai": "2.0.0",

@@ -71,3 +71,3 @@ "del": "1.1.1",

"sinon-chai": "2.7.0",
"underscore": "^1.8.3"
"underscore": "~1.8.3"
},

@@ -79,6 +79,6 @@ "babelBoilerplateOptions": {

"peerDependencies": {
"backbone.marionette": "^3.0.0",
"backbone": "^1.3.3",
"underscore": "^1.8.3"
"backbone.marionette": "^4.0.0 || 4.0.0-alpha.1",
"backbone": "~1.3.3",
"underscore": "~1.8.3"
}
}
import _ from 'underscore';
import Marionette from 'backbone.marionette';
import { Application } from 'backbone.marionette';
import StateMixin from './mixins/state';

@@ -10,2 +10,3 @@ import ChildAppsMixin from './mixins/child-apps';

'startWithParent',
'restartWithParent',
'stopWithParent',

@@ -29,3 +30,3 @@ 'startAfterInitialized',

*/
const App = Marionette.Application.extend({
const App = Application.extend({

@@ -42,2 +43,11 @@ /**

/**
* Internal flag indiciate when `App` is in the process of stopping then starting.
*
* @private
* @type {Boolean}
* @default false
*/
_isRestarting: false,
/**
* Set to true if a parent `App` should not be able to destroy this `App`.

@@ -74,3 +84,12 @@ *

/**
* Set to true if a parent `App` should be able to restart this `App`.
*
* @type {Boolean|Function}
* @default false
*/
restartWithParent: false,
/**
* @public

@@ -80,2 +99,3 @@ * @constructs App

* @param {Boolean} [options.startWithParent]
* @param {Boolean} [options.restartWithParent]
* @param {Boolean} [options.stopWithParent]

@@ -91,9 +111,6 @@ * @param {Boolean} [options.startAfterInitialized]

// ViewEventMixin
this._buildEventProxies();
// ChildAppsMixin
this._initChildApps(options);
Marionette.Application.call(this, options);
Application.call(this, options);

@@ -106,15 +123,2 @@ if(_.result(this, 'startAfterInitialized')) {

/**
* Override of Marionette's Application._initRegion
* Allows region monitor to be setup prior to initialize
*
* @private
* @method _initRegion
* @memberOf App
*/
_initRegion() {
Marionette.Application.prototype._initRegion.call(this);
this._regionEventMonitor();
},
/**
* Internal helper to verify if `App` has been destroyed

@@ -129,6 +133,3 @@ *

if(this._isDestroyed) {
throw new Marionette.Error({
name: 'AppDestroyedError',
message: 'App has already been destroyed and cannot be used.'
});
throw new Error('App has already been destroyed and cannot be used.');
}

@@ -189,2 +190,5 @@ },

// ViewEventMixin
this._buildEventProxies();
this.triggerMethod('before:start', options);

@@ -194,5 +198,6 @@

// StateMixin
this.delegateStateEvents();
this._bindRunningEvents();
this._startChildApps();
this.triggerStart(options);

@@ -203,3 +208,23 @@

/**
* Sets up region, view, and state events.
* To only be called after `isRunning` is true
*
* @private
* @method _bindRunningEvents
* @memberOf App
*/
_bindRunningEvents() {
if(this._region) {
this._regionEventMonitor();
}
if(this._view) {
this._proxyViewEvents(this._view);
}
// StateMixin
this.delegateStateEvents();
},
/**

@@ -258,2 +283,4 @@ * Sets the app lifecycle to not running

this._stopChildApps();
this._isRunning = false;

@@ -285,6 +312,8 @@

delete this._view;
this._removeView();
Marionette.Application.prototype.destroy.apply(this, arguments);
this._destroyChildApps();
Application.prototype.destroy.apply(this, arguments);
return this;

@@ -309,4 +338,10 @@ },

this._regionEventMonitor();
if(region.currentView) {
this.setView(region.currentView);
}
if(this._isRunning) {
this._regionEventMonitor();
}
return region;

@@ -324,3 +359,6 @@ },

_regionEventMonitor() {
this.listenTo(this._region, 'before:show', this._onBeforeShow);
this.listenTo(this._region, {
'before:show': this._onBeforeShow,
'empty': this._onEmpty
});
},

@@ -340,2 +378,27 @@

/**
* Region monitor handler which empties the region's view
*
* @private
* @method _onEmpty
* @memberOf App
*/
_onEmpty() {
this._removeView();
},
/**
* Region monitor handler which deletes the region's view and listeners to view
*
* @private
* @method _removeView
* @memberOf App
*/
_removeView() {
if(this._view) {
this.stopListening(this._view);
delete this._view;
}
},
/**
* Get the Application's Region or

@@ -379,4 +442,9 @@ * Get a region from the Application's View

// ViewEventsMixin
this._proxyViewEvents(view);
if(this._isRunning) {
this._proxyViewEvents(view);
}
// Internal non-running listener
this._listenTo(this._view, 'destroy', this._removeView);
return view;

@@ -394,3 +462,3 @@ },

getView() {
return this._view;
return this._view || this._region && this._region.currentView;
},

@@ -397,0 +465,0 @@

import _ from 'underscore';
import Backbone from 'backbone';
import Marionette from 'backbone.marionette';
import { MnObject, View } from 'backbone.marionette';
import StateMixin from './mixins/state';

@@ -17,3 +17,3 @@ import ViewEventsMixin from './mixins/view-events';

/**
* Reusable Marionette.Object with View management boilerplate
* Reusable Marionette.MnObject with View management boilerplate
*

@@ -25,3 +25,3 @@ * @public

*/
const Component = Marionette.Object.extend({
const Component = MnObject.extend({

@@ -33,3 +33,3 @@ /**

*/
ViewClass: Marionette.View,
ViewClass: View,

@@ -60,3 +60,3 @@ /**

Marionette.Object.call(this, options);
MnObject.call(this, options);

@@ -112,13 +112,7 @@ // StateMixin

if(this._isShown) {
throw new Marionette.Error({
name: 'ComponentShowError',
message: 'Component has already been shown in a region.'
});
throw new Error('Component has already been shown in a region.');
}
if(!region) {
throw new Marionette.Error({
name: 'ComponentRegionError',
message: 'Component has no defined region.'
});
throw new Error('Component has no defined region.');
}

@@ -172,6 +166,3 @@

throw new Marionette.Error({
name: 'InvalidViewClassError',
message: '"ViewClass" must be a view class or a function that returns a view class'
});
throw new Error('"ViewClass" must be a view class or a function that returns a view class');
},

@@ -209,4 +200,3 @@

// Show the view in the region
this.getRegion().show(view);
this.showView(view);

@@ -221,2 +211,15 @@ this._shouldDestroy = true;

/**
* Override this to change how the component's view is shown in the region
*
* @public
* @method showView
* @memberOf Component
* @param {Object} view - view built from a viewClass and viewOptions
*/
showView(view) {
// Show the view in the region
this.getRegion().show(view);
},
/**
* Mixin initial State with any other viewOptions

@@ -263,3 +266,3 @@ *

if(this._shouldDestroy) {
Marionette.Object.prototype.destroy.apply(this, arguments);
MnObject.prototype.destroy.apply(this, arguments);
}

@@ -266,0 +269,0 @@ },

import _ from 'underscore';
import Marionette from 'backbone.marionette';

@@ -12,12 +11,5 @@ import StateMixin from './mixins/state';

const previousToolkit = Marionette.Toolkit;
const VERSION = '<%VERSION%>';
const Toolkit = Marionette.Toolkit = {};
Toolkit.noConflict = function() {
Marionette.Toolkit = previousToolkit;
return this;
};
Toolkit.MixinState = function(classDefinition) {
function MixinState(classDefinition) {
let _StateMixin = StateMixin;

@@ -30,12 +22,18 @@

_.extend(classDefinition.prototype, _StateMixin);
}
export {
MixinState,
VERSION,
StateMixin,
App,
Component
};
Toolkit.VERSION = '<%VERSION%>';
Toolkit.StateMixin = StateMixin;
Toolkit.App = App;
Toolkit.Component = Component;
export default Toolkit;
export default {
MixinState,
VERSION,
StateMixin,
App,
Component
};
import _ from 'underscore';
import Marionette from 'backbone.marionette';

@@ -50,19 +49,16 @@ const ClassOptions = [

}
this._initListeners();
},
/**
* The child apps should be handled while the app is running;
* After start, before stop, and before destroy.
*
* @private
* @method _initListeners
*/
_initListeners() {
this.on({
'start': this._startChildApps,
'before:stop': this._stopChildApps,
'before:destroy': this._destroyChildApps
_getChildStartOpts(childApp) {
const tkOpts = childApp._tkOpts || {};
const opts = {
region: this.getRegion(tkOpts.regionName)
};
_.each(tkOpts.getOptions, opt => {
opts[opt] = this.getOption(opt);
});
return opts;
},

@@ -77,6 +73,8 @@

_startChildApps() {
_.each(this._childApps, function(childApp) {
if(_.result(childApp, 'startWithParent')) {
childApp.start();
}
const shouldStartOption = this._isRestarting ? 'restartWithParent' : 'startWithParent';
_.each(this._childApps, childApp => {
if(!_.result(childApp, shouldStartOption)) return;
const opts = this._getChildStartOpts(childApp);
childApp.start(opts);
});

@@ -92,4 +90,5 @@ },

_stopChildApps() {
const shouldStopOption = this._isRestarting ? 'restartWithParent' : 'stopWithParent';
_.each(this._childApps, function(childApp) {
if(_.result(childApp, 'stopWithParent')) {
if(_.result(childApp, shouldStopOption)) {
childApp.stop();

@@ -109,3 +108,5 @@ }

startChildApp(appName, options) {
return this.getChildApp(appName).start(options);
const childApp = this.getChildApp(appName);
const opts = this._getChildStartOpts(childApp);
return childApp.start(_.extend(opts, options));
},

@@ -117,7 +118,8 @@

* @param {String} appName - Name of childApp to stop
* @param {Object} options - Stop options for app
* @public
* @method stopChildApp
*/
stopChildApp(appName) {
return this.getChildApp(appName).stop();
stopChildApp(appName, options) {
return this.getChildApp(appName).stop(options);
},

@@ -149,5 +151,9 @@

const AppClass = appConfig.AppClass;
const options = _.omit(appConfig, 'AppClass');
const options = _.omit(appConfig, 'AppClass', 'regionName', 'getOptions');
return this.buildApp(AppClass, options);
const app = this.buildApp(AppClass, options);
app._tkOpts = _.pick(appConfig, 'regionName', 'getOptions');
return app;
},

@@ -201,6 +207,3 @@

if(this._childApps[appName]) {
throw new Marionette.Error({
name: 'DuplicateChildAppError',
message: `A child App with name "${ appName }" has already been added.`
});
throw new Error(`A child App with name "${ appName }" has already been added.`);
}

@@ -241,6 +244,3 @@ },

if(!childApp) {
throw new Marionette.Error({
name: 'AddChildAppError',
message: 'App build failed. Incorrect configuration.'
});
throw new Error('App build failed. Incorrect configuration.');
}

@@ -253,3 +253,4 @@

// When the app is destroyed remove the cached app.
childApp.on('destroy', _.partial(this._removeChildApp, appName), this);
// Listener setup relative to the childApp's running state (using _on)
childApp._on('destroy', _.partial(this._removeChildApp, appName), this);

@@ -256,0 +257,0 @@ if(this.isRunning() && _.result(childApp, 'startWithParent')) {

import _ from 'underscore';
import Marionette from 'backbone.marionette';
import { MnObject } from 'backbone.marionette';

@@ -50,6 +50,15 @@ /**

return Marionette.Object.prototype.on.apply(this, arguments);
return MnObject.prototype.on.apply(this, arguments);
},
/**
* Keep a copy of non-running on for internal use
*
* @private
* @method _on
* @returns {EventListeners}
*/
_on: MnObject.prototype.on,
/**
* Overrides `Backbone.Event.listenTo()`

@@ -67,6 +76,15 @@ * If this `App` is running it will register the listener for removal `onStop`

}
return Marionette.Object.prototype.listenTo.apply(this, arguments);
return MnObject.prototype.listenTo.apply(this, arguments);
},
/**
* Keep a copy of non-running on for internal use
*
* @private
* @method _listenTo
* @returns {EventListeners}
*/
_listenTo: MnObject.prototype.listenTo,
/**
* Overrides `Backbone.Event.listenToOnce()`

@@ -85,4 +103,4 @@ * If this `App` is running it will register the listener for removal `onStop`

return Marionette.Object.prototype.listenToOnce.apply(this, arguments);
return MnObject.prototype.listenToOnce.apply(this, arguments);
}
};
import _ from 'underscore';
import Backbone from 'backbone';
import Marionette from 'backbone.marionette';

@@ -12,3 +11,3 @@ const ClassOptions = [

* This provides methods used for keeping state using a Backbone.Model. It's meant to
* be used with either a Marionette.Object or Backbone.View.
* be used with either a Marionette.MnObject or Backbone.View.
*

@@ -126,6 +125,3 @@ * @mixin

throw new Marionette.Error({
name: 'InvalidStateModelError',
message: '"StateModel" must be a model class or a function that returns a model class'
});
throw new Error('"StateModel" must be a model class or a function that returns a model class');
},

@@ -179,2 +175,29 @@

/**
* Toggle a property on the _stateModel.
*
* @public
* @method toggleState
* @param {String} attr - Attribute name of stateModel.
* @param {val} [value] - Attribute value.
* @returns {Backbone.Model} - The _stateModel or attribute value.
*/
toggleState(attr, val) {
if(arguments.length > 1) return this._stateModel.set(attr, !!val);
return this._stateModel.set(attr, !this._stateModel.get(attr));
},
/**
* Check if _stateModel has a property
*
* @public
* @method hasState
* @param {String} [attr] - Attribute name of stateModel.
* @returns {Boolean}
*/
hasState(attr) {
return this._stateModel.has(attr);
},
/**
* Clean up any listeners on the _stateModel.

@@ -181,0 +204,0 @@ *

@@ -0,8 +1,9 @@

import _ from 'underscore';
import Backbone from 'backbone';
import * as Marionette from 'backbone.marionette';
module.exports = function() {
const _ = require('underscore');
const Backbone = require('backbone');
const $ = require('jquery');
Backbone.$ = $;
const Marionette = require('backbone.marionette');
require('../../src/marionette.toolkit');
Marionette.Toolkit = require('../../src/marionette.toolkit');

@@ -9,0 +10,0 @@ // Set up test div

@@ -114,2 +114,47 @@ function createNewApp(startWParent, stopWParent, prevDestroy) {

});
describe('when restarting the application with child apps', function() {
describe('and a childApp has restartWithParent = true', function() {
it('should stop and start the specific childApp', function() {
const childApps = {
cA1: {
AppClass: Marionette.Toolkit.App,
restartWithParent: true
}
};
const myApp = new Marionette.Toolkit.App({ childApps: childApps });
myApp.start();
const stopSpy = sinon.spy(myApp.getChildApp('cA1'), 'stop');
const startSpy = sinon.spy(myApp.getChildApp('cA1'), 'start');
myApp.restart();
expect(stopSpy).to.be.called.once;
expect(startSpy).to.be.called.once;
});
});
describe('and a childApp has restartWithParent = false', function() {
it('should not stop or start the specific childApp', function() {
const childApps = {
cA1: Marionette.Toolkit.App
};
const myApp = new Marionette.Toolkit.App({ childApps: childApps });
myApp.start();
const stopSpy = sinon.spy(myApp.getChildApp('cA1'), 'stop');
const startSpy = sinon.spy(myApp.getChildApp('cA1'), 'start');
myApp.restart();
expect(stopSpy).to.not.be.called;
expect(startSpy).to.not.be.called;
});
});
});
});

@@ -114,2 +114,6 @@ import App from '../../src/app';

it('should start with _isRestarting flag set to false', function() {
expect(this.myApp.isRestarting()).to.equal(false);
});
it('should be stopped', function() {

@@ -116,0 +120,0 @@ this.myApp.restart();

@@ -93,2 +93,17 @@ import $ from 'jquery';

});
describe('when setting a region with a view', function() {
beforeEach(function() {
this.myRegion = new Marionette.Region({ el: $('<div>')[0] });
this.myRegion.show(new Marionette.View({ template: false }));
this.myApp = new this.MyApp();
this.myApp.setRegion(this.myRegion);
});
it('should set the app view to the region view', function() {
expect(this.myApp.getRegion().currentView).to.equal(this.myApp.getView());
});
});
});

@@ -210,2 +225,40 @@

});
describe('when a view is emptied in the app\'s region', function() {
it('should delete the shown view', function() {
this.myApp.setRegion(this.region);
this.myApp.showView(this.view);
this.myApp.getRegion().empty();
expect(this.myApp.getView()).to.be.undefined;
});
it('should remove any listeners to the view', function() {
this.sinon.spy(this.myApp, 'stopListening');
this.myApp.setRegion(this.region);
this.myApp.showView(this.view);
this.myApp.stopListening.reset();
this.myApp.getRegion().empty();
expect(this.myApp.stopListening).to.have.been.calledWith(this.view);
});
});
describe('when a view in the app\'s region is destroyed', function() {
it('should delete the shown view', function() {
this.myApp.setRegion(this.region);
this.myApp.showView(this.view);
this.myApp.getView().destroy();
expect(this.myApp.getView()).to.be.undefined;
});
it('should remove any listeners to the view', function() {
this.sinon.spy(this.myApp, 'stopListening');
this.myApp.setRegion(this.region);
this.myApp.showView(this.view);
this.myApp.stopListening.reset();
this.myApp.getView().destroy();
expect(this.myApp.stopListening).to.have.been.calledWith(this.view);
});
});
});

@@ -212,0 +265,0 @@

@@ -5,3 +5,3 @@ describe('Marionette.Toolkit.Component', function() {

this.el = Backbone.$('#testRegion');
this.myRegion = new Backbone.Marionette.Region({
this.myRegion = new Marionette.Region({
el: this.el

@@ -124,2 +124,10 @@ });

it('should call showView with the current view instance', function() {
this.sinon.spy(this.myComponent, 'showView');
this.myComponent.renderView();
expect(this.myComponent.showView).to.have.been.calledOnce.and.calledWith(this.myComponent.currentView);
});
describe('and checking the currentView', function() {

@@ -126,0 +134,0 @@ it('should have the correct className on currentView', function() {

@@ -223,2 +223,11 @@ describe('ChildAppMixin', function() {

});
describe('when the child startAfterInitialize', function() {
it('should remove the child if destroyed', function() {
this.myApp.addChildApp('foo', Marionette.Toolkit.App.extend({ startAfterInitialized: true }));
this.myApp.getChildApp('foo').destroy();
expect(this.myApp.getChildApp('foo')).to.be.undefined;
});
});
});

@@ -385,2 +394,11 @@

it('should stop childApp with options', function() {
const spy = sinon.spy(this.myChildApp, 'stop');
this.myApp.stopChildApp('cA1', { foo: 'bar' });
expect(spy.calledWith({ foo: 'bar' })).to.be.true;
});
it('should return parentApp instance', function() {

@@ -387,0 +405,0 @@ const spy = sinon.spy(this.myApp, 'stopChildApp');

@@ -1,2 +0,2 @@

import Marionette from 'backbone.marionette';
import * as Marionette from 'backbone.marionette';

@@ -9,3 +9,3 @@ describe('StateMixin', function() {

this.StateClass = Marionette.Object.extend();
this.StateClass = Marionette.MnObject.extend();

@@ -62,3 +62,3 @@ _.extend(this.StateClass.prototype, Marionette.Toolkit.StateMixin);

beforeEach(function() {
this.StateClass = Marionette.Object.extend();
this.StateClass = Marionette.MnObject.extend();
_.extend(this.StateClass.prototype, Marionette.Toolkit.StateMixin);

@@ -175,3 +175,3 @@ });

beforeEach(function() {
this.StateClass = Marionette.Object.extend();
this.StateClass = Marionette.MnObject.extend();
_.extend(this.StateClass.prototype, Marionette.Toolkit.StateMixin);

@@ -203,3 +203,3 @@

beforeEach(function() {
this.StateClass = Marionette.Object.extend();
this.StateClass = Marionette.MnObject.extend();
_.extend(this.StateClass.prototype, Marionette.Toolkit.StateMixin);

@@ -244,2 +244,114 @@

describe('when calling toggleState with an attribute on a statemodel', function() {
beforeEach(function() {
this.myStateClass.setState('test', true);
});
describe('with no attribute', function() {
it('should not modify the state', function() {
this.myStateClass.toggleState();
expect(this.myStateClass.getState('test')).to.be.true;
});
});
describe('with no value', function() {
it('should return the modified state', function() {
this.myStateClass.toggleState('test');
expect(this.myStateClass.getState('test')).to.be.false;
});
});
describe('with a string', function() {
it('should return the modified state', function() {
this.myStateClass.toggleState('test', 'foo');
expect(this.myStateClass.getState('test')).to.be.true;
});
});
describe('with a non-zero number', function() {
it('should return the modified state', function() {
this.myStateClass.toggleState('test', 123);
expect(this.myStateClass.getState('test')).to.be.true;
});
});
describe('with a zero value', function() {
it('should return the modified state', function() {
this.myStateClass.toggleState('test', 0);
expect(this.myStateClass.getState('test')).to.be.false;
});
});
describe('with a null value', function() {
it('should return the modified state', function() {
this.myStateClass.toggleState('test', null);
expect(this.myStateClass.getState('test')).to.be.false;
});
});
describe('with an undefined value', function() {
it('should return the modified state', function() {
this.myStateClass.toggleState('test', undefined);
expect(this.myStateClass.getState('test')).to.be.false;
});
});
});
describe('when calling toggleState without an attribute on a statemodel', function() {
describe('with no value', function() {
it('should return the modified state', function() {
this.myStateClass.toggleState('test');
expect(this.myStateClass.getState('test')).to.be.true;
});
});
describe('with a string', function() {
it('should return the modified state', function() {
this.myStateClass.toggleState('test', 'foo');
expect(this.myStateClass.getState('test')).to.be.true;
});
});
describe('with a non-zero number', function() {
it('should return the modified state', function() {
this.myStateClass.toggleState('test', 123);
expect(this.myStateClass.getState('test')).to.be.true;
});
});
describe('with a zero value', function() {
it('should return the modified state', function() {
this.myStateClass.toggleState('test', 0);
expect(this.myStateClass.getState('test')).to.be.false;
});
});
describe('with a null value', function() {
it('should return the modified state', function() {
this.myStateClass.toggleState('test', null);
expect(this.myStateClass.getState('test')).to.be.false;
});
});
describe('with an undefined value', function() {
it('should return the modified state', function() {
this.myStateClass.toggleState('test', undefined);
expect(this.myStateClass.getState('test')).to.be.false;
});
});
});
describe('when calling hasState with no attribute on a state model', function() {
it('should return false', function() {
expect(this.myStateClass.hasState('test')).to.be.false;
});
});
describe('when calling haState with an attribute on a state model', function() {
it('should return true', function() {
this.myStateClass.setState('test', 'testing');
expect(this.myStateClass.hasState('test')).to.be.true;
});
});
describe('when destroying a state object', function() {

@@ -246,0 +358,0 @@ it('should be gone', function() {

@@ -19,3 +19,3 @@ import _ from 'underscore';

describe('when initializing an app', function() {
describe('when starting an app', function() {
let myApp;

@@ -27,2 +27,3 @@

myApp = new MyApp(mergeOptions);
myApp.start();
});

@@ -69,2 +70,4 @@

myApp.start();
expect(myApp._proxyViewEvents)

@@ -154,2 +157,4 @@ .to.have.been.calledOnce.and.calledWith(myView);

myApp.setView(myView);
myApp.start();
});

@@ -190,2 +195,4 @@

myApp.setView(myView);
myApp.start();
});

@@ -192,0 +199,0 @@

@@ -1,15 +0,5 @@

describe('Marionette.Toolkit.noConflict()', function() {
describe('when calling noConflict', function() {
it('should make Marionette.Toolkit return undefined', function() {
const preNoConflict = Marionette.Toolkit.noConflict();
expect(Marionette.Toolkit).to.equal(undefined);
Marionette.Toolkit = preNoConflict;
});
});
});
describe('Marionette.Toolkit.MixinState', function() {
describe('when classDefinition has no StateModel definition', function() {
it('should use the StateModel defined on StateMixin', function() {
const MyClass = Marionette.Object.extend();
const MyClass = Marionette.MnObject.extend();
Marionette.Toolkit.MixinState(MyClass);

@@ -29,3 +19,3 @@

const MyClass = Marionette.Object.extend({
const MyClass = Marionette.MnObject.extend({
StateModel: MyModel

@@ -32,0 +22,0 @@ });

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc