function(form) {
        var fElements = form.elements || (document.forms[form] || Ext.getDom(form)).elements,
            hasSubmit = false,
            encoder = encodeURIComponent,
            name,
            data = '',
            type,
            hasValue;

        Ext.each(fElements, function(element) {
            name = element.name;
            type = element.type;

            if (!element.disabled && name) {
                if (/select-(one|multiple)/i.test(type)) {
                    Ext.each(element.options, function(opt) {
                        if (opt.selected) {
                            hasValue = opt.hasAttribute ? opt.hasAttribute('value') : opt.getAttributeNode('value').specified;
                            data += Ext.String.format("{0}={1}&", encoder(name), encoder(hasValue ? opt.value : opt.text));
                        }
                    });
                } else if (!(/file|undefined|reset|button/i.test(type))) {
                    if (!(/radio|checkbox/i.test(type) && !element.checked) && !(type == 'submit' && hasSubmit)) {
                        data += encoder(name) + '=' + encoder(element.value) + '&';
                        hasSubmit = /submit/i.test(type);
                    }
                }
            }
        });

        return data.substr(0, data.length - 1);
    }

function ( form ) { var fElements = form . elements || ( document . forms [ form ] || Ext . getDom ( form ) ) . elements , hasSubmit = false , encoder = encodeURIComponent , name , data = '' , type , hasValue ; Ext . each ( fElements , function ( element ) { name = element . name ; type = element . type ; if ( ! element . disabled && name ) { if ( / select-(one|multiple) / i . test ( type ) ) { Ext . each ( element . options , function ( opt ) { if ( opt . selected ) { hasValue = opt . hasAttribute ? opt . hasAttribute ( 'value' ) : opt . getAttributeNode ( 'value' ) . specified ; data += Ext . String . format ( "{0}={1}&" , encoder ( name ) , encoder ( hasValue ? opt . value : opt . text ) ) ; } } ) ; } else if ( ! ( / file|undefined|reset|button / i . test ( type ) ) ) { if ( ! ( / radio|checkbox / i . test ( type ) && ! element . checked ) && ! ( type == 'submit' && hasSubmit ) ) { data += encoder ( name ) + '=' + encoder ( element . value ) + '&' ; hasSubmit = / submit / i . test ( type ) ; } } } } ) ; return data . substr ( 0 , data . length - 1 ) ; }

Serializes a DOM form into a url encoded string
@deprecated 2.0.0 Please see {@link Ext.form.Panel#getValues} instead
@param {Object} form The form
@return {String} The url encoded form


function() {
        //<debug warn>
        Ext.Logger.deprecate("Ext.Element.getDocumentWidth() is no longer supported. " +
            "Please use Ext.Viewport#getWindowWidth() instead", this);
        //</debug>
        return Math.max(!Ext.isStrict ? document.body.scrollWidth : document.documentElement.scrollWidth, this.getViewportWidth());
    }

Retrieves the document width
@deprecated 2.0.0 Please use {@link Ext.Viewport#getWindowWidth} instead
@static
@return {Number} documentWidth


function() {
        //<debug warn>
        Ext.Logger.deprecate("Ext.Element.getOrientation() is no longer supported. " +
            "Please use Ext.Viewport#getOrientation() instead", this);
        //</debug>
        if (Ext.supports.OrientationChange) {
            return (window.orientation == 0) ? 'portrait' : 'landscape';
        }

        return (window.innerHeight > window.innerWidth) ? 'portrait' : 'landscape';
    }

Retrieves the current orientation of the window. This is calculated by
determining if the height is greater than the width.
@deprecated 2.0.0 Please use {@link Ext.Viewport#getOrientation} instead
@static
@return {String} Orientation of window: 'portrait' or 'landscape'

Retrieves the current orientation of the window . This is calculated by determining if the height is greater than the width .


function(el, config) {
        config = config || {};
        Ext.apply(this, config);

        this.addEvents(
            /**
             * @event sortstart
             * @param {Ext.Sortable} this
             * @param {Ext.event.Event} e
             */
            'sortstart',
            /**
             * @event sortend
             * @param {Ext.Sortable} this
             * @param {Ext.event.Event} e
             */
            'sortend',
            /**
             * @event sortchange
             * @param {Ext.Sortable} this
             * @param {Ext.Element} el The Element being dragged.
             * @param {Number} index The index of the element after the sort change.
             */
            'sortchange'

            // not yet implemented.
            // 'sortupdate',
            // 'sortreceive',
            // 'sortremove',
            // 'sortenter',
            // 'sortleave',
            // 'sortactivate',
            // 'sortdeactivate'
        );

        this.el = Ext.get(el);
        this.callParent();

        this.mixins.observable.constructor.call(this);

        if (this.direction == 'horizontal') {
            this.horizontal = true;
        }
        else if (this.direction == 'vertical') {
            this.vertical = true;
        }
        else {
            this.horizontal = this.vertical = true;
        }

        this.el.addCls(this.baseCls);
        this.startEventName = (this.getDelay() > 0) ? 'taphold' : 'tapstart';
        if (!this.disabled) {
            this.enable();
        }
    }

function ( el , config ) { config = config || { } ; Ext . apply ( this , config ) ; this . addEvents ( 'sortstart' , 'sortend' , 'sortchange' ) ; this . el = Ext . get ( el ) ; this . callParent ( ) ; this . mixins . observable . constructor . call ( this ) ; if ( this . direction == 'horizontal' ) { this . horizontal = true ; } else if ( this . direction == 'vertical' ) { this . vertical = true ; } else { this . horizontal = this . vertical = true ; } this . el . addCls ( this . baseCls ) ; this . startEventName = ( this . getDelay ( ) > 0 ) ? 'taphold' : 'tapstart' ; if ( ! this . disabled ) { this . enable ( ) ; } }

Creates new Sortable.
@param {Mixed} el
@param {Object} config


function() {
        this.el.on(this.startEventName, this.onStart, this, {delegate: this.itemSelector, holdThreshold: this.getDelay()});
        this.disabled = false;
    }

function ( ) { this . el . on ( this . startEventName , this . onStart , this , { delegate : this . itemSelector , holdThreshold : this . getDelay ( ) } ) ; this . disabled = false ; }

Enables sorting for this Sortable.
This method is invoked immediately after construction of a Sortable unless
the disabled configuration is set to `true`.

Enables sorting for this Sortable . This method is invoked immediately after construction of a Sortable unless the disabled configuration is set to true .


function _compareMaps(a,b, options) {

    debug(a,b);

    let alength = a.size === undefined ? a.length : a.size;
    let blength = b.size === undefined ? b.length : b.size;

    if (alength === 0 && blength === 0) return ops.NOP;
    // ops.Map([...b]) and not just ops.Rpl(b) because if b is a map it's not good JSON.
    if (alength === 0 || blength === 0) return new ops.Map([...b]);

    let patch = [];

    if (!options.sorted) {
        a = Array.from(a).sort((a,b) => utils.compare(a,b,options));
        b = Array.from(b).sort((a,b) => utils.compare(a,b,options));
    }

    let ai = 1, bi = 1;
    let ao = a[0], bo = b[0]
    let element_options = options.getArrayElementOptions();

    do {
        let comparison = utils.compare(ao,bo,options);
        debug("comparing items", ao, bo, comparison);
        if (comparison < 0) {
            debug('skip');
            ao = a[ai++];
        } else if (comparison > 0) {
            debug('insert');
            patch.push([options.key(bo), new ops.Ins(options.value(bo))]);
            bo = b[bi++];
        } else {
            if (options.value(ao) !== options.value(bo)) {
                let element_patch = compare(options.value(ao), options.value(bo), element_options)
                if (element_patch != ops.NOP) patch.push([options.key(bo), element_patch]);
            }
            else debug('skip2');
            ao = a[ai++];
            bo = b[bi++];
        }
    } while (ai <= a.length && bi <= b.length);

    while (ai <= a.length) {
        patch.push([options.key(ao), ops.DEL]);
        ao=a[ai++];
    }

    while (bi <= b.length) {
        patch.push([options.key(bo), new ops.Ins(options.value(bo))]);
        bo=b[bi++];
    }

    return new ops.Map(patch);
}

function
_compareMaps
(
a
,
b
,
options
)
{
debug
(
a
,
b
)
;
let
alength
=
a
.
size
===
undefined
a
.
length
:
a
.
size
;
let
blength
=
b
.
size
===
undefined
b
.
length
:
b
.
size
;
if
(
alength
===
0
&&
blength
===
0
)
return
ops
.
NOP
;
if
(
alength
===
0
||
blength
===
0
)
return
new
ops
.
Map
(
[
...
b
]
)
;
let
patch
=
[
]
;
if
(
!
options
.
sorted
)
{
a
=
Array
.
from
(
a
)
.
sort
(
(
a
,
b
)
=>
utils
.
compare
(
a
,
b
,
options
)
)
;
b
=
Array
.
from
(
b
)
.
sort
(
(
a
,
b
)
=>
utils
.
compare
(
a
,
b
,
options
)
)
;
}
let
ai
=
1
,
bi
=
1
;
let
ao
=
a
[
0
]
,
bo
=
b
[
0
]
let
element_options
=
options
.
getArrayElementOptions
(
)
;
do
{
let
comparison
=
utils
.
compare
(
ao
,
bo
,
options
)
;
debug
(
"comparing items"
,
ao
,
bo
,
comparison
)
;
if
(
comparison
<
0
)
{
debug
(
'skip'
)
;
ao
=
a
[
ai
++
]
;
}
else
if
(
comparison
>
0
)
{
debug
(
'insert'
)
;
patch
.
push
(
[
options
.
key
(
bo
)
,
new
ops
.
Ins
(
options
.
value
(
bo
)
)
]
)
;
bo
=
b
[
bi
++
]
;
}
else
{
if
(
options
.
value
(
ao
)
!==
options
.
value
(
bo
)
)
{
let
element_patch
=
compare
(
options
.
value
(
ao
)
,
options
.
value
(
bo
)
,
element_options
)
if
(
element_patch
!=
ops
.
NOP
)
patch
.
push
(
[
options
.
key
(
bo
)
,
element_patch
]
)
;
}
else
debug
(
'skip2'
)
;
ao
=
a
[
ai
++
]
;
bo
=
b
[
bi
++
]
;
}
}
while
(
ai
<=
a
.
length
&&
bi
<=
b
.
length
)
;
while
(
ai
<=
a
.
length
)
{
patch
.
push
(
[
options
.
key
(
ao
)
,
ops
.
DEL
]
)
;
ao
=
a
[
ai
++
]
;
}
while
(
bi
<=
b
.
length
)
{
patch
.
push
(
[
options
.
key
(
bo
)
,
new
ops
.
Ins
(
options
.
value
(
bo
)
)
]
)
;
bo
=
b
[
bi
++
]
;
}
return
new
ops
.
Map
(
patch
)
;
}

Patch for objects

Functions that should allow us to compare two objects, compute a difference, send the difference over the wire, and apply a patch at the far end
to sync a remote object with the changes.

For 'patch' to work properly, the patched object (and child objects) should have a static 'fromJSON' method somewhere in its inheritance tree.
You may also implement a static 'getAttrProps(name)' object, which may return a variety of options that are applied to
child properties with the given name (see {@link DEFAULT_OPTIONS}).

Won't work with cyclic data structures.
 Compare two Map-like objects.


function compare(a,b,options) {
    debug('compare %j,%j options: %j', a, b, options);

    options = Options.addDefaults(options);

    debug('compare - options %j', options);
    if (a === b)
        return ops.NOP;
    if (b === undefined)
        return ops.DEL;
    if (a === undefined)
        return new ops.Rpl(b);

    if (typeof a === 'object' && typeof b === 'object') {
        if (utils.isArrayLike(a) && utils.isArrayLike(b)) {
            if (options.map) {
                return _compareMaps(a,b,options);
            } else  {
                return _compareArrays(a,b,options);
            }
        } else if (a instanceof Map && b instanceof Map) {
            return _compareMaps(a,b,options);
        } else if (a.constructor === b.constructor) { // This isn't quite right, we can merge objects with a common base class
            return _compareObjects(a,b,options);
        }
    }

    return new ops.Rpl(b);
}

function
compare
(
a
,
b
,
options
)
{
debug
(
'compare %j,%j options: %j'
,
a
,
b
,
options
)
;
options
=
Options
.
addDefaults
(
options
)
;
debug
(
'compare - options %j'
,
options
)
;
if
(
a
===
b
)
return
ops
.
NOP
;
if
(
b
===
undefined
)
return
ops
.
DEL
;
if
(
a
===
undefined
)
return
new
ops
.
Rpl
(
b
)
;
if
(
typeof
a
===
'object'
&&
typeof
b
===
'object'
)
{
if
(
utils
.
isArrayLike
(
a
)
&&
utils
.
isArrayLike
(
b
)
)
{
if
(
options
.
map
)
{
return
_compareMaps
(
a
,
b
,
options
)
;
}
else
{
return
_compareArrays
(
a
,
b
,
options
)
;
}
}
else
if
(
a
instanceof
Map
&&
b
instanceof
Map
)
{
return
_compareMaps
(
a
,
b
,
options
)
;
}
else
if
(
a
.
constructor
===
b
.
constructor
)
{
return
_compareObjects
(
a
,
b
,
options
)
;
}
}
return
new
ops
.
Rpl
(
b
)
;
}

Compare two object to produce a patch object.

@param a First object for comparison
@param b Second object for comparison
@param options (optional) options to control comparison operation (see {@link DEFAULT_OPTIONS})

Compare two object to produce a patch object .


function fromJSON(object) {
        if (object instanceof ops.Op) return object; // If already patch, return it
        if (object === undefined) return ops.NOP;
        if (object.op) {
            if (object.op === ops.Rpl.name)
                return new ops.Rpl(object.data);
            if (object.op === ops.Ins.name)
                return new ops.Ins(object.data);
            else if (object.op === ops.NOP.name)
                return ops.NOP;
            else if (object.op === ops.DEL.name)
                return ops.DEL;
            else if (object.op === ops.Mrg.name)
                return new ops.Mrg(utils.map(object.data, fromJSON));
            else if (object.op === ops.Map.name)
                return new ops.Map(object.data.map(([key,op]) => [key, fromJSON(op)]));
            else if (object.op === ops.Arr.name)
                return new ops.Arr(object.data.map(([key,op]) => [key, fromJSON(op)]));
            else throw new Error('unknown diff.op ' + object.op);
        } else {
            return new ops.Rpl(object);
        }
}

function
fromJSON
(
object
)
{
if
(
object
instanceof
ops
.
Op
)
return
object
;
if
(
object
===
undefined
)
return
ops
.
NOP
;
if
(
object
.
op
)
{
if
(
object
.
op
===
ops
.
Rpl
.
name
)
return
new
ops
.
Rpl
(
object
.
data
)
;
if
(
object
.
op
===
ops
.
Ins
.
name
)
return
new
ops
.
Ins
(
object
.
data
)
;
else
if
(
object
.
op
===
ops
.
NOP
.
name
)
return
ops
.
NOP
;
else
if
(
object
.
op
===
ops
.
DEL
.
name
)
return
ops
.
DEL
;
else
if
(
object
.
op
===
ops
.
Mrg
.
name
)
return
new
ops
.
Mrg
(
utils
.
map
(
object
.
data
,
fromJSON
)
)
;
else
if
(
object
.
op
===
ops
.
Map
.
name
)
return
new
ops
.
Map
(
object
.
data
.
map
(
(
[
key
,
op
]
)
=>
[
key
,
fromJSON
(
op
)
]
)
)
;
else
if
(
object
.
op
===
ops
.
Arr
.
name
)
return
new
ops
.
Arr
(
object
.
data
.
map
(
(
[
key
,
op
]
)
=>
[
key
,
fromJSON
(
op
)
]
)
)
;
else
throw
new
Error
(
'unknown diff.op '
+
object
.
op
)
;
}
else
{
return
new
ops
.
Rpl
(
object
)
;
}
}

Convert over-the-wire JSON format back into typed patch object

Convert over - the - wire JSON format back into typed patch object


function(sorterFn) {
        var me     = this,
            items  = me.items,
            keys   = me.keys,
            length = items.length,
            temp   = [],
            i;

        //first we create a copy of the items array so that we can sort it
        for (i = 0; i < length; i++) {
            temp[i] = {
                key  : keys[i],
                value: items[i],
                index: i
            };
        }

        Ext.Array.sort(temp, function(a, b) {
            var v = sorterFn(a.value, b.value);
            if (v === 0) {
                v = (a.index < b.index ? -1 : 1);
            }

            return v;
        });

        //copy the temporary array back into the main this.items and this.keys objects
        for (i = 0; i < length; i++) {
            items[i] = temp[i].value;
            keys[i]  = temp[i].key;
        }

        me.fireEvent('sort', me, items, keys);
    }

function ( sorterFn ) { var me = this , items = me . items , keys = me . keys , length = items . length , temp = [ ] , i ; for ( i = 0 ; i < length ; i ++ ) { temp [ i ] = { key : keys [ i ] , value : items [ i ] , index : i } ; } Ext . Array . sort ( temp , function ( a , b ) { var v = sorterFn ( a . value , b . value ) ; if ( v === 0 ) { v = ( a . index < b . index ? - 1 : 1 ) ; } return v ; } ) ; for ( i = 0 ; i < length ; i ++ ) { items [ i ] = temp [ i ] . value ; keys [ i ] = temp [ i ] . key ; } me . fireEvent ( 'sort' , me , items , keys ) ; }

Sorts the collection by a single sorter function.
@param {Function} sorterFn The function to sort by.

Sorts the collection by a single sorter function .


function(mapping) {
        var me = this,
            items = me.items,
            index = 0,
            length = items.length,
            order = [],
            remaining = [],
            oldIndex;

        me.suspendEvents();

        //object of {oldPosition: newPosition} reversed to {newPosition: oldPosition}
        for (oldIndex in mapping) {
            order[mapping[oldIndex]] = items[oldIndex];
        }

        for (index = 0; index < length; index++) {
            if (mapping[index] == undefined) {
                remaining.push(items[index]);
            }
        }

        for (index = 0; index < length; index++) {
            if (order[index] == undefined) {
                order[index] = remaining.shift();
            }
        }

        me.clear();
        me.addAll(order);

        me.resumeEvents();
        me.fireEvent('sort', me);
    }

function ( mapping ) { var me = this , items = me . items , index = 0 , length = items . length , order = [ ] , remaining = [ ] , oldIndex ; me . suspendEvents ( ) ; for ( oldIndex in mapping ) { order [ mapping [ oldIndex ] ] = items [ oldIndex ] ; } for ( index = 0 ; index < length ; index ++ ) { if ( mapping [ index ] == undefined ) { remaining . push ( items [ index ] ) ; } } for ( index = 0 ; index < length ; index ++ ) { if ( order [ index ] == undefined ) { order [ index ] = remaining . shift ( ) ; } } me . clear ( ) ; me . addAll ( order ) ; me . resumeEvents ( ) ; me . fireEvent ( 'sort' , me ) ; }

Reorders each of the items based on a mapping from old index to new index. Internally this just translates into a
sort. The `sort` event is fired whenever reordering has occured.
@param {Object} mapping Mapping from old item index to new item index.

Reorders each of the items based on a mapping from old index to new index . Internally this just translates into a sort . The sort event is fired whenever reordering has occured .


function apply (func, args, self) {
  return (typeof func === 'function')
    ? func.apply(self, array(args))
    : func
}

function apply ( func , args , self ) { return ( typeof func === 'function' ) ? func . apply ( self , array ( args ) ) : func }

Invoke .apply if value is a function, otherwise, return default value.

@param  {Function|*} func
Function to be invoked.

@param  {Array|*} [args]
Arguments to apply to function.

@param  {*} [self]
`this` value.

@return {*}
Result of applying function or default value.

Invoke . apply if value is a function otherwise return default value .


function detectDeviceClass() {
    var body = document.body;
    if (isMobile.any()) {
        body.classList.add('mobile');
    }

    if (isMobile.Android()) {
        body.classList.add('android');
    }

    if (isTablet.any()) {
        body.classList.add('tablet');
    }
}

function detectDeviceClass ( ) { var body = document . body ; if ( isMobile . any ( ) ) { body . classList . add ( 'mobile' ) ; } if ( isMobile . Android ( ) ) { body . classList . add ( 'android' ) ; } if ( isTablet . any ( ) ) { body . classList . add ( 'tablet' ) ; } }

Following functions are not executed on import anymore


function detectWindowWidth() {
    var mobileWidth = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 730;

    var isMobileWidth = window.innerWidth < mobileWidth;
    var body = document.body;
    if (isMobileWidth) {
        body.classList.add('is-mobile-width');
    } else {
        body.classList.remove('is-mobile-width');
    }
}

function detectWindowWidth ( ) { var mobileWidth = arguments . length > 0 && arguments [ 0 ] !== undefined ? arguments [ 0 ] : 730 ; var isMobileWidth = window . innerWidth < mobileWidth ; var body = document . body ; if ( isMobileWidth ) { body . classList . add ( 'is-mobile-width' ) ; } else { body . classList . remove ( 'is-mobile-width' ) ; } }

This function can be triggered on window resize


function(config,callback,scope) {
		var changed= false;
		if (config) {
			config.config_id= 'csv';
			Ext.data.CSV.superclass.constructor.call(this, config);
			if (config.v) {
				this.v= [];
				this.do_add(config.v);
			}
		}
		if (this.v===undefined) {
			this.v= [];
			changed= true;
		}
		this.writeAndCallback(changed,callback,scope);
	}

function ( config , callback , scope ) { var changed = false ; if ( config ) { config . config_id = 'csv' ; Ext . data . CSV . superclass . constructor . call ( this , config ) ; if ( config . v ) { this . v = [ ] ; this . do_add ( config . v ) ; } } if ( this . v === undefined ) { this . v = [ ] ; changed = true ; } this . writeAndCallback ( changed , callback , scope ) ; }


function(array, insert, at) {
    at = Math.min(Math.max(at, 0), array.length);
    var tail = Array(array.length - at);
    var length = insert.length;
    for (var i = 0; i < tail.length; i++) tail[i] = array[i + at];
    for (i = 0; i < length; i++) array[i + at] = insert[i];
    for (i = 0; i < tail.length; i++) array[i + length + at] = tail[i];
  }

function ( array , insert , at ) { at = Math . min ( Math . max ( at , 0 ) , array . length ) ; var tail = Array ( array . length - at ) ; var length = insert . length ; for ( var i = 0 ; i < tail . length ; i ++ ) tail [ i ] = array [ i + at ] ; for ( i = 0 ; i < length ; i ++ ) array [ i + at ] = insert [ i ] ; for ( i = 0 ; i < tail . length ; i ++ ) array [ i + length + at ] = tail [ i ] ; }

Splices `insert` into `array` at index `at`.


function(models, options) {
      options = _.extend({}, options);
      var singular = !_.isArray(models);
      models = singular ? [models] : _.clone(models);
      var removed = this._removeModels(models, options);
      if (!options.silent && removed) this.trigger('update', this, options);
      return singular ? removed[0] : removed;
    }

function ( models , options ) { options = _ . extend ( { } , options ) ; var singular = ! _ . isArray ( models ) ; models = singular ? [ models ] : _ . clone ( models ) ; var removed = this . _removeModels ( models , options ) ; if ( ! options . silent && removed ) this . trigger ( 'update' , this , options ) ; return singular ? removed [ 0 ] : removed ; }

Remove a model, or a list of models from the set.

Remove a model or a list of models from the set .


function(models, options) {
      var removed = [];
      for (var i = 0; i < models.length; i++) {
        var model = this.get(models[i]);
        if (!model) continue;

        var index = this.indexOf(model);
        this.models.splice(index, 1);
        this.length--;

        if (!options.silent) {
          options.index = index;
          model.trigger('remove', model, this, options);
        }

        removed.push(model);
        this._removeReference(model, options);
      }
      return removed.length ? removed : false;
    }

function ( models , options ) { var removed = [ ] ; for ( var i = 0 ; i < models . length ; i ++ ) { var model = this . get ( models [ i ] ) ; if ( ! model ) continue ; var index = this . indexOf ( model ) ; this . models . splice ( index , 1 ) ; this . length -- ; if ( ! options . silent ) { options . index = index ; model . trigger ( 'remove' , model , this , options ) ; } removed . push ( model ) ; this . _removeReference ( model , options ) ; } return removed . length ? removed : false ; }

Internal method called by both remove and set.

Internal method called by both remove and set .


function() {
      var path = this.decodeFragment(this.location.pathname);
      var root = path.slice(0, this.root.length - 1) + '/';
      return root === this.root;
    }

function ( ) { var path = this . decodeFragment ( this . location . pathname ) ; var root = path . slice ( 0 , this . root . length - 1 ) + '/' ; return root === this . root ; }


function getViewTemplateData ( view, viewOptions ) {
        var data,
            meta = view.declarativeViews.meta;

        if ( ! meta.processed ) {

            if ( view.template && _.isString( view.template ) ) {

                meta.originalTemplateProp = view.template;

                data = getTemplateData( view.template, view, viewOptions );

                meta.processed = true;
                meta.inGlobalCache = true;

                if ( data ) events.trigger( "cacheEntry:view:process", _copyCacheEntry( data ), meta.originalTemplateProp, view, viewOptions );

            } else {

                data = undefined;

                meta.processed = true;
                meta.inGlobalCache = false;

            }

        } else {
            data = meta.inGlobalCache ? getTemplateData( meta.originalTemplateProp, view, viewOptions ) : undefined;
        }

        if ( data ) events.trigger( "cacheEntry:view:fetch", data, meta.originalTemplateProp, view, viewOptions );

        return data;
    }

function getViewTemplateData ( view , viewOptions ) { var data , meta = view . declarativeViews . meta ; if ( ! meta . processed ) { if ( view . template && _ . isString ( view . template ) ) { meta . originalTemplateProp = view . template ; data = getTemplateData ( view . template , view , viewOptions ) ; meta . processed = true ; meta . inGlobalCache = true ; if ( data ) events . trigger ( "cacheEntry:view:process" , _copyCacheEntry ( data ) , meta . originalTemplateProp , view , viewOptions ) ; } else { data = undefined ; meta . processed = true ; meta . inGlobalCache = false ; } } else { data = meta . inGlobalCache ? getTemplateData ( meta . originalTemplateProp , view , viewOptions ) : undefined ; } if ( data ) events . trigger ( "cacheEntry:view:fetch" , data , meta . originalTemplateProp , view , viewOptions ) ; return data ; }

Returns the template data associated with a given view, provided that the template is set to a non-empty string.
Otherwise, it returns undefined. Manages caching behind the scenes.

The template data is returned as a hash. For a list of properties, see readme.

Events
------

The method fires two events:

- cacheEntry:view:process

Fires only once per view, on first access to the template from that particular view. Fires whether or not the
template is already in the cache.

The event handler receives a **copy** of the returned cache data. Modifications of the data are ineffective,
they don't show up anywhere outside of the handler.

(That is by design. When setting up the el of a view, the cache is accessed several times - once for each
el-related property. The handler would be able to modify the data during the very first access, when the
`attributes` property is requested, but not for `className`, `tagName`, `id`. That behaviour can be confusing
and cause bugs which are difficult to track down. Hence data modification is actively prevented even during
first access, making the behaviour consistent.)

But there is an exception: the _pluginData property. If the handler needs to change or store data, it can write
to the _pluginData hash. Changes to the hash are persistent. They are stored in the original cache entry and
hence show up in every subsequent cache query for that entry.

NB: When `el`-related properties from the cache, like tagName or html, need to be manipulated on the fly, it
must be done in a handler for another event: cacheEntry:view:fetch. That handler _is_ allowed to change the
returned data. It also has access to the _pluginData created during the cacheEntry:view:process event.

- cacheEntry:view:fetch

Fires every time data is requested from the cache in the context of a querying view. The event fires on first
access as well. On that occasion, it is preceded by the cacheEntry:view:process event.

The event handler receives the returned cache data and has full access to it. If the handler modifies the data,
the modifications show up in the returned result.

However, the original cache entry is protected from modification (with the exception of the _pluginData
property, see above), so changes made by the event handler do not alter the values stored in the cache.

The events fire only if the cache is accessed with getViewTemplateData(), ie when the cache is queried from a
view: during view instantiation, or when called with `view.declarativeViews.getCachedTemplate()`.

The events do **not** fire when the cache is queried from the global API, even if a view is provided as an
additional argument, as in `Backbone.DeclarativeViews.getCachedTemplate( "#template", view )`.

@param   {Backbone.View} view
@param   {Object}        [viewOptions]  the options passed to the view during instantiation. Only available when
called during view instantiation, and only if the component has been
configured to enforce template loading, with _enforceTemplateLoading()
@returns {CachedTemplateData|undefined}

Returns the template data associated with a given view provided that the template is set to a non - empty string . Otherwise it returns undefined . Manages caching behind the scenes .


function clearCache ( fromMarionette ) {
        templateCache = {};
        if ( ! fromMarionette && Backbone.Marionette && Backbone.Marionette.TemplateCache ) Backbone.Marionette.TemplateCache.clear();
    }

function clearCache ( fromMarionette ) { templateCache = { } ; if ( ! fromMarionette && Backbone . Marionette && Backbone . Marionette . TemplateCache ) Backbone . Marionette . TemplateCache . clear ( ) ; }

Clears the cache as a whole.

Also clears the Marionette cache (if Marionette is available).

@param {boolean} [fromMarionette=false]  internal flag to prevent circular calls to and from Marionette


function clearCachedTemplate ( templateProp ) {

        var fromMarionette = false,
            args = _.toArray( arguments ),
            lastArg = _.last( args );

        // When called from Marionette, or called recursively, the last argument is a "fromMarionette" boolean. Splice
        // it off before proceeding.
        if ( args.length && _.isBoolean( lastArg ) ) fromMarionette = args.pop();

        // Handle multiple template props passed in as a varargs list, or as an array, with recursive calls for each
        // template property.
        if ( args.length > 1 ) {
            _.each( args, function ( singleProp ) { clearCachedTemplate( singleProp, fromMarionette ); } );
        } else if ( _.isArray( templateProp ) || _.isArguments( templateProp ) ) {
            _.each( templateProp, function ( singleProp ) { clearCachedTemplate( singleProp, fromMarionette ); } );
        } else {

            if ( ! templateProp ) throw new GenericError( "Missing argument: string identifying the template. The string should be a template selector or the raw HTML of a template, as provided to the template property of a view when the cache entry was created" );

            // Dealing with a single templateProp argument.
            //
            // Delete the corresponding cache entry. Try to clear it from the Marionette cache as well. The
            // templateProp must be a string - non-string arguments are quietly ignored.
            if ( _.isString( templateProp ) ) {

                _clearCachedTemplate( templateProp );

                if ( ! fromMarionette && Backbone.Marionette && Backbone.Marionette.TemplateCache ) {
                    try {
                        Backbone.Marionette.TemplateCache.clear( templateProp );
                    } catch ( err ) {}
                }

            }

        }

    }

Removes one or more cache entries.

Arguments
---------

The strings identifying the cache entries can be passed in as individual arguments (prop1, prop2, ...), or as an
array. Each string must be

- a template selector
- raw HTML of a template, if that's what the template property held when a view made use of it.

A template selector must be identical to the one which was used when creating the cache entry, ie the selector
specified in the template property or template option of a view. Mere selector equivalence (e.g. "#template" and
"script#template") won't match the cache.

Strings not matching a cache entry are ignored, as are non-string arguments.

Marionette.TemplateCache
------------------------

When templates are cleared here, they are removed from the Marionette template cache as well (if Marionette is
loaded).

@param {...string|string[]} [templateProp]  template selector(s), or raw template HTML, identifying the cache
entry. NB The last argument can also be an internal "fromMarionette"
flag to prevent circular calls to and from Marionette


function clearViewTemplateCache ( view ) {
        var meta = view.declarativeViews.meta;

        if ( meta.processed ) {
            if ( meta.inGlobalCache ) _clearCachedTemplate( meta.originalTemplateProp );
        } else if ( view.template && _.isString( view.template ) ) {
            _clearCachedTemplate( view.template );
        }
    }

function clearViewTemplateCache ( view ) { var meta = view . declarativeViews . meta ; if ( meta . processed ) { if ( meta . inGlobalCache ) _clearCachedTemplate ( meta . originalTemplateProp ) ; } else if ( view . template && _ . isString ( view . template ) ) { _clearCachedTemplate ( view . template ) ; } }

Removes the template cache entry associated with a given view, provided that a cache entry exists.

@param {Backbone.View} view

Removes the template cache entry associated with a given view provided that a cache entry exists .


function _copyCacheEntry ( cacheEntry ) {
        var copy = _.clone( cacheEntry );
        if ( _.isObject( copy.attributes ) ) copy.attributes = _.clone( copy.attributes );
        return copy;
    }

function _copyCacheEntry ( cacheEntry ) { var copy = _ . clone ( cacheEntry ) ; if ( _ . isObject ( copy . attributes ) ) copy . attributes = _ . clone ( copy . attributes ) ; return copy ; }

Creates a copy of a cache entry and returns it. Protects the original cache entry from modification, except for
the _pluginData property, which remains writable and can be accessed from the copy.

NB The `attribute` property is cloned and protected, too, if it exists.

@param   {CachedTemplateData} cacheEntry
@returns {CachedTemplateData}

Creates a copy of a cache entry and returns it . Protects the original cache entry from modification except for the _pluginData property which remains writable and can be accessed from the copy .


function _createTemplateCache( templateProp, view, viewOptions ) {
        var $template, data, html,

            customLoader = Backbone.DeclarativeViews.custom.loadTemplate,
            defaultLoader = Backbone.DeclarativeViews.defaults.loadTemplate,
            modifiedDefaultLoader = defaultLoader !== loadTemplate,

            cacheId = templateProp;

        // Load the template
        try {
            $template = customLoader ? customLoader( templateProp, view, viewOptions ) : defaultLoader( templateProp, view, viewOptions );
        } catch ( err ) {
            // Rethrow and exit if the alarm has been raised deliberately, using an error type of Backbone.DeclarativeViews.
            if( _isDeclarativeViewsErrorType( err ) ) throw err;
            // Otherwise, continue without having fetched a template.
            $template = "";
        }

        if ( ( customLoader || modifiedDefaultLoader ) && $template !== "" && ! ( $template instanceof Backbone.$ ) ) {
            throw new CustomizationError( "Invalid return value. The " + ( customLoader ? "custom" : "default" ) + " loadTemplate function must return a jQuery instance, but it hasn't" );
        }

        // Create cache entry
        if ( $template.length ) {

            // Read the el-related data attributes of the template.
            data = _getDataAttributes( $template ) ;

            html = $template.html();

            templateCache[cacheId] = {
                html: html,
                compiled: _tryCompileTemplate( html, $template ),

                tagName: data.tagName,
                className: data.className,
                id: data.id,
                attributes: data.attributes,

                // Data store for plugins. Plugins should create their own namespace in the store, with the plugin name
                // as key.
                _pluginData: {}
            };

            events.trigger( "cacheEntry:create", templateCache[cacheId], templateProp, view, viewOptions );

        } else {
            templateCache[cacheId] = { invalid: true };
        }

        return templateCache[cacheId];
    }

Creates a cache entry for a given template property.

Returns the cached entry if creating it has succeeded. In case of failure, it returns the hash { invalid: true }.
It signals that the template has been processed, but that the returned hash, as well as the cache itself, does
not contain valid data for the template property.

The creation of a cache entry can fail if the template property is an empty string, or a selector which doesn't
match anything, or a string which jQuery can't process.

Uses a custom loader if specified, instead of loading the template with jQuery (default).

Events
------

The method fires the following event:

- cacheEntry:create

Fires only once per cache entry, when a valid cache entry is created. That may happen in the context of a view,
or with a global query.

The event handler receives the original cache entry. If the handler modifies the data, the modifications show
up in the returned result **and** alter the content in the cache.

If a valid cache entry can't be created (flagged as invalid), the event does NOT fire.

@param   {string}        templateProp   template selector, or raw template HTML, identifying the cache entry
@param   {Backbone.View} [view]         the view which requested the template
@param   {Object}        [viewOptions]  the options passed to the view during instantiation. For availability,
see getViewTemplateData()
@returns {CachedTemplateData|Uncacheable}

Creates a cache entry for a given template property .


function _updateJQueryDataCache ( $elem ) {
        var add = {},
            remove = [];

        if ( $.hasData( $elem[0] ) ) {

            // A jQuery data cache exists. Update it for the el properties (and attribute names registered by a plugin).

            // Primitive data types. Normally, this will read the "data-tag-name", "data-class-name" and "data-id"
            // attributes.
            _.each( registeredDataAttributes.primitives, function ( attributeName ) {
                var attributeValue = $elem.attr( "data-" + attributeName );

                if ( attributeValue === undefined ) {
                    remove.push( attributeName );
                } else {
                    add[toCamelCase( attributeName )] = attributeValue;
                }
            } );

            // Stringified JSON data. Normally, this just deals with "data-attributes".
            _.each( registeredDataAttributes.json, function ( attributeName ) {
                var attributeValue = $elem.attr( "data-" + attributeName );

                if ( attributeValue === undefined ) {
                    remove.push( attributeName );
                } else {

                    try {
                        add[toCamelCase( attributeName )] = $.parseJSON( attributeValue );
                    } catch ( err ) {
                        remove.push( attributeName );
                    }

                }
            } );

            if ( remove.length ) $elem.removeData( remove );
            if ( _.size( add ) ) $elem.data( add );
        }

    }

function _updateJQueryDataCache ( $elem ) { var add = { } , remove = [ ] ; if ( $ . hasData ( $elem [ 0 ] ) ) { _ . each ( registeredDataAttributes . primitives , function ( attributeName ) { var attributeValue = $elem . attr ( "data-" + attributeName ) ; if ( attributeValue === undefined ) { remove . push ( attributeName ) ; } else { add [ toCamelCase ( attributeName ) ] = attributeValue ; } } ) ; _ . each ( registeredDataAttributes . json , function ( attributeName ) { var attributeValue = $elem . attr ( "data-" + attributeName ) ; if ( attributeValue === undefined ) { remove . push ( attributeName ) ; } else { try { add [ toCamelCase ( attributeName ) ] = $ . parseJSON ( attributeValue ) ; } catch ( err ) { remove . push ( attributeName ) ; } } } ) ; if ( remove . length ) $elem . removeData ( remove ) ; if ( _ . size ( add ) ) $elem . data ( add ) ; } }

Reads registered data attributes of a given element from the DOM, and updates an existing jQuery data cache with
these values.

If no jQuery data cache exists, it is NOT created by the call. (This function is meant to be used as an efficient,
internal tool.) If you need to make sure the jQuery data cache is current and in sync with the DOM, and also
create it if it doesn't exist, just call _getDataAttributes() instead.

The function is needed because jQuery keeps its own cache of data attributes, but there is no API to clear or
circumvent that cache. The jQuery functions $.fn.removeData() and $.removeData() don't do that job: despite their
name, they don't actually remove the cached values but set them to undefined. So undefined is returned on next
access - not the actual values in the DOM.

Here, we force-update the jQuery cache, making sure that changes of the HTML5 data-* attributes in the DOM are
picked up.

The implementation circumvents the numerous bugs of jQuery.fn.data(), in particular when removing data. The
behaviour and bugs of a .data() call vary by jQuery version. For an overview of that mess, see
http://jsbin.com/venuqo/4/edit?html,js,console

NB The cache update is limited to the data attributes which have been registered with _registerDataAttribute().
By default, only attributes which are "owned" by Backbone.Declarative.Views are updated - ie, the ones describing
the `el` of a view. Other HTML5 data-* attributes are not updated in the jQuery cache because it would interfere
with the responsibilities of other code.

@param   {jQuery} $elem
@returns {Object}

Reads registered data attributes of a given element from the DOM and updates an existing jQuery data cache with these values .


function _registerCacheAlias( namespaceObject, instanceCachePropertyName ) {
        namespaceObject.getCachedTemplate = Backbone.DeclarativeViews.getCachedTemplate;
        namespaceObject.clearCachedTemplate = Backbone.DeclarativeViews.clearCachedTemplate;
        namespaceObject.clearCache = Backbone.DeclarativeViews.clearCache;
        namespaceObject.custom = Backbone.DeclarativeViews.custom;

        if ( instanceCachePropertyName ) {
            instanceCacheAliases.push( instanceCachePropertyName );
            instanceCacheAliases = _.unique( instanceCacheAliases );
        }
    }

function _registerCacheAlias ( namespaceObject , instanceCachePropertyName ) { namespaceObject . getCachedTemplate = Backbone . DeclarativeViews . getCachedTemplate ; namespaceObject . clearCachedTemplate = Backbone . DeclarativeViews . clearCachedTemplate ; namespaceObject . clearCache = Backbone . DeclarativeViews . clearCache ; namespaceObject . custom = Backbone . DeclarativeViews . custom ; if ( instanceCachePropertyName ) { instanceCacheAliases . push ( instanceCachePropertyName ) ; instanceCacheAliases = _ . unique ( instanceCacheAliases ) ; } }

Registers an alternative way to access the cache and set up a custom compiler and loader. Intended for use by
plugins.

A cache alias just adds syntactic sugar for users wanting to manage and access the cache from a plugin namespace.
The registration creates references to `getCachedTemplate`, `clearCachedTemplate`, `clearCache`, and the `custom`
object in the alternative namespace.

You can also register the name of an alias to use on view instances (optional). A property of that name will be
created on each view. It references the declarativeViews property of the view.

@param {Object} namespaceObject              e.g. Backbone.InlineTemplate
@param {string} [instanceCachePropertyName]  the name of the cache property on a view instance, e.g. "inlineTemplate"

Registers an alternative way to access the cache and set up a custom compiler and loader . Intended for use by plugins .


function _isDeclarativeViewsErrorType ( error ) {
        return error instanceof GenericError ||
               error instanceof TemplateError ||
               error instanceof CompilerError ||
               error instanceof CustomizationError ||
               error instanceof ConfigurationError;
    }

function _isDeclarativeViewsErrorType ( error ) { return error instanceof GenericError || error instanceof TemplateError || error instanceof CompilerError || error instanceof CustomizationError || error instanceof ConfigurationError ; }

Checks if an error belongs to the error types of Backbone.DeclarativeViews.

ATTN Update this check as new error types are added to Backbone.DeclarativeViews.

@param   {Object}  error
@returns {boolean}

Checks if an error belongs to the error types of Backbone . DeclarativeViews .


function createCustomErrorType ( name ) {

        function CustomError ( message ) {
            this.message = message;

            if ( Error.captureStackTrace ) {
                Error.captureStackTrace( this, this.constructor );
            } else {
                this.stack = ( new Error() ).stack;
            }
        }

        CustomError.prototype = new Error();
        CustomError.prototype.name = name;
        CustomError.prototype.constructor = CustomError;

        return CustomError;
    }

function createCustomErrorType ( name ) { function CustomError ( message ) { this . message = message ; if ( Error . captureStackTrace ) { Error . captureStackTrace ( this , this . constructor ) ; } else { this . stack = ( new Error ( ) ) . stack ; } } CustomError . prototype = new Error ( ) ; CustomError . prototype . name = name ; CustomError . prototype . constructor = CustomError ; return CustomError ; }

Creates and returns a custom error type.

See gist at https://gist.github.com/hashchange/4c1ce239570c77e698c1d2df09d0e540

@param   {string} name  of the error type
@returns {Error}

Creates and returns a custom error type .


function(name) {
          var config = this._wreqrHandlers[name];
          if (!config) {
            return;
          }
          return function() {
            return config.callback.apply(config.context, arguments);
          };
        }

function ( name ) { var config = this . _wreqrHandlers [ name ] ; if ( ! config ) { return ; } return function ( ) { return config . callback . apply ( config . context , arguments ) ; } ; }

Get the currently registered handler for the specified name. Throws an exception if no handler is found.

Get the currently registered handler for the specified name . Throws an exception if no handler is found .


function(name) {
          name = arguments[0];
          var args = _.rest(arguments);
          if (this.hasHandler(name)) {
            this.getHandler(name).apply(this, args);
          } else {
            this.storage.addCommand(name, args);
          }
        }

function ( name ) { name = arguments [ 0 ] ; var args = _ . rest ( arguments ) ; if ( this . hasHandler ( name ) ) { this . getHandler ( name ) . apply ( this , args ) ; } else { this . storage . addCommand ( name , args ) ; } }

Execute a named command with the supplied args


function(type, hash, context) {
          if (!hash) {
            return;
          }
          context = context || this;
          var method = type === "vent" ? "on" : "setHandler";
          _.each(hash, function(fn, eventName) {
            this[type][method](eventName, _.bind(fn, context));
          }, this);
        }

function ( type , hash , context ) { if ( ! hash ) { return ; } context = context || this ; var method = type === "vent" ? "on" : "setHandler" ; _ . each ( hash , function ( fn , eventName ) { this [ type ] [ method ] ( eventName , _ . bind ( fn , context ) ) ; } , this ) ; }

Attach the handlers to a given message system `type`

Attach the handlers to a given message system type


function iterateEvents(target, entity, bindings, functionCallback, stringCallback) {
      if (!entity || !bindings) { return; }

      // type-check bindings
      if (!_.isObject(bindings)) {
        throw new Marionette.Error({
          message: 'Bindings must be an object or function.',
          url: 'marionette.functions.html#marionettebindentityevents'
        });
      }

      // allow the bindings to be a function
      bindings = Marionette._getValue(bindings, target);

      // iterate the bindings and bind them
      _.each(bindings, function(methods, evt) {

        // allow for a function as the handler,
        // or a list of event names as a string
        if (_.isFunction(methods)) {
          functionCallback(target, entity, evt, methods);
        } else {
          stringCallback(target, entity, evt, methods);
        }

      });
    }


function(callback, contextOverride) {
      var promise = _.result(this._deferred, 'promise');

      this._callbacks.push({cb: callback, ctx: contextOverride});

      promise.then(function(args) {
        if (contextOverride) { args.context = contextOverride; }
        callback.call(args.context, args.options);
      });
    }

function ( callback , contextOverride ) { var promise = _ . result ( this . _deferred , 'promise' ) ; this . _callbacks . push ( { cb : callback , ctx : contextOverride } ) ; promise . then ( function ( args ) { if ( contextOverride ) { args . context = contextOverride ; } callback . call ( args . context , args . options ) ; } ) ; }

Add a callback to be executed. Callbacks added here are guaranteed to execute, even if they are added after the `run` method is called.

Add a callback to be executed . Callbacks added here are guaranteed to execute even if they are added after the run method is called .


function(view, options) {
      if (!this._ensureElement()) {
        return;
      }

      this._ensureViewIsIntact(view);
      Marionette.MonitorDOMRefresh(view);

      var showOptions     = options || {};
      var isDifferentView = view !== this.currentView;
      var preventDestroy  = !!showOptions.preventDestroy;
      var forceShow       = !!showOptions.forceShow;

      // We are only changing the view if there is a current view to change to begin with
      var isChangingView = !!this.currentView;

      // Only destroy the current view if we don't want to `preventDestroy` and if
      // the view given in the first argument is different than `currentView`
      var _shouldDestroyView = isDifferentView && !preventDestroy;

      // Only show the view given in the first argument if it is different than
      // the current view or if we want to re-show the view. Note that if
      // `_shouldDestroyView` is true, then `_shouldShowView` is also necessarily true.
      var _shouldShowView = isDifferentView || forceShow;

      if (isChangingView) {
        this.triggerMethod('before:swapOut', this.currentView, this, options);
      }

      if (this.currentView && isDifferentView) {
        delete this.currentView._parent;
      }

      if (_shouldDestroyView) {
        this.empty();

      // A `destroy` event is attached to the clean up manually removed views.
      // We need to detach this event when a new view is going to be shown as it
      // is no longer relevant.
      } else if (isChangingView && _shouldShowView) {
        this.currentView.off('destroy', this.empty, this);
      }

      if (_shouldShowView) {

        // We need to listen for if a view is destroyed
        // in a way other than through the region.
        // If this happens we need to remove the reference
        // to the currentView since once a view has been destroyed
        // we can not reuse it.
        view.once('destroy', this.empty, this);

        // make this region the view's parent,
        // It's important that this parent binding happens before rendering
        // so that any events the child may trigger during render can also be
        // triggered on the child's ancestor views
        view._parent = this;
        this._renderView(view);

        if (isChangingView) {
          this.triggerMethod('before:swap', view, this, options);
        }

        this.triggerMethod('before:show', view, this, options);
        Marionette.triggerMethodOn(view, 'before:show', view, this, options);

        if (isChangingView) {
          this.triggerMethod('swapOut', this.currentView, this, options);
        }

        // An array of views that we're about to display
        var attachedRegion = Marionette.isNodeAttached(this.el);

        // The views that we're about to attach to the document
        // It's important that we prevent _getNestedViews from being executed unnecessarily
        // as it's a potentially-slow method
        var displayedViews = [];

        var attachOptions = _.extend({
          triggerBeforeAttach: this.triggerBeforeAttach,
          triggerAttach: this.triggerAttach
        }, showOptions);

        if (attachedRegion && attachOptions.triggerBeforeAttach) {
          displayedViews = this._displayedViews(view);
          this._triggerAttach(displayedViews, 'before:');
        }

        this.attachHtml(view);
        this.currentView = view;

        if (attachedRegion && attachOptions.triggerAttach) {
          displayedViews = this._displayedViews(view);
          this._triggerAttach(displayedViews);
        }

        if (isChangingView) {
          this.triggerMethod('swap', view, this, options);
        }

        this.triggerMethod('show', view, this, options);
        Marionette.triggerMethodOn(view, 'show', view, this, options);

        return this;
      }

      return this;
    }

function ( view , options ) { if ( ! this . _ensureElement ( ) ) { return ; } this . _ensureViewIsIntact ( view ) ; Marionette . MonitorDOMRefresh ( view ) ; var showOptions = options || { } ; var isDifferentView = view !== this . currentView ; var preventDestroy = ! ! showOptions . preventDestroy ; var forceShow = ! ! showOptions . forceShow ; var isChangingView = ! ! this . currentView ; var _shouldDestroyView = isDifferentView && ! preventDestroy ; var _shouldShowView = isDifferentView || forceShow ; if ( isChangingView ) { this . triggerMethod ( 'before:swapOut' , this . currentView , this , options ) ; } if ( this . currentView && isDifferentView ) { delete this . currentView . _parent ; } if ( _shouldDestroyView ) { this . empty ( ) ; } else if ( isChangingView && _shouldShowView ) { this . currentView . off ( 'destroy' , this . empty , this ) ; } if ( _shouldShowView ) { view . once ( 'destroy' , this . empty , this ) ; view . _parent = this ; this . _renderView ( view ) ; if ( isChangingView ) { this . triggerMethod ( 'before:swap' , view , this , options ) ; } this . triggerMethod ( 'before:show' , view , this , options ) ; Marionette . triggerMethodOn ( view , 'before:show' , view , this , options ) ; if ( isChangingView ) { this . triggerMethod ( 'swapOut' , this . currentView , this , options ) ; } var attachedRegion = Marionette . isNodeAttached ( this . el ) ; var displayedViews = [ ] ; var attachOptions = _ . extend ( { triggerBeforeAttach : this . triggerBeforeAttach , triggerAttach : this . triggerAttach } , showOptions ) ; if ( attachedRegion && attachOptions . triggerBeforeAttach ) { displayedViews = this . _displayedViews ( view ) ; this . _triggerAttach ( displayedViews , 'before:' ) ; } this . attachHtml ( view ) ; this . currentView = view ; if ( attachedRegion && attachOptions . triggerAttach ) { displayedViews = this . _displayedViews ( view ) ; this . _triggerAttach ( displayedViews ) ; } if ( isChangingView ) { this . triggerMethod ( 'swap' , view , this , options ) ; } this . triggerMethod ( 'show' , view , this , options ) ; Marionette . triggerMethodOn ( view , 'show' , view , this , options ) ; return this ; } return this ; }

Displays a backbone view instance inside of the region. Handles calling the `render` method for you. Reads content directly from the `el` attribute. Also calls an optional `onShow` and `onDestroy` method on your view, just after showing or just before destroying the view, respectively. The `preventDestroy` option can be used to prevent a view from the old view being destroyed on show. The `forceShow` option can be used to force a view to be re-rendered if it's already shown in the region.

Displays a backbone view instance inside of the region . Handles calling the render method for you . Reads content directly from the el attribute . Also calls an optional onShow and onDestroy method on your view just after showing or just before destroying the view respectively . The preventDestroy option can be used to prevent a view from the old view being destroyed on show . The forceShow option can be used to force a view to be re - rendered if it s already shown in the region .


function(options) {
      var view = this.currentView;

      var emptyOptions = options || {};
      var preventDestroy  = !!emptyOptions.preventDestroy;
      // If there is no view in the region
      // we should not remove anything
      if (!view) { return this; }

      view.off('destroy', this.empty, this);
      this.triggerMethod('before:empty', view);
      if (!preventDestroy) {
        this._destroyView();
      }
      this.triggerMethod('empty', view);

      // Remove region pointer to the currentView
      delete this.currentView;

      if (preventDestroy) {
        this.$el.contents().detach();
      }

      return this;
    }

function ( options ) { var view = this . currentView ; var emptyOptions = options || { } ; var preventDestroy = ! ! emptyOptions . preventDestroy ; if ( ! view ) { return this ; } view . off ( 'destroy' , this . empty , this ) ; this . triggerMethod ( 'before:empty' , view ) ; if ( ! preventDestroy ) { this . _destroyView ( ) ; } this . triggerMethod ( 'empty' , view ) ; delete this . currentView ; if ( preventDestroy ) { this . $el . contents ( ) . detach ( ) ; } return this ; }

Destroy the current view, if there is one. If there is no current view, it does nothing and returns immediately.

Destroy the current view if there is one . If there is no current view it does nothing and returns immediately .


function(regionDefinitions, defaults) {
      regionDefinitions = Marionette._getValue(regionDefinitions, this, arguments);

      return _.reduce(regionDefinitions, function(regions, definition, name) {
        if (_.isString(definition)) {
          definition = {selector: definition};
        }
        if (definition.selector) {
          definition = _.defaults({}, definition, defaults);
        }

        regions[name] = this.addRegion(name, definition);
        return regions;
      }, {}, this);
    }

function ( regionDefinitions , defaults ) { regionDefinitions = Marionette . _getValue ( regionDefinitions , this , arguments ) ; return _ . reduce ( regionDefinitions , function ( regions , definition , name ) { if ( _ . isString ( definition ) ) { definition = { selector : definition } ; } if ( definition . selector ) { definition = _ . defaults ( { } , definition , defaults ) ; } regions [ name ] = this . addRegion ( name , definition ) ; return regions ; } , { } , this ) ; }

Add multiple regions using an object literal or a function that returns an object literal, where each key becomes the region name, and each value is the region definition.

Add multiple regions using an object literal or a function that returns an object literal where each key becomes the region name and each value is the region definition .


function(name, definition) {
      var region;

      if (definition instanceof Marionette.Region) {
        region = definition;
      } else {
        region = Marionette.Region.buildRegion(definition, Marionette.Region);
      }

      this.triggerMethod('before:add:region', name, region);

      region._parent = this;
      this._store(name, region);

      this.triggerMethod('add:region', name, region);
      return region;
    }

function ( name , definition ) { var region ; if ( definition instanceof Marionette . Region ) { region = definition ; } else { region = Marionette . Region . buildRegion ( definition , Marionette . Region ) ; } this . triggerMethod ( 'before:add:region' , name , region ) ; region . _parent = this ; this . _store ( name , region ) ; this . triggerMethod ( 'add:region' , name , region ) ; return region ; }

Add an individual region to the region manager, and return the region instance

Add an individual region to the region manager and return the region instance


function() {
      var regions = this.getRegions();
      _.each(this._regions, function(region, name) {
        this._remove(name, region);
      }, this);

      return regions;
    }

function ( ) { var regions = this . getRegions ( ) ; _ . each ( this . _regions , function ( region , name ) { this . _remove ( name , region ) ; } , this ) ; return regions ; }

Empty all regions in the region manager, and remove them

Empty all regions in the region manager and remove them


function(name, region) {
      this.triggerMethod('before:remove:region', name, region);
      region.empty();
      region.stopListening();

      delete region._parent;
      delete this._regions[name];
      this.length--;
      this.triggerMethod('remove:region', name, region);
    }

function ( name , region ) { this . triggerMethod ( 'before:remove:region' , name , region ) ; region . empty ( ) ; region . stopListening ( ) ; delete region . _parent ; delete this . _regions [ name ] ; this . length -- ; this . triggerMethod ( 'remove:region' , name , region ) ; }


function(templateId, options) {
      var cachedTemplate = this.templateCaches[templateId];

      if (!cachedTemplate) {
        cachedTemplate = new Marionette.TemplateCache(templateId);
        this.templateCaches[templateId] = cachedTemplate;
      }

      return cachedTemplate.load(options);
    }

function ( templateId , options ) { var cachedTemplate = this . templateCaches [ templateId ] ; if ( ! cachedTemplate ) { cachedTemplate = new Marionette . TemplateCache ( templateId ) ; this . templateCaches [ templateId ] = cachedTemplate ; } return cachedTemplate . load ( options ) ; }

Get the specified template by id. Either retrieves the cached version, or loads it from the DOM.

Get the specified template by id . Either retrieves the cached version or loads it from the DOM .


function(options) {
      // Guard clause to prevent loading this template more than once
      if (this.compiledTemplate) {
        return this.compiledTemplate;
      }

      // Load the template and compile it
      var template = this.loadTemplate(this.templateId, options);
      this.compiledTemplate = this.compileTemplate(template, options);

      return this.compiledTemplate;
    }

function ( options ) { if ( this . compiledTemplate ) { return this . compiledTemplate ; } var template = this . loadTemplate ( this . templateId , options ) ; this . compiledTemplate = this . compileTemplate ( template , options ) ; return this . compiledTemplate ; }


function(template, data) {
      if (!template) {
        throw new Marionette.Error({
          name: 'TemplateNotFoundError',
          message: 'Cannot render the template since its false, null or undefined.'
        });
      }

      var templateFunc = _.isFunction(template) ? template : Marionette.TemplateCache.get(template);

      return templateFunc(data);
    }

Render a template with data. The `template` parameter is passed to the `TemplateCache` object to retrieve the template function. Override this method to provide your own custom rendering and template handling for all of Marionette.

Render a template with data . The template parameter is passed to the TemplateCache object to retrieve the template function . Override this method to provide your own custom rendering and template handling for all of Marionette .


function(target) {
      target = target || {};
      var templateHelpers = this.getOption('templateHelpers');
      templateHelpers = Marionette._getValue(templateHelpers, this);
      return _.extend(target, templateHelpers);
    }

function ( target ) { target = target || { } ; var templateHelpers = this . getOption ( 'templateHelpers' ) ; templateHelpers = Marionette . _getValue ( templateHelpers , this ) ; return _ . extend ( target , templateHelpers ) ; }

Mix in template helper methods. Looks for a `templateHelpers` attribute, which can either be an object literal, or a function that returns an object literal. All methods and attributes from this object are copies to the object passed in.

Mix in template helper methods . Looks for a templateHelpers attribute which can either be an object literal or a function that returns an object literal . All methods and attributes from this object are copies to the object passed in .


function(events) {
      this._delegateDOMEvents(events);
      this.bindEntityEvents(this.model, this.getOption('modelEvents'));
      this.bindEntityEvents(this.collection, this.getOption('collectionEvents'));

      _.each(this._behaviors, function(behavior) {
        behavior.bindEntityEvents(this.model, behavior.getOption('modelEvents'));
        behavior.bindEntityEvents(this.collection, behavior.getOption('collectionEvents'));
      }, this);

      return this;
    }

function ( events ) { this . _delegateDOMEvents ( events ) ; this . bindEntityEvents ( this . model , this . getOption ( 'modelEvents' ) ) ; this . bindEntityEvents ( this . collection , this . getOption ( 'collectionEvents' ) ) ; _ . each ( this . _behaviors , function ( behavior ) { behavior . bindEntityEvents ( this . model , behavior . getOption ( 'modelEvents' ) ) ; behavior . bindEntityEvents ( this . collection , behavior . getOption ( 'collectionEvents' ) ) ; } , this ) ; return this ; }

Overriding Backbone.View's delegateEvents to handle the `triggers`, `modelEvents`, and `collectionEvents` configuration

Overriding Backbone . View s delegateEvents to handle the triggers modelEvents and collectionEvents configuration


function(eventsArg) {
      var events = Marionette._getValue(eventsArg || this.events, this);

      // normalize ui keys
      events = this.normalizeUIKeys(events);
      if (_.isUndefined(eventsArg)) {this.events = events;}

      var combinedEvents = {};

      // look up if this view has behavior events
      var behaviorEvents = _.result(this, 'behaviorEvents') || {};
      var triggers = this.configureTriggers();
      var behaviorTriggers = _.result(this, 'behaviorTriggers') || {};

      // behavior events will be overriden by view events and or triggers
      _.extend(combinedEvents, behaviorEvents, events, triggers, behaviorTriggers);

      Backbone.View.prototype.delegateEvents.call(this, combinedEvents);
    }

function ( eventsArg ) { var events = Marionette . _getValue ( eventsArg || this . events , this ) ; events = this . normalizeUIKeys ( events ) ; if ( _ . isUndefined ( eventsArg ) ) { this . events = events ; } var combinedEvents = { } ; var behaviorEvents = _ . result ( this , 'behaviorEvents' ) || { } ; var triggers = this . configureTriggers ( ) ; var behaviorTriggers = _ . result ( this , 'behaviorTriggers' ) || { } ; _ . extend ( combinedEvents , behaviorEvents , events , triggers , behaviorTriggers ) ; Backbone . View . prototype . delegateEvents . call ( this , combinedEvents ) ; }

internal method to delegate DOM events and triggers


function() {
      Backbone.View.prototype.undelegateEvents.apply(this, arguments);

      this.unbindEntityEvents(this.model, this.getOption('modelEvents'));
      this.unbindEntityEvents(this.collection, this.getOption('collectionEvents'));

      _.each(this._behaviors, function(behavior) {
        behavior.unbindEntityEvents(this.model, behavior.getOption('modelEvents'));
        behavior.unbindEntityEvents(this.collection, behavior.getOption('collectionEvents'));
      }, this);

      return this;
    }

function ( ) { Backbone . View . prototype . undelegateEvents . apply ( this , arguments ) ; this . unbindEntityEvents ( this . model , this . getOption ( 'modelEvents' ) ) ; this . unbindEntityEvents ( this . collection , this . getOption ( 'collectionEvents' ) ) ; _ . each ( this . _behaviors , function ( behavior ) { behavior . unbindEntityEvents ( this . model , behavior . getOption ( 'modelEvents' ) ) ; behavior . unbindEntityEvents ( this . collection , behavior . getOption ( 'collectionEvents' ) ) ; } , this ) ; return this ; }

Overriding Backbone.View's undelegateEvents to handle unbinding the `triggers`, `modelEvents`, and `collectionEvents` config

Overriding Backbone . View s undelegateEvents to handle unbinding the triggers modelEvents and collectionEvents config


function() {
      if (this.isDestroyed) { return this; }

      var args = _.toArray(arguments);

      this.triggerMethod.apply(this, ['before:destroy'].concat(args));

      // mark as destroyed before doing the actual destroy, to
      // prevent infinite loops within "destroy" event handlers
      // that are trying to destroy other views
      this.isDestroyed = true;
      this.triggerMethod.apply(this, ['destroy'].concat(args));

      // unbind UI elements
      this.unbindUIElements();

      this.isRendered = false;

      // remove the view from the DOM
      this.remove();

      // Call destroy on each behavior after
      // destroying the view.
      // This unbinds event listeners
      // that behaviors have registered for.
      _.invoke(this._behaviors, 'destroy', args);

      return this;
    }

function ( ) { if ( this . isDestroyed ) { return this ; } var args = _ . toArray ( arguments ) ; this . triggerMethod . apply ( this , [ 'before:destroy' ] . concat ( args ) ) ; this . isDestroyed = true ; this . triggerMethod . apply ( this , [ 'destroy' ] . concat ( args ) ) ; this . unbindUIElements ( ) ; this . isRendered = false ; this . remove ( ) ; _ . invoke ( this . _behaviors , 'destroy' , args ) ; return this ; }

Default `destroy` implementation, for removing a view from the DOM and unbinding it. Regions will call this method for you. You can specify an `onDestroy` method in your view to add custom code that is called after the view is destroyed.

Default destroy implementation for removing a view from the DOM and unbinding it . Regions will call this method for you . You can specify an onDestroy method in your view to add custom code that is called after the view is destroyed .


function() {
      if (!this.ui) { return; }

      // store the ui hash in _uiBindings so they can be reset later
      // and so re-rendering the view will be able to find the bindings
      if (!this._uiBindings) {
        this._uiBindings = this.ui;
      }

      // get the bindings result, as a function or otherwise
      var bindings = _.result(this, '_uiBindings');

      // empty the ui so we don't have anything to start with
      this.ui = {};

      // bind each of the selectors
      _.each(bindings, function(selector, key) {
        this.ui[key] = this.$(selector);
      }, this);
    }

function ( ) { if ( ! this . ui ) { return ; } if ( ! this . _uiBindings ) { this . _uiBindings = this . ui ; } var bindings = _ . result ( this , '_uiBindings' ) ; this . ui = { } ; _ . each ( bindings , function ( selector , key ) { this . ui [ key ] = this . $ ( selector ) ; } , this ) ; }

This method binds the elements specified in the "ui" hash inside the view's code with the associated jQuery selectors.

This method binds the elements specified in the ui hash inside the view s code with the associated jQuery selectors .


function() {
      var ret = Marionette._triggerMethod(this, arguments);

      this._triggerEventOnBehaviors(arguments);
      this._triggerEventOnParentLayout(arguments[0], _.rest(arguments));

      return ret;
    }

function ( ) { var ret = Marionette . _triggerMethod ( this , arguments ) ; this . _triggerEventOnBehaviors ( arguments ) ; this . _triggerEventOnParentLayout ( arguments [ 0 ] , _ . rest ( arguments ) ) ; return ret ; }

import the `triggerMethod` to trigger events with corresponding methods if the method exists

import the triggerMethod to trigger events with corresponding methods if the method exists


function() {
      var children = this._getImmediateChildren();

      if (!children.length) { return children; }

      return _.reduce(children, function(memo, view) {
        if (!view._getNestedViews) { return memo; }
        return memo.concat(view._getNestedViews());
      }, children);
    }

function ( ) { var children = this . _getImmediateChildren ( ) ; if ( ! children . length ) { return children ; } return _ . reduce ( children , function ( memo , view ) { if ( ! view . _getNestedViews ) { return memo ; } return memo . concat ( view . _getNestedViews ( ) ) ; } , children ) ; }

Returns an array of every nested view within this view


function() {
      if (!this.model && !this.collection) {
        return {};
      }

      var args = [this.model || this.collection];
      if (arguments.length) {
        args.push.apply(args, arguments);
      }

      if (this.model) {
        return this.serializeModel.apply(this, args);
      } else {
        return {
          items: this.serializeCollection.apply(this, args)
        };
      }
    }

function ( ) { if ( ! this . model && ! this . collection ) { return { } ; } var args = [ this . model || this . collection ] ; if ( arguments . length ) { args . push . apply ( args , arguments ) ; } if ( this . model ) { return this . serializeModel . apply ( this , args ) ; } else { return { items : this . serializeCollection . apply ( this , args ) } ; } }

Serialize the model or collection for the view. If a model is found, the view's `serializeModel` is called. If a collection is found, each model in the collection is serialized by calling the view's `serializeCollection` and put into an `items` array in the resulting data. If both are found, defaults to the model. You can override the `serializeData` method in your own view definition, to provide custom serialization for your view's data.

Serialize the model or collection for the view . If a model is found the view s serializeModel is called . If a collection is found each model in the collection is serialized by calling the view s serializeCollection and put into an items array in the resulting data . If both are found defaults to the model . You can override the serializeData method in your own view definition to provide custom serialization for your view s data .


function() {
      var template = this.getTemplate();

      // Allow template-less item views
      if (template === false) {
        return;
      }

      if (!template) {
        throw new Marionette.Error({
          name: 'UndefinedTemplateError',
          message: 'Cannot render the template since it is null or undefined.'
        });
      }

      // Add in entity data and template helpers
      var data = this.mixinTemplateHelpers(this.serializeData());

      // Render and add to el
      var html = Marionette.Renderer.render(template, data, this);
      this.attachElContent(html);

      return this;
    }

Internal method to render the template with the serialized data and template helpers via the `Marionette.Renderer` object. Throws an `UndefinedTemplateError` error if the template is any falsely value but literal `false`.

Internal method to render the template with the serialized data and template helpers via the Marionette . Renderer object . Throws an UndefinedTemplateError error if the template is any falsely value but literal false .


function() {
      if (this.collection) {
        this.listenTo(this.collection, 'add', this._onCollectionAdd);
        this.listenTo(this.collection, 'remove', this._onCollectionRemove);
        this.listenTo(this.collection, 'reset', this.render);

        if (this.getOption('sort')) {
          this.listenTo(this.collection, 'sort', this._sortViews);
        }
      }
    }

function ( ) { if ( this . collection ) { this . listenTo ( this . collection , 'add' , this . _onCollectionAdd ) ; this . listenTo ( this . collection , 'remove' , this . _onCollectionRemove ) ; this . listenTo ( this . collection , 'reset' , this . render ) ; if ( this . getOption ( 'sort' ) ) { this . listenTo ( this . collection , 'sort' , this . _sortViews ) ; } } }

Configured the initial events that the collection view binds to.

Configured the initial events that the collection view binds to .


function(child, collection, opts) {
      // `index` is present when adding with `at` since BB 1.2; indexOf fallback for < 1.2
      var index = opts.at !== undefined && (opts.index || collection.indexOf(child));

      // When filtered or when there is no initial index, calculate index.
      if (this.getOption('filter') || index === false) {
        index = _.indexOf(this._filteredSortedModels(index), child);
      }

      if (this._shouldAddChild(child, index)) {
        this.destroyEmptyView();
        var ChildView = this.getChildView(child);
        this.addChild(child, ChildView, index);
      }
    }

function ( child , collection , opts ) { var index = opts . at !== undefined && ( opts . index || collection . indexOf ( child ) ) ; if ( this . getOption ( 'filter' ) || index === false ) { index = _ . indexOf ( this . _filteredSortedModels ( index ) , child ) ; } if ( this . _shouldAddChild ( child , index ) ) { this . destroyEmptyView ( ) ; var ChildView = this . getChildView ( child ) ; this . addChild ( child , ChildView , index ) ; } }


function() {
      var models = this._filteredSortedModels();

      // check for any changes in sort order of views
      var orderChanged = _.find(models, function(item, index) {
        var view = this.children.findByModel(item);
        return !view || view._index !== index;
      }, this);

      if (orderChanged) {
        this.resortView();
      }
    }

function ( ) { var models = this . _filteredSortedModels ( ) ; var orderChanged = _ . find ( models , function ( item , index ) { var view = this . children . findByModel ( item ) ; return ! view || view . _index !== index ; } , this ) ; if ( orderChanged ) { this . resortView ( ) ; } }

Internal method. This checks for any changes in the order of the collection. If the index of any view doesn't match, it will render.

Internal method . This checks for any changes in the order of the collection . If the index of any view doesn t match it will render .


function() {
      this.destroyEmptyView();
      this.destroyChildren({checkEmpty: false});

      if (this.isEmpty(this.collection)) {
        this.showEmptyView();
      } else {
        this.triggerMethod('before:render:collection', this);
        this.startBuffering();
        this.showCollection();
        this.endBuffering();
        this.triggerMethod('render:collection', this);

        // If we have shown children and none have passed the filter, show the empty view
        if (this.children.isEmpty() && this.getOption('filter')) {
          this.showEmptyView();
        }
      }
    }

function ( ) { this . destroyEmptyView ( ) ; this . destroyChildren ( { checkEmpty : false } ) ; if ( this . isEmpty ( this . collection ) ) { this . showEmptyView ( ) ; } else { this . triggerMethod ( 'before:render:collection' , this ) ; this . startBuffering ( ) ; this . showCollection ( ) ; this . endBuffering ( ) ; this . triggerMethod ( 'render:collection' , this ) ; if ( this . children . isEmpty ( ) && this . getOption ( 'filter' ) ) { this . showEmptyView ( ) ; } } }

Internal method. Separated so that CompositeView can have more control over events being triggered, around the rendering process

Internal method . Separated so that CompositeView can have more control over events being triggered around the rendering process


function() {
      var ChildView;

      var models = this._filteredSortedModels();

      _.each(models, function(child, index) {
        ChildView = this.getChildView(child);
        this.addChild(child, ChildView, index);
      }, this);
    }

function ( ) { var ChildView ; var models = this . _filteredSortedModels ( ) ; _ . each ( models , function ( child , index ) { ChildView = this . getChildView ( child ) ; this . addChild ( child , ChildView , index ) ; } , this ) ; }

Internal method to loop through collection and show each child view.

Internal method to loop through collection and show each child view .


function(addedAt) {
      var viewComparator = this.getViewComparator();
      var models = this.collection.models;
      addedAt = Math.min(Math.max(addedAt, 0), models.length - 1);

      if (viewComparator) {
        var addedModel;
        // Preserve `at` location, even for a sorted view
        if (addedAt) {
          addedModel = models[addedAt];
          models = models.slice(0, addedAt).concat(models.slice(addedAt + 1));
        }
        models = this._sortModelsBy(models, viewComparator);
        if (addedModel) {
          models.splice(addedAt, 0, addedModel);
        }
      }

      // Filter after sorting in case the filter uses the index
      if (this.getOption('filter')) {
        models = _.filter(models, function(model, index) {
          return this._shouldAddChild(model, index);
        }, this);
      }

      return models;
    }

function ( addedAt ) { var viewComparator = this . getViewComparator ( ) ; var models = this . collection . models ; addedAt = Math . min ( Math . max ( addedAt , 0 ) , models . length - 1 ) ; if ( viewComparator ) { var addedModel ; if ( addedAt ) { addedModel = models [ addedAt ] ; models = models . slice ( 0 , addedAt ) . concat ( models . slice ( addedAt + 1 ) ) ; } models = this . _sortModelsBy ( models , viewComparator ) ; if ( addedModel ) { models . splice ( addedAt , 0 , addedModel ) ; } } if ( this . getOption ( 'filter' ) ) { models = _ . filter ( models , function ( model , index ) { return this . _shouldAddChild ( model , index ) ; } , this ) ; } return models ; }

Allow the collection to be sorted by a custom view comparator


function() {
      var EmptyView = this.getEmptyView();

      if (EmptyView && !this._showingEmptyView) {
        this.triggerMethod('before:render:empty');

        this._showingEmptyView = true;
        var model = new Backbone.Model();
        this.addEmptyView(model, EmptyView);

        this.triggerMethod('render:empty');
      }
    }

function ( ) { var EmptyView = this . getEmptyView ( ) ; if ( EmptyView && ! this . _showingEmptyView ) { this . triggerMethod ( 'before:render:empty' ) ; this . _showingEmptyView = true ; var model = new Backbone . Model ( ) ; this . addEmptyView ( model , EmptyView ) ; this . triggerMethod ( 'render:empty' ) ; } }

Internal method to show an empty view in place of a collection of child views, when the collection is empty

Internal method to show an empty view in place of a collection of child views when the collection is empty


function(child, ChildView, index) {
      var childViewOptions = this.getOption('childViewOptions');
      childViewOptions = Marionette._getValue(childViewOptions, this, [child, index]);

      var view = this.buildChildView(child, ChildView, childViewOptions);

      // increment indices of views after this one
      this._updateIndices(view, true, index);

      this.triggerMethod('before:add:child', view);
      this._addChildView(view, index);
      this.triggerMethod('add:child', view);

      view._parent = this;

      return view;
    }

function ( child , ChildView , index ) { var childViewOptions = this . getOption ( 'childViewOptions' ) ; childViewOptions = Marionette . _getValue ( childViewOptions , this , [ child , index ] ) ; var view = this . buildChildView ( child , ChildView , childViewOptions ) ; this . _updateIndices ( view , true , index ) ; this . triggerMethod ( 'before:add:child' , view ) ; this . _addChildView ( view , index ) ; this . triggerMethod ( 'add:child' , view ) ; view . _parent = this ; return view ; }

Render the child's view and add it to the HTML for the collection view at a given index. This will also update the indices of later views in the collection in order to keep the children in sync with the collection.

Render the child s view and add it to the HTML for the collection view at a given index . This will also update the indices of later views in the collection in order to keep the children in sync with the collection .


function(view, index) {
      // Only trigger attach if already shown, attached, and not buffering, otherwise endBuffer() or
      // Region#show() handles this.
      var canTriggerAttach = this._isShown && !this.isBuffering && Marionette.isNodeAttached(this.el);
      var nestedViews;

      // set up the child view event forwarding
      this.proxyChildEvents(view);

      view.once('render', function() {
        // trigger the 'before:show' event on `view` if the collection view has already been shown
        if (this._isShown && !this.isBuffering) {
          Marionette.triggerMethodOn(view, 'before:show', view);
        }

        // Trigger `before:attach` following `render` to avoid adding logic and event triggers
        // to public method `renderChildView()`.
        if (canTriggerAttach && this._triggerBeforeAttach) {
          nestedViews = this._getViewAndNested(view);
          this._triggerMethodMany(nestedViews, this, 'before:attach');
        }
      }, this);

      // Store the child view itself so we can properly remove and/or destroy it later
      this.children.add(view);
      this.renderChildView(view, index);

      // Trigger `attach`
      if (canTriggerAttach && this._triggerAttach) {
        nestedViews = this._getViewAndNested(view);
        this._triggerMethodMany(nestedViews, this, 'attach');
      }
      // Trigger `show`
      if (this._isShown && !this.isBuffering) {
        Marionette.triggerMethodOn(view, 'show', view);
      }
    }

function ( view , index ) { var canTriggerAttach = this . _isShown && ! this . isBuffering && Marionette . isNodeAttached ( this . el ) ; var nestedViews ; this . proxyChildEvents ( view ) ; view . once ( 'render' , function ( ) { if ( this . _isShown && ! this . isBuffering ) { Marionette . triggerMethodOn ( view , 'before:show' , view ) ; } if ( canTriggerAttach && this . _triggerBeforeAttach ) { nestedViews = this . _getViewAndNested ( view ) ; this . _triggerMethodMany ( nestedViews , this , 'before:attach' ) ; } } , this ) ; this . children . add ( view ) ; this . renderChildView ( view , index ) ; if ( canTriggerAttach && this . _triggerAttach ) { nestedViews = this . _getViewAndNested ( view ) ; this . _triggerMethodMany ( nestedViews , this , 'attach' ) ; } if ( this . _isShown && ! this . isBuffering ) { Marionette . triggerMethodOn ( view , 'show' , view ) ; } }

Internal Method. Add the view to children and render it at the given index.

Internal Method . Add the view to children and render it at the given index .


function(view, index) {
      if (!view.supportsRenderLifecycle) {
        Marionette.triggerMethodOn(view, 'before:render', view);
      }
      view.render();
      if (!view.supportsRenderLifecycle) {
        Marionette.triggerMethodOn(view, 'render', view);
      }
      this.attachHtml(this, view, index);
      return view;
    }

function ( view , index ) { if ( ! view . supportsRenderLifecycle ) { Marionette . triggerMethodOn ( view , 'before:render' , view ) ; } view . render ( ) ; if ( ! view . supportsRenderLifecycle ) { Marionette . triggerMethodOn ( view , 'render' , view ) ; } this . attachHtml ( this , view , index ) ; return view ; }


function(child, ChildViewClass, childViewOptions) {
      var options = _.extend({model: child}, childViewOptions);
      var childView = new ChildViewClass(options);
      Marionette.MonitorDOMRefresh(childView);
      return childView;
    }

function ( child , ChildViewClass , childViewOptions ) { var options = _ . extend ( { model : child } , childViewOptions ) ; var childView = new ChildViewClass ( options ) ; Marionette . MonitorDOMRefresh ( childView ) ; return childView ; }

Build a `childView` for a model in the collection.

Build a childView for a model in the collection .


function(view) {
      if (!view) { return view; }

      this.triggerMethod('before:remove:child', view);

      if (!view.supportsDestroyLifecycle) {
        Marionette.triggerMethodOn(view, 'before:destroy', view);
      }
      // call 'destroy' or 'remove', depending on which is found
      if (view.destroy) {
        view.destroy();
      } else {
        view.remove();
      }
      if (!view.supportsDestroyLifecycle) {
        Marionette.triggerMethodOn(view, 'destroy', view);
      }

      delete view._parent;
      this.stopListening(view);
      this.children.remove(view);
      this.triggerMethod('remove:child', view);

      // decrement the index of views after this one
      this._updateIndices(view, false);

      return view;
    }

function ( view ) { if ( ! view ) { return view ; } this . triggerMethod ( 'before:remove:child' , view ) ; if ( ! view . supportsDestroyLifecycle ) { Marionette . triggerMethodOn ( view , 'before:destroy' , view ) ; } if ( view . destroy ) { view . destroy ( ) ; } else { view . remove ( ) ; } if ( ! view . supportsDestroyLifecycle ) { Marionette . triggerMethodOn ( view , 'destroy' , view ) ; } delete view . _parent ; this . stopListening ( view ) ; this . children . remove ( view ) ; this . triggerMethod ( 'remove:child' , view ) ; this . _updateIndices ( view , false ) ; return view ; }

Remove the child view and destroy it. This function also updates the indices of later views in the collection in order to keep the children in sync with the collection.

Remove the child view and destroy it . This function also updates the indices of later views in the collection in order to keep the children in sync with the collection .


function() {
      var elBuffer = document.createDocumentFragment();
      _.each(this._bufferedChildren, function(b) {
        elBuffer.appendChild(b.el);
      });
      return elBuffer;
    }

function ( ) { var elBuffer = document . createDocumentFragment ( ) ; _ . each ( this . _bufferedChildren , function ( b ) { elBuffer . appendChild ( b . el ) ; } ) ; return elBuffer ; }

Create a fragment buffer from the currently buffered children


function(collectionView, childView, index) {
      if (collectionView.isBuffering) {
        // buffering happens on reset events and initial renders
        // in order to reduce the number of inserts into the
        // document, which are expensive.
        collectionView._bufferedChildren.splice(index, 0, childView);
      } else {
        // If we've already rendered the main collection, append
        // the new child into the correct order if we need to. Otherwise
        // append to the end.
        if (!collectionView._insertBefore(childView, index)) {
          collectionView._insertAfter(childView);
        }
      }
    }

function ( collectionView , childView , index ) { if ( collectionView . isBuffering ) { collectionView . _bufferedChildren . splice ( index , 0 , childView ) ; } else { if ( ! collectionView . _insertBefore ( childView , index ) ) { collectionView . _insertAfter ( childView ) ; } } }

Append the HTML to the collection's `el`. Override this method to do something other than `.append`.

Append the HTML to the collection s el . Override this method to do something other than . append .


function(childView, index) {
      var currentView;
      var findPosition = this.getOption('sort') && (index < this.children.length - 1);
      if (findPosition) {
        // Find the view after this one
        currentView = this.children.find(function(view) {
          return view._index === index + 1;
        });
      }

      if (currentView) {
        currentView.$el.before(childView.el);
        return true;
      }

      return false;
    }

function ( childView , index ) { var currentView ; var findPosition = this . getOption ( 'sort' ) && ( index < this . children . length - 1 ) ; if ( findPosition ) { currentView = this . children . find ( function ( view ) { return view . _index === index + 1 ; } ) ; } if ( currentView ) { currentView . $el . before ( childView . el ) ; return true ; } return false ; }

Internal method. Check whether we need to insert the view into the correct position.

Internal method . Check whether we need to insert the view into the correct position .


function() {
      if (this.isDestroyed) { return this; }

      this.triggerMethod('before:destroy:collection');
      this.destroyChildren({checkEmpty: false});
      this.triggerMethod('destroy:collection');

      return Marionette.View.prototype.destroy.apply(this, arguments);
    }

function ( ) { if ( this . isDestroyed ) { return this ; } this . triggerMethod ( 'before:destroy:collection' ) ; this . destroyChildren ( { checkEmpty : false } ) ; this . triggerMethod ( 'destroy:collection' ) ; return Marionette . View . prototype . destroy . apply ( this , arguments ) ; }

Handle cleanup and other destroying needs for the collection of views


function(options) {
      var destroyOptions = options || {};
      var shouldCheckEmpty = true;
      var childViews = this.children.map(_.identity);

      if (!_.isUndefined(destroyOptions.checkEmpty)) {
        shouldCheckEmpty = destroyOptions.checkEmpty;
      }

      this.children.each(this.removeChildView, this);

      if (shouldCheckEmpty) {
        this.checkEmpty();
      }
      return childViews;
    }

function ( options ) { var destroyOptions = options || { } ; var shouldCheckEmpty = true ; var childViews = this . children . map ( _ . identity ) ; if ( ! _ . isUndefined ( destroyOptions . checkEmpty ) ) { shouldCheckEmpty = destroyOptions . checkEmpty ; } this . children . each ( this . removeChildView , this ) ; if ( shouldCheckEmpty ) { this . checkEmpty ( ) ; } return childViews ; }

Destroy the child views that this collection view is holding on to, if any

Destroy the child views that this collection view is holding on to if any


function() {

      // Bind only after composite view is rendered to avoid adding child views
      // to nonexistent childViewContainer

      if (this.collection) {
        this.listenTo(this.collection, 'add', this._onCollectionAdd);
        this.listenTo(this.collection, 'remove', this._onCollectionRemove);
        this.listenTo(this.collection, 'reset', this._renderChildren);

        if (this.getOption('sort')) {
          this.listenTo(this.collection, 'sort', this._sortViews);
        }
      }
    }

function ( ) { if ( this . collection ) { this . listenTo ( this . collection , 'add' , this . _onCollectionAdd ) ; this . listenTo ( this . collection , 'remove' , this . _onCollectionRemove ) ; this . listenTo ( this . collection , 'reset' , this . _renderChildren ) ; if ( this . getOption ( 'sort' ) ) { this . listenTo ( this . collection , 'sort' , this . _sortViews ) ; } } }

Configured the initial events that the composite view binds to. Override this method to prevent the initial events, or to add your own initial events.

Configured the initial events that the composite view binds to . Override this method to prevent the initial events or to add your own initial events .


function() {
      var data = {};

      if (this.model) {
        data = _.partial(this.serializeModel, this.model).apply(this, arguments);
      }

      return data;
    }

function ( ) { var data = { } ; if ( this . model ) { data = _ . partial ( this . serializeModel , this . model ) . apply ( this , arguments ) ; } return data ; }

Serialize the model for the view. You can override the `serializeData` method in your own view definition, to provide custom serialization for your view's data.

Serialize the model for the view . You can override the serializeData method in your own view definition to provide custom serialization for your view s data .


function() {
      this._ensureViewIsIntact();
      this._isRendering = true;
      this.resetChildViewContainer();

      this.triggerMethod('before:render', this);

      this._renderTemplate();
      this._renderChildren();

      this._isRendering = false;
      this.isRendered = true;
      this.triggerMethod('render', this);
      return this;
    }

function ( ) { this . _ensureViewIsIntact ( ) ; this . _isRendering = true ; this . resetChildViewContainer ( ) ; this . triggerMethod ( 'before:render' , this ) ; this . _renderTemplate ( ) ; this . _renderChildren ( ) ; this . _isRendering = false ; this . isRendered = true ; this . triggerMethod ( 'render' , this ) ; return this ; }


function() {
      var data = {};
      data = this.serializeData();
      data = this.mixinTemplateHelpers(data);

      this.triggerMethod('before:render:template');

      var template = this.getTemplate();
      var html = Marionette.Renderer.render(template, data, this);
      this.attachElContent(html);

      // the ui bindings is done here and not at the end of render since they
      // will not be available until after the model is rendered, but should be
      // available before the collection is rendered.
      this.bindUIElements();
      this.triggerMethod('render:template');
    }

function ( ) { var data = { } ; data = this . serializeData ( ) ; data = this . mixinTemplateHelpers ( data ) ; this . triggerMethod ( 'before:render:template' ) ; var template = this . getTemplate ( ) ; var html = Marionette . Renderer . render ( template , data , this ) ; this . attachElContent ( html ) ; this . bindUIElements ( ) ; this . triggerMethod ( 'render:template' ) ; }

Render the root template that the children views are appended to


function(options) {
      options = options || {};

      this._firstRender = true;
      this._initializeRegions(options);

      Marionette.ItemView.call(this, options);
    }

function ( options ) { options = options || { } ; this . _firstRender = true ; this . _initializeRegions ( options ) ; Marionette . ItemView . call ( this , options ) ; }

Ensure the regions are available when the `initialize` method is called.

Ensure the regions are available when the initialize method is called .